import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js'; import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); /** * Git-related slash commands: /gitstatus and /gitpull */ export const commands = [ // Show current branch and commit status { data: new SlashCommandBuilder() .setName('gitstatus') .setDescription('Show current git branch and remote status'), async execute(interaction, client) { try { // Get current branch and commit const { stdout: branchOut } = await execAsync('git rev-parse --abbrev-ref HEAD'); const branch = branchOut.trim(); const { stdout: localOut } = await execAsync('git rev-parse HEAD'); const local = localOut.trim().slice(0, 7); // Fetch updates and get remote commit await execAsync('git fetch --quiet'); const { stdout: remoteOut } = await execAsync(`git rev-parse origin/${branch}`); const remote = remoteOut.trim().slice(0, 7); // Determine ahead/behind counts const { stdout: behindOut } = await execAsync(`git rev-list --count HEAD..origin/${branch}`); const behind = parseInt(behindOut.trim(), 10); const { stdout: aheadOut } = await execAsync(`git rev-list --count origin/${branch}..HEAD`); const ahead = parseInt(aheadOut.trim(), 10); const status = (ahead === 0 && behind === 0) ? 'Up-to-date' : `${ahead} ahead, ${behind} behind`; // Reply with status await interaction.reply({ content: `Branch: \`${branch}\`\nLocal: \`${local}\`\nRemote: \`${remote}\`\nStatus: ${status}`, ephemeral: true }); } catch (err) { client.logger.error(`Error in gitstatus: ${err.message}`); await interaction.reply({ content: `Failed to get git status: ${err.message}`, ephemeral: true }); } } }, // Pull latest changes and restart bot (owner only) { data: new SlashCommandBuilder() .setName('gitpull') .setDescription('Pull latest changes and restart bot (Owner only)') .setDefaultMemberPermissions(PermissionFlagsBits.Administrator), async execute(interaction, client) { const ownerId = client.config.owner; if (interaction.user.id !== ownerId) { return interaction.reply({ content: 'Only the bot owner can perform this action.', ephemeral: true }); } await interaction.deferReply({ ephemeral: true }); try { // Pull with fast-forward only const { stdout, stderr } = await execAsync('git pull --ff-only'); const output = stdout.trim() || stderr.trim(); await interaction.editReply({ content: `Git pull output:\n\`\`\`\n${output}\n\`\`\`\nRestarting...` }); setTimeout(() => process.exit(0), 1000); } catch (err) { client.logger.error(`Error in gitpull: ${err.message}`); await interaction.editReply({ content: `Git pull failed: ${err.message}`, ephemeral: true }); } } } ]; /** * No special init logic for git utilities */ export async function init(client, config) { client.logger.info('Git utilities module loaded'); }