feat: add descriptions, categories, and usage examples to commands for improved help functionality

This commit is contained in:
2025-09-26 06:38:09 -05:00
parent eb3f874628
commit 119ac89274
9 changed files with 193 additions and 388 deletions

View File

@@ -24,6 +24,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ['chat', 'gemini'],
cooldown: 5,
description: 'Chatea con la IA (Gemini) directamente desde Discord.',
category: 'IA',
usage: 'ai <mensaje>',
run: async (message, args) => {
// Verificar que se proporcione un prompt
if (!args || args.length === 0) {

View File

@@ -2,7 +2,6 @@ import { CommandMessage } from "../../../core/types/commands";
// @ts-ignore
import {
ComponentType, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, Message, MessageFlags,
AnyComponentBuilder
} from "discord.js";
import { replaceVars, isValidUrlOrVariable, listVariables } from "../../../core/lib/vars";
@@ -238,6 +237,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ["embed-crear", "nuevo-embed", "blockcreatev2"],
cooldown: 20,
description: "Crea un nuevo bloque/embedded con editor interactivo (DisplayComponents).",
category: "Alianzas",
usage: "crear-embed <nombre>",
run: async (message, args, client) => {
if (!message.member?.permissions.has("Administrator")) {
await message.reply("❌ No tienes permisos de Administrador.");
@@ -383,7 +385,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(true);
const firstActionRow: ActionRowBuilder<AnyComponentBuilder> = new ActionRowBuilder().addComponents(descInput);
const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(descInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -406,7 +408,7 @@ export const command: CommandMessage = {
.setMaxLength(7)
.setRequired(false);
const firstActionRow: ActionRowBuilder<TextInputBuilder> = new ActionRowBuilder().addComponents(colorInput);
const firstActionRow: ActionRowBuilder<TextInputBuilder> = new ActionRowBuilder<TextInputBuilder>().addComponents(colorInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -426,7 +428,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(true);
const firstActionRow = new ActionRowBuilder().addComponents(contentInput);
const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(contentInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -446,7 +448,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(true);
const firstActionRow = new ActionRowBuilder().addComponents(imageUrlInput);
const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(imageUrlInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -498,7 +500,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(true);
const firstActionRow = new ActionRowBuilder().addComponents(coverInput);
const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(coverInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -527,7 +529,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(true);
const firstActionRow = new ActionRowBuilder().addComponents(coverInput);
const firstActionRow = new ActionRowBuilder<TextInputBuilder>().addComponents(coverInput);
modal.addComponents(firstActionRow);
//@ts-ignore
@@ -831,7 +833,7 @@ export const command: CommandMessage = {
.setMaxLength(4000)
.setRequired(true);
const firstRow = new ActionRowBuilder().addComponents(jsonInput);
const firstRow = new ActionRowBuilder<TextInputBuilder>().addComponents(jsonInput);
modal.addComponents(firstRow);
//@ts-ignore
@@ -874,8 +876,8 @@ export const command: CommandMessage = {
.setMaxLength(1)
.setRequired(false);
const firstRow = new ActionRowBuilder().addComponents(visibleInput);
const secondRow = new ActionRowBuilder().addComponents(spacingInput);
const firstRow = new ActionRowBuilder<TextInputBuilder>().addComponents(visibleInput);
const secondRow = new ActionRowBuilder<TextInputBuilder>().addComponents(spacingInput);
modal.addComponents(firstRow, secondRow);
//@ts-ignore
@@ -936,7 +938,7 @@ export const command: CommandMessage = {
.setMaxLength(2000)
.setRequired(false);
const firstRow = new ActionRowBuilder().addComponents(thumbnailInput);
const firstRow = new ActionRowBuilder<TextInputBuilder>().addComponents(thumbnailInput);
modal.addComponents(firstRow);
// Abrir modal directamente sin update previo
@@ -1035,9 +1037,9 @@ export const command: CommandMessage = {
.setMaxLength(64)
.setRequired(false);
const r1 = new ActionRowBuilder().addComponents(urlInput);
const r2 = new ActionRowBuilder().addComponents(labelInput);
const r3 = new ActionRowBuilder().addComponents(emojiInput);
const r1 = new ActionRowBuilder<TextInputBuilder>().addComponents(urlInput);
const r2 = new ActionRowBuilder<TextInputBuilder>().addComponents(labelInput);
const r3 = new ActionRowBuilder<TextInputBuilder>().addComponents(emojiInput);
modal.addComponents(r1, r2, r3);
// Abrir modal directamente en la misma interacción del botón
@@ -1081,9 +1083,9 @@ export const command: CommandMessage = {
.setMaxLength(64)
.setRequired(false);
const r1 = new ActionRowBuilder().addComponents(urlInput);
const r2 = new ActionRowBuilder().addComponents(labelInput);
const r3 = new ActionRowBuilder().addComponents(emojiInput);
const r1 = new ActionRowBuilder<TextInputBuilder>().addComponents(urlInput);
const r2 = new ActionRowBuilder<TextInputBuilder>().addComponents(labelInput);
const r3 = new ActionRowBuilder<TextInputBuilder>().addComponents(emojiInput);
modal.addComponents(r1, r2, r3);
// Abrir modal directamente sin update previo

View File

@@ -5,6 +5,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ["ddemo", "componentsdemo"],
cooldown: 10,
description: "Demostración de DisplayComponents con accesorios y acciones.",
category: "Alianzas",
usage: "displaydemo",
run: async (message, args, client) => {
if (!message.member?.permissions.has("Administrator")) {
await message.reply("❌ No tienes permisos de Administrador.");

View File

@@ -2,7 +2,6 @@ import { CommandMessage } from "../../../core/types/commands";
// @ts-ignore
import { ComponentType, ButtonStyle, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, MessageFlags } from "discord.js";
import { replaceVars, isValidUrlOrVariable, listVariables } from "../../../core/lib/vars";
import {Block} from "../../../core/types/block";
// Botones de edición (máx 5 por fila)
const btns = (disabled = false) => ([
@@ -122,6 +121,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ["embed-editar", "modificar-embed", "blockeditv2"],
cooldown: 20,
description: "Edita un bloque/embed existente con herramientas interactivas.",
category: "Alianzas",
usage: "editar-embed <nombre>",
run: async (message, args, client) => {
if (!message.member?.permissions.has("Administrator")) {
await message.reply("❌ No tienes permisos de Administrador.");
@@ -142,7 +144,7 @@ export const command: CommandMessage = {
return;
}
let blockState: Block = {
let blockState: any = {
//@ts-ignore
title: existingBlock.config?.title ?? `## Block: ${blockName}`,
//@ts-ignore

View File

@@ -1,11 +1,15 @@
// @ts-ignore
import { CommandMessage } from "../../../core/types/commands";
import { commands as registry } from "../../core/loader";
export const command: CommandMessage = {
name: 'ayuda',
type: "message",
aliases: ['help', 'comandos', 'cmds'],
cooldown: 5,
description: 'Muestra la lista de comandos y detalles por categoría.',
category: 'Utilidad',
usage: 'ayuda [comando] | [categoría] | vacío',
run: async (message: any, args: string[], client: any) => {
// Obtener información del servidor para mostrar el prefix actual
const server = await client.prisma.guild.findFirst({
@@ -13,432 +17,210 @@ export const command: CommandMessage = {
});
const prefix = server?.prefix || "!";
// Definir categorías de comandos con nombres modernos
const commandCategories = {
"Alianzas": [
{
name: "crear-embed",
aliases: ["embed-crear", "nuevo-embed"],
description: "Crear nuevos embeds con DisplayComponents modernos",
usage: `${prefix}crear-embed <nombre>`
},
{
name: "editar-embed",
aliases: ["embed-editar", "modificar-embed"],
description: "Editor avanzado de embeds con interfaz interactiva",
usage: `${prefix}editar-embed <nombre>`
},
{
name: "lista-embeds",
aliases: ["embeds", "ver-embeds"],
description: "Centro de gestión de embeds con paginación",
usage: `${prefix}lista-embeds`
},
{
name: "eliminar-embed",
aliases: ["embed-eliminar", "borrar-embed"],
description: "Panel interactivo para eliminar embeds",
usage: `${prefix}eliminar-embed [nombre]`
},
{
name: "canal-alianza",
aliases: ["configurar-canal", "setup-canal"],
description: "Configurar canales para sistema de alianzas",
usage: `${prefix}canal-alianza`
},
{
name: "eliminar-canal-alianza",
aliases: ["removechannel-alliance", "removealchannel", "delalchannel"],
description: "Eliminar canales de la configuración de alianzas",
usage: `${prefix}eliminar-canal-alianza`
},
{
name: "listar-canales-alianza",
aliases: ["listchannels-alliance", "listalchannel", "channelsally"],
description: "Ver lista detallada de canales configurados para alianzas",
usage: `${prefix}listar-canales-alianza`
},
{
name: "demo-componentes",
aliases: ["demo", "prueba-componentes"],
description: "Demostración de DisplayComponents con accesorios",
usage: `${prefix}demo-componentes`
}
],
"Red": [
{
name: "ping",
aliases: ["latencia", "pong"],
description: "Verificar latencia y estado del bot",
usage: `${prefix}ping`
}
],
"Configuracion": [
{
name: "configuracion",
aliases: ["config", "ajustes", "settings"],
description: "Panel de configuración del servidor",
usage: `${prefix}configuracion`
}
]
};
// Construir lista de comandos únicos (sin duplicar aliases)
const seen = new Set<string>();
const allMsgCommands = [] as Array<{
name: string;
aliases: string[];
description: string;
category: string;
usage: string;
cooldown?: number;
}>;
// Definir backRow una sola vez fuera de los casos
const backRow = {
type: 1,
components: [
{
type: 2,
style: 2,
label: "↩️ Volver al Menú",
custom_id: "back_to_main"
}
]
};
for (const [, cmd] of registry) {
if (!cmd || cmd.type !== 'message') continue;
const baseName: string | undefined = cmd.name ?? cmd.data?.name;
if (!baseName) continue;
if (seen.has(baseName)) continue; // evitar duplicados por alias
seen.add(baseName);
// Si se especifica un comando específico
if (args.length > 0) {
const searchCommand = args[0].toLowerCase();
let foundCommand = null;
let foundCategory = null;
const cdesc = (cmd.description ?? '').toString().trim();
const ccat = (cmd.category ?? 'Otros').toString();
const usage = (cmd.usage ? `${prefix}${cmd.usage}` : `${prefix}${baseName}`);
// Buscar el comando en todas las categorías
for (const [category, commands] of Object.entries(commandCategories)) {
const command = commands.find(cmd =>
cmd.name === searchCommand || cmd.aliases.includes(searchCommand)
);
if (command) {
foundCommand = command;
foundCategory = category;
break;
}
}
if (foundCommand) {
// Panel detallado del comando específico - SIMPLIFICADO
const commandDetailPanel = {
type: 17,
accent_color: 0x5865f2,
components: [
{
type: 10,
content: `### 📖 **Ayuda: \`${foundCommand.name}\`**\n\n**Categoría:** ${foundCategory}\n**Descripción:** ${foundCommand.description}\n**Uso:** ${foundCommand.usage}\n\n**Aliases disponibles:**\n${foundCommand.aliases.map(alias => `\`${prefix}${alias}\``).join(", ")}`
}
]
};
const detailActionsRow = {
type: 1,
components: [
{
type: 2,
style: 2,
label: "📋 Ver Todos",
custom_id: "show_all_commands"
},
{
type: 2,
style: 2,
label: "🔍 Buscar Otro",
custom_id: "search_command"
}
]
};
await message.reply({
flags: 32768,
components: [commandDetailPanel, detailActionsRow]
allMsgCommands.push({
name: baseName,
aliases: Array.isArray(cmd.aliases) ? cmd.aliases : [],
description: cdesc || 'Sin descripción',
category: ccat,
usage,
cooldown: typeof cmd.cooldown === 'number' ? cmd.cooldown : undefined
});
return;
} else {
// Comando no encontrado - SIMPLIFICADO
const notFoundPanel = {
}
// Si no hay comandos
if (allMsgCommands.length === 0) {
const emptyPanel = {
type: 17,
accent_color: 0xf04747,
components: [
{
type: 10,
content: `### ❌ **Comando no encontrado: \`${searchCommand}\`**\n\nNo se encontró ningún comando con el nombre o alias \`${searchCommand}\`.\n\n🔍 **Sugerencias:**\n• Verifica la ortografía\n• Usa \`${prefix}ayuda\` para ver todos los comandos\n• Usa \`${prefix}ayuda <categoría>\` para filtrar`
content: `### ❌ No hay comandos disponibles\n\nAún no se han cargado comandos de mensaje.`
}
]
};
const notFoundRow = {
type: 1,
components: [
{
type: 2,
style: 1,
label: "📋 Ver Todos",
custom_id: "show_all_commands"
}
]
};
await message.reply({
flags: 32768,
components: [notFoundPanel, notFoundRow]
});
await message.reply({ flags: 32768, components: [emptyPanel] });
return;
}
// Index para búsqueda rápida por nombre/alias
const findByNameOrAlias = (q: string) => {
const term = q.toLowerCase();
return allMsgCommands.find(c => c.name === term || c.aliases.map(a => a.toLowerCase()).includes(term));
};
// Agrupar por categoría
const byCategory = new Map<string, typeof allMsgCommands>();
for (const c of allMsgCommands) {
const cat = c.category || 'Otros';
if (!byCategory.has(cat)) byCategory.set(cat, [] as any);
// @ts-ignore
byCategory.get(cat)!.push(c);
}
// Panel principal de ayuda - OPTIMIZADO para no exceder límite de componentes
const helpPanel = {
// Ordenar categorías por nombre
const categories = Array.from(byCategory.keys()).sort((a, b) => a.localeCompare(b, 'es'));
// Si se solicita un comando concreto
if (args.length > 0) {
const query = args.join(' ').trim();
const found = findByNameOrAlias(query);
if (found) {
const panel = {
type: 17,
accent_color: 0x5865f2,
components: [
{
type: 10,
content: `### 📚 **Centro de Ayuda - ${message.guild!.name}**`
},
{
type: 14,
spacing: 1,
divider: true
},
{
type: 10,
content: `**Prefix actual:** \`${prefix}\`\n**Total de comandos:** ${Object.values(commandCategories).flat().length}\n**Categorías disponibles:** ${Object.keys(commandCategories).length}`
},
{
type: 14,
spacing: 2,
divider: false
content: `### 📖 Ayuda: \`${found.name}\`\n\n` +
`• Categoría: **${found.category}**\n` +
`• Descripción: ${found.description}\n` +
`• Uso: \`${found.usage}\`\n` +
(found.aliases.length ? `• Aliases: ${found.aliases.map(a => `\`${prefix}${a}\``).join(', ')}` : '')
}
]
};
// Agregar resumen de categorías de forma compacta
for (const [categoryName, commands] of Object.entries(commandCategories)) {
const commandsList = commands.map(cmd => `\`${cmd.name}\``).join(", ");
helpPanel.components.push({
const backRow = {
type: 1,
components: [
{ type: 2, style: 2, label: '↩️ Volver', custom_id: 'back_to_main' }
]
};
await message.reply({ flags: 32768, components: [panel, backRow] });
return;
}
// También permitir filtrar por categoría si coincide exacto (case-insensitive)
const matchCat = categories.find(c => c.toLowerCase() === query.toLowerCase());
if (matchCat) {
const cmds = byCategory.get(matchCat)!;
const catPanel = {
type: 17,
accent_color: 0x00a8ff,
components: [
{ type: 10, content: `### 📂 Categoría: **${matchCat}** (${cmds.length})` },
{ type: 14, spacing: 2, divider: true },
...cmds.map(cmd => ({
type: 10,
content: `🔹 **${categoryName}** (${commands.length})\n${commandsList}`
});
content: `**${cmd.name}** ${cmd.description}\n\`${cmd.usage}\``
}))
]
};
const backRow = {
type: 1,
components: [ { type: 2, style: 2, label: '↩️ Volver', custom_id: 'back_to_main' } ]
};
await message.reply({ flags: 32768, components: [catPanel, backRow] });
return;
}
}
// Botones de navegación
const navigationRow = {
// Panel principal dinámico
const helpPanel: any = {
type: 17,
accent_color: 0x5865f2,
components: [
{ type: 10, content: `### 📚 Centro de Ayuda — ${message.guild!.name}` },
{ type: 14, spacing: 1, divider: true },
{ type: 10, content: `**Prefix actual:** \`${prefix}\`\n**Total de comandos:** ${allMsgCommands.length}\n**Categorías disponibles:** ${categories.length}` },
{ type: 14, spacing: 2, divider: false },
...categories.map(cat => {
const list = byCategory.get(cat)!;
const names = list.map(c => `\`${c.name}\``).join(', ');
return { type: 10, content: `🔹 **${cat}** (${list.length})\n${names}` };
})
]
};
// Select de categorías + botón exportar
const categoryRow = {
type: 1,
components: [
{
type: 2,
style: 1,
label: "🤝 Alianzas",
custom_id: "category_alliances"
type: 3,
custom_id: 'help_category_select',
placeholder: '📂 Selecciona una categoría...',
options: categories.slice(0, 25).map(c => ({ label: c, value: `cat:${c}` }))
},
{
type: 2,
style: 2,
label: "🌐 Red",
custom_id: "category_network"
},
{
type: 2,
style: 2,
label: "⚙️ Config",
custom_id: "category_settings"
},
{
type: 2,
style: 3,
label: "📋 Exportar",
custom_id: "export_commands"
}
{ type: 2, style: 3, label: '📋 Exportar', custom_id: 'export_commands' }
]
};
const panelMessage = await message.reply({
flags: 32768,
components: [helpPanel, navigationRow]
});
const panelMessage = await message.reply({ flags: 32768, components: [helpPanel, categoryRow] });
const collector = panelMessage.createMessageComponentCollector({
time: 600000,
filter: (i: any) => i.user.id === message.author.id
});
collector.on("collect", async (interaction: any) => {
// Manejar información específica de comandos
if (interaction.customId.startsWith("cmd_info_")) {
const commandName = interaction.customId.replace("cmd_info_", "");
let foundCommand = null;
let foundCategory = null;
collector.on('collect', async (interaction: any) => {
// Selección de categoría
if (interaction.customId === 'help_category_select' && interaction.isStringSelectMenu()) {
const val = interaction.values?.[0] ?? '';
const cat = val.startsWith('cat:') ? val.slice(4) : val;
const list = byCategory.get(cat) ?? [];
for (const [category, commands] of Object.entries(commandCategories)) {
const command = commands.find(cmd => cmd.name === commandName);
if (command) {
foundCommand = command;
foundCategory = category;
break;
}
}
if (foundCommand) {
await interaction.reply({
content: `📖 **${foundCommand.name}**\n\n**Categoría:** ${foundCategory}\n**Descripción:** ${foundCommand.description}\n**Uso:** ${foundCommand.usage}\n**Aliases:** ${foundCommand.aliases.join(", ")}\n\n💡 **Tip:** Usa \`${foundCommand.usage}\` para ejecutar este comando.`,
flags: 64
});
}
const catPanel = {
type: 17,
accent_color: 0x00a8ff,
components: [
{ type: 10, content: `### 📂 Categoría: **${cat}** (${list.length})` },
{ type: 14, spacing: 2, divider: true },
...list.map(cmd => ({ type: 10, content: `**${cmd.name}** — ${cmd.description}\n\`${cmd.usage}\`` }))
]
};
const backRow = { type: 1, components: [ { type: 2, style: 2, label: '↩️ Volver', custom_id: 'back_to_main' } ] };
await interaction.update({ components: [catPanel, backRow] });
return;
}
// Manejar categorías específicas - VERSIÓN COMPACTA
switch (interaction.customId) {
case "category_alliances":
const alliancePanel = {
type: 17,
accent_color: 0x00ff88,
components: [
{
type: 10,
content: "### 🤝 **Comandos de Alianzas**\n\nSistema completo para gestionar alianzas entre servidores:"
},
{
type: 14,
spacing: 2,
divider: true
if (interaction.customId === 'back_to_main' || interaction.customId === 'show_all_commands') {
await interaction.update({ components: [helpPanel, categoryRow] });
return;
}
]
};
// Agregar comandos de forma compacta
commandCategories["Alianzas"].forEach(cmd => {
alliancePanel.components.push({
type: 10,
content: `**${cmd.name}**\n${cmd.description}\n\`${cmd.usage}\``
});
});
await interaction.update({
components: [alliancePanel, backRow]
});
break;
case "category_network":
const networkPanel = {
type: 17,
accent_color: 0x0099ff,
components: [
{
type: 10,
content: "### 🌐 **Comandos de Red**"
},
{
type: 14,
spacing: 2,
divider: true
}
]
};
commandCategories["Red"].forEach(cmd => {
networkPanel.components.push({
type: 10,
content: `**${cmd.name}**\n${cmd.description}\n\`${cmd.usage}\``
});
});
await interaction.update({
components: [networkPanel, backRow]
});
break;
case "category_settings":
const settingsPanel = {
type: 17,
accent_color: 0xff9500,
components: [
{
type: 10,
content: "### ⚙️ **Comandos de Configuración**"
},
{
type: 14,
spacing: 2,
divider: true
}
]
};
commandCategories["Configuracion"].forEach(cmd => {
settingsPanel.components.push({
type: 10,
content: `**${cmd.name}**\n${cmd.description}\n\`${cmd.usage}\``
});
});
await interaction.update({
components: [settingsPanel, backRow]
});
break;
case "back_to_main":
await interaction.update({
components: [helpPanel, navigationRow]
});
break;
case "export_commands":
let exportText = `📋 **Lista Completa de Comandos - ${message.guild!.name}**\n\n`;
exportText += `**Prefix:** ${prefix}\n\n`;
for (const [category, commands] of Object.entries(commandCategories)) {
exportText += `**${category}**\n`;
commands.forEach(cmd => {
exportText += `${cmd.name} - ${cmd.description}\n`;
exportText += ` Uso: ${cmd.usage}\n`;
if (cmd.aliases.length > 0) {
exportText += ` Aliases: ${cmd.aliases.join(", ")}\n`;
if (interaction.customId === 'export_commands') {
let exportText = `Comandos — ${message.guild!.name}\n\nPrefix: ${prefix}\n\n`;
for (const cat of categories) {
const list = byCategory.get(cat)!;
exportText += `${cat}\n`;
for (const cmd of list) {
exportText += `${cmd.name}${cmd.description}\n Uso: ${cmd.usage}\n`;
if (cmd.aliases.length) exportText += ` Aliases: ${cmd.aliases.join(', ')}\n`;
}
exportText += `\n`;
});
exportText += `\n`;
}
await interaction.reply({
content: `\`\`\`\n${exportText}\`\`\``,
flags: 64
});
break;
default:
if (interaction.customId.startsWith("use_")) {
const commandName = interaction.customId.replace("use_", "");
const foundCmd = Object.values(commandCategories).flat().find(cmd => cmd.name === commandName);
if (foundCmd) {
await interaction.reply({
content: `🚀 **Ejecutar: \`${foundCmd.name}\`**\n\nUsa: \`${foundCmd.usage}\`\n\n💡 **Tip:** Copia y pega el comando en el chat para usarlo.`,
flags: 64
});
}
}
break;
await interaction.reply({ content: `\`\`\`\n${exportText}\n\`\`\``, flags: 64 });
return;
}
});
collector.on("end", async (collected: any, reason: string) => {
if (reason === "time") {
const timeoutPanel = {
type: 17,
accent_color: 0x36393f,
components: [
{
type: 10,
content: `### ⏰ **Panel de Ayuda Expirado**\n\nEl panel de ayuda ha expirado por inactividad.\n\nUsa \`${prefix}ayuda\` para abrir un nuevo panel.`
}
]
};
collector.on('end', async (collected: any, reason: string) => {
if (reason === 'time') {
try {
await panelMessage.edit({
components: [timeoutPanel]
});
} catch (error) {
// Mensaje eliminado o error de edición
}
await panelMessage.edit({ components: [helpPanel] });
} catch {}
}
});
}

View File

@@ -62,6 +62,9 @@ export const command: CommandMessage = {
type: 'message',
aliases: ['cmdadmin', 'synccommands', 'comandos-admin'],
cooldown: 5,
description: 'Panel del dueño para registrar/limpiar comandos slash y revisar memoria.',
category: 'Administración',
usage: 'admin-comandos',
run: async (message, _args, _client) => {
if (message.author.id !== OWNER_ID) {
await message.reply({ content: '❌ No tienes permisos para usar este panel.' });

View File

@@ -5,6 +5,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ['latency', 'pong'],
cooldown: 5,
description: 'Verifica la latencia y que el bot esté respondiendo.',
category: 'Red',
usage: 'ping',
run: async (message, args) => {
await message.reply('pong!')
}

View File

@@ -5,6 +5,9 @@ export const command: CommandMessage = {
type: "message",
aliases: ['config', 'ajustes', 'settings'],
cooldown: 5,
description: 'Abre el panel de configuración del servidor (prefix y más).',
category: 'Configuración',
usage: 'configuracion',
run: async (message, args, client) => {
if (!message.member?.permissions.has("Administrator")) {
await message.reply("❌ No tienes permisos de Administrador.");

View File

@@ -6,6 +6,10 @@ export interface CommandMessage {
type: 'message';
aliases?: string[];
cooldown?: number;
// New optional metadata for auto-help
description?: string;
category?: string;
usage?: string;
run: (message: Message, args: string[], client: Amayo) => Promise<void>;
}