import { createCommand } from "@lib/utils"; import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, ComponentType } from "discord.js"; import { UpdateService } from "@/modules/admin/update.service"; import { getCheckingEmbed, getNoUpdatesEmbed, getUpdatesAvailableMessage, getPreparingEmbed, getUpdatingEmbed, getCancelledEmbed, getTimeoutEmbed, getErrorEmbed } from "@/modules/admin/update.view"; export const update = createCommand({ data: new SlashCommandBuilder() .setName("update") .setDescription("Check for updates and restart the bot") .addBooleanOption(option => option.setName("force") .setDescription("Force update even if checks fail (not recommended)") .setRequired(false) ) .setDefaultMemberPermissions(PermissionFlagsBits.Administrator), execute: async (interaction) => { await interaction.deferReply({ flags: MessageFlags.Ephemeral }); const force = interaction.options.getBoolean("force") || false; try { await interaction.editReply({ embeds: [getCheckingEmbed()] }); const { hasUpdates, log, branch } = await UpdateService.checkForUpdates(); if (!hasUpdates && !force) { await interaction.editReply({ embeds: [getNoUpdatesEmbed()] }); return; } const { embeds, components } = getUpdatesAvailableMessage(branch, log, force); const response = await interaction.editReply({ embeds, components }); try { const confirmation = await response.awaitMessageComponent({ filter: (i) => i.user.id === interaction.user.id, componentType: ComponentType.Button, time: 30000 }); if (confirmation.customId === "confirm_update") { await confirmation.update({ embeds: [getPreparingEmbed()], components: [] }); // 1. Check what the update requires const { needsInstall, needsMigrations } = await UpdateService.checkUpdateRequirements(branch); // 2. Prepare context BEFORE update await UpdateService.prepareRestartContext({ channelId: interaction.channelId, userId: interaction.user.id, timestamp: Date.now(), runMigrations: needsMigrations, installDependencies: needsInstall }); // 3. Update UI to "Restarting" state await interaction.editReply({ embeds: [getUpdatingEmbed(needsInstall)] }); // 4. Perform Update (Danger Zone) await UpdateService.performUpdate(branch); // 5. Trigger Restart (if we are still alive) await UpdateService.triggerRestart(); } else { await confirmation.update({ embeds: [getCancelledEmbed()], components: [] }); } } catch (e) { if (e instanceof Error && e.message.includes("time")) { await interaction.editReply({ embeds: [getTimeoutEmbed()], components: [] }); } else { throw e; } } } catch (error) { console.error("Update failed:", error); await interaction.editReply({ embeds: [getErrorEmbed(error)] }); } } });