Git and Bot utility updates.
This commit is contained in:
parent
0c99238646
commit
976d3bc6db
149
_opt/botUtils.js
149
_opt/botUtils.js
@ -1,4 +1,4 @@
|
|||||||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } from 'discord.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* botUtils module - provides administrative bot control commands
|
* botUtils module - provides administrative bot control commands
|
||||||
@ -86,102 +86,69 @@ export const commands = [
|
|||||||
const commandCount = client.commands.size;
|
const commandCount = client.commands.size;
|
||||||
// List of loaded optional modules
|
// List of loaded optional modules
|
||||||
const loadedModules = client.modules ? Array.from(client.modules.keys()) : [];
|
const loadedModules = client.modules ? Array.from(client.modules.keys()) : [];
|
||||||
// Format output as Markdown lists
|
// Build embed for status
|
||||||
const sections = [];
|
// Determine if gitUtils module is loaded
|
||||||
sections.push('**Process Metrics**');
|
const gitLoaded = client.modules?.has('gitUtils');
|
||||||
sections.push(`- Uptime: ${uptime}`);
|
let branch, build, statusBlock;
|
||||||
sections.push(`- Memory: ${memoryInfo}`);
|
if (gitLoaded) {
|
||||||
sections.push(`- CPU Usage: ${cpuInfo}`);
|
const git = client.modules.get('gitUtils');
|
||||||
sections.push(`- Node.js: ${nodeVersion}`);
|
try {
|
||||||
sections.push(`- Platform: ${platform}`);
|
branch = await git.getBranch();
|
||||||
sections.push('');
|
build = await git.getShortHash();
|
||||||
sections.push(`- ${client.config.id}`);
|
const statusRaw = await git.getStatusShort();
|
||||||
sections.push(` - Guilds: ${guildCount}`);
|
// Format status as fenced code block using template literals
|
||||||
sections.push(` - Users: ${userCount}`);
|
// Normalize each line with a leading space in a code fence
|
||||||
sections.push(` - Commands: ${commandCount}`);
|
// Prefix raw status output with a single space
|
||||||
sections.push(` - Modules: ${loadedModules.length > 0 ? loadedModules.join(', ') : 'None'}`);
|
statusBlock = statusRaw
|
||||||
await interaction.editReply({ content: sections.join('\n') });
|
? '```\n ' + statusRaw + '\n```'
|
||||||
client.logger.info(`[cmd:status] Returned status for client ${client.config.id}`);
|
: '```\n (clean)\n```';
|
||||||
}
|
} catch {
|
||||||
},
|
branch = 'error';
|
||||||
// /statusall: show status for all initialized bot clients
|
build = 'error';
|
||||||
{
|
// Represent error status in code fence
|
||||||
data: new SlashCommandBuilder()
|
statusBlock = '```\n (error)\n```';
|
||||||
.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;
|
// Prepare module list as bullet points
|
||||||
await interaction.deferReply({ ephemeral });
|
const moduleList = loadedModules.length > 0
|
||||||
// Process metrics
|
? loadedModules.map(m => `• ${m}`).join('\n')
|
||||||
const uptimeSec = process.uptime();
|
: 'None';
|
||||||
const hours = Math.floor(uptimeSec / 3600);
|
// Assemble fields
|
||||||
const minutes = Math.floor((uptimeSec % 3600) / 60);
|
const fields = [];
|
||||||
const seconds = Math.floor(uptimeSec % 60);
|
// Client identification
|
||||||
const uptime = `${hours}h ${minutes}m ${seconds}s`;
|
fields.push({ name: 'Client', value: client.config.id, inline: false });
|
||||||
const mem = process.memoryUsage();
|
// Performance metrics
|
||||||
const toMB = bytes => (bytes / 1024 / 1024).toFixed(2);
|
fields.push({ name: 'CPU Usage', value: cpuInfo, inline: false });
|
||||||
const memoryInfo = `RSS: ${toMB(mem.rss)} MB, Heap: ${toMB(mem.heapUsed)}/${toMB(mem.heapTotal)} MB`;
|
fields.push({ name: 'Memory', value: memoryInfo, inline: false });
|
||||||
const cpu = process.cpuUsage();
|
// Environment
|
||||||
const cpuInfo = `User: ${(cpu.user / 1000).toFixed(2)} ms, System: ${(cpu.system / 1000).toFixed(2)} ms`;
|
fields.push({ name: 'Node.js', value: nodeVersion, inline: true });
|
||||||
const nodeVersion = process.version;
|
fields.push({ name: 'Platform', value: platform, inline: true });
|
||||||
const platform = `${process.platform} ${process.arch}`;
|
// Uptime
|
||||||
// Format output as Markdown lists
|
fields.push({ name: 'Uptime', value: uptime, inline: true });
|
||||||
const sections = [];
|
// Loaded modules
|
||||||
sections.push('**Process Metrics**');
|
fields.push({ name: 'Modules', value: moduleList, inline: false });
|
||||||
sections.push(`- Uptime: ${uptime}`);
|
// Entity counts
|
||||||
sections.push(`- Memory: ${memoryInfo}`);
|
fields.push({ name: 'Commands', value: commandCount.toString(), inline: true });
|
||||||
sections.push(`- CPU Usage: ${cpuInfo}`);
|
fields.push({ name: 'Guilds', value: guildCount.toString(), inline: true });
|
||||||
sections.push(`- Node.js: ${nodeVersion}`);
|
fields.push({ name: 'Users', value: userCount.toString(), inline: true });
|
||||||
sections.push(`- Platform: ${platform}`);
|
// Git reference and status if available
|
||||||
sections.push('');
|
if (gitLoaded) {
|
||||||
sections.push('**Clients**');
|
fields.push({ name: 'Git Reference', value: `${branch}/${build}`, inline: false });
|
||||||
for (const entry of botUtilsClients) {
|
fields.push({ name: 'Git Status', value: statusBlock, inline: false });
|
||||||
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') });
|
// Create embed
|
||||||
client.logger.info(`[cmd:statusall] Returned status for all ${botUtilsClients.length} clients`);
|
const embed = new EmbedBuilder()
|
||||||
|
.setAuthor({ name: 'ClientX', iconURL: client.user.displayAvatarURL() })
|
||||||
|
.setThumbnail(client.user.displayAvatarURL())
|
||||||
|
.addFields(fields)
|
||||||
|
.setTimestamp();
|
||||||
|
await interaction.editReply({ embeds: [embed] });
|
||||||
|
client.logger.info(`[cmd:status] Returned status embed for client ${client.config.id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Note: statusall command implemented above
|
// Module loaded logging
|
||||||
|
|
||||||
// Enhance status command to list loaded modules
|
|
||||||
// (nothing else follows)
|
|
||||||
// Store all initialized clients for statusall
|
|
||||||
const botUtilsClients = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional init hook; logs when the module is loaded and tracks clients
|
|
||||||
* @param {import('discord.js').Client} client
|
|
||||||
* @param {Object} clientConfig
|
|
||||||
*/
|
|
||||||
export async function init(client, clientConfig) {
|
export async function init(client, clientConfig) {
|
||||||
client.logger.info('[module:botUtils] Module loaded');
|
client.logger.info('[module:botUtils] Module loaded');
|
||||||
// Track this client instance and its config
|
|
||||||
botUtilsClients.push({ client, clientConfig });
|
|
||||||
}
|
}
|
||||||
@ -100,3 +100,47 @@ export const commands = [
|
|||||||
export async function init(client) {
|
export async function init(client) {
|
||||||
client.logger.warn('[module:gitUtils] Git utilities module loaded - dangerous module, use with caution');
|
client.logger.warn('[module:gitUtils] Git utilities module loaded - dangerous module, use with caution');
|
||||||
}
|
}
|
||||||
|
// Helper functions for external use
|
||||||
|
/**
|
||||||
|
* Get current Git branch name
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getBranch() {
|
||||||
|
return runGit(['rev-parse', '--abbrev-ref', 'HEAD']);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get short commit hash of HEAD
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getShortHash() {
|
||||||
|
return runGit(['rev-parse', '--short', 'HEAD']);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get concise working tree status (git status --porcelain)
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getStatusShort() {
|
||||||
|
return runGit(['status', '--porcelain']);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Git remote origin URL
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getRemoteUrl() {
|
||||||
|
return runGit(['config', '--get', 'remote.origin.url']);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get recent commit log (n lines, one-line format)
|
||||||
|
* @param {number} [n=5]
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getLog(n = 5) {
|
||||||
|
return runGit(['log', `-n${n}`, '--oneline']);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get diff summary (git diff --stat)
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
export async function getDiffStat() {
|
||||||
|
return runGit(['diff', '--stat']);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user