diff --git a/_opt/botUtils.js b/_opt/botUtils.js index f0915bf..3a6f3ec 100644 --- a/_opt/botUtils.js +++ b/_opt/botUtils.js @@ -86,25 +86,89 @@ export const commands = [ const commandCount = client.commands.size; // List of loaded optional modules const loadedModules = client.modules ? Array.from(client.modules.keys()) : []; - const lines = [ - `Client ID : ${client.config.id}`, - `Uptime : ${uptime}`, - `Memory : ${memoryInfo}`, - `CPU Usage : ${cpuInfo}`, - `Node.js : ${nodeVersion}`, - `Platform : ${platform}`, - `Guilds : ${guildCount}`, - `Users : ${userCount}`, - `Commands : ${commandCount}`, - `Modules : ${loadedModules.length > 0 ? loadedModules.join(', ') : 'None'}` - ]; - await interaction.editReply({ content: '```\n' + lines.join('\n') + '\n```' }); + // Format output as Markdown lists + const sections = []; + sections.push('**Process Metrics**'); + sections.push(`- Uptime: ${uptime}`); + sections.push(`- Memory: ${memoryInfo}`); + sections.push(`- CPU Usage: ${cpuInfo}`); + sections.push(`- Node.js: ${nodeVersion}`); + sections.push(`- Platform: ${platform}`); + sections.push(''); + sections.push(`- ${client.config.id}`); + sections.push(` - Guilds: ${guildCount}`); + sections.push(` - Users: ${userCount}`); + sections.push(` - Commands: ${commandCount}`); + sections.push(` - Modules: ${loadedModules.length > 0 ? loadedModules.join(', ') : 'None'}`); + await interaction.editReply({ content: sections.join('\n') }); client.logger.info(`[cmd:status] Returned status for client ${client.config.id}`); } + }, + // /statusall: show status for all initialized bot clients + { + data: new SlashCommandBuilder() + .setName('statusall') + .setDescription('Show status for all bot clients') + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .setDMPermission(false) + .addBooleanOption(option => + option + .setName('ephemeral') + .setDescription('Whether the response should be ephemeral') + .setRequired(false) + ), + async execute(interaction, client) { + // Only the bot owner may run this command + const ownerId = client.config.owner; + if (interaction.user.id !== String(ownerId)) { + return interaction.reply({ content: 'Only the bot owner can use this command.', ephemeral: true }); + } + const ephemeral = interaction.options.getBoolean('ephemeral') ?? true; + await interaction.deferReply({ ephemeral }); + // Process metrics + const uptimeSec = process.uptime(); + const hours = Math.floor(uptimeSec / 3600); + const minutes = Math.floor((uptimeSec % 3600) / 60); + const seconds = Math.floor(uptimeSec % 60); + const uptime = `${hours}h ${minutes}m ${seconds}s`; + const mem = process.memoryUsage(); + const toMB = bytes => (bytes / 1024 / 1024).toFixed(2); + const memoryInfo = `RSS: ${toMB(mem.rss)} MB, Heap: ${toMB(mem.heapUsed)}/${toMB(mem.heapTotal)} MB`; + const cpu = process.cpuUsage(); + const cpuInfo = `User: ${(cpu.user / 1000).toFixed(2)} ms, System: ${(cpu.system / 1000).toFixed(2)} ms`; + const nodeVersion = process.version; + const platform = `${process.platform} ${process.arch}`; + // Format output as Markdown lists + const sections = []; + sections.push('**Process Metrics**'); + sections.push(`- Uptime: ${uptime}`); + sections.push(`- Memory: ${memoryInfo}`); + sections.push(`- CPU Usage: ${cpuInfo}`); + sections.push(`- Node.js: ${nodeVersion}`); + sections.push(`- Platform: ${platform}`); + sections.push(''); + sections.push('**Clients**'); + for (const entry of botUtilsClients) { + const c = entry.client; + const cfg = entry.clientConfig; + const guildCount = c.guilds.cache.size; + const userCount = c.guilds.cache.reduce((sum, g) => sum + (g.memberCount || 0), 0); + const commandCount = c.commands.size; + const modules = c.modules ? Array.from(c.modules.keys()) : []; + sections.push(`- ${cfg.id}`); + sections.push(` - Guilds: ${guildCount}`); + sections.push(` - Users: ${userCount}`); + sections.push(` - Commands: ${commandCount}`); + sections.push(` - Modules: ${modules.length > 0 ? modules.join(', ') : 'None'}`); + sections.push(''); + } + await interaction.editReply({ content: sections.join('\n') }); + client.logger.info(`[cmd:statusall] Returned status for all ${botUtilsClients.length} clients`); + } } ]; -// Remove statusall command: not needed +// Note: statusall command implemented above // Enhance status command to list loaded modules // (nothing else follows) diff --git a/_opt/responsesPrompt.js b/_opt/responsesPrompt.js index 861db20..6107a54 100644 --- a/_opt/responsesPrompt.js +++ b/_opt/responsesPrompt.js @@ -83,8 +83,9 @@ export const commands = [ .setValue(chunk); modal.addComponents(new ActionRowBuilder().addComponents(input)); }); - // Add empty remaining fields - for (let i = chunks.length; i < MAX_FIELDS; i++) { + // Add one extra empty field to allow expansion (up to MAX_FIELDS) + if (chunks.length < MAX_FIELDS) { + const i = chunks.length; const input = new TextInputBuilder() .setCustomId(`prompt_${i}`) .setLabel(`Part ${i + 1}`)