import { ChannelType, MessageFlags, PermissionFlagsBits, SlashCommandSubcommandBuilder, type TextChannel, } from "discord.js"; import { Command, requirePermission } from "@voidy/framework"; import { ChatbotChannel } from "../schemas/ChatbotChannel"; import { ChatbotRepository } from "../schemas/ChatbotRepository"; export default new Command({ id: "chatbot.setup", use: [requirePermission(PermissionFlagsBits.ManageGuild)], data: new SlashCommandSubcommandBuilder() .setName("setup") .setDescription("Set up chatbot in a channel (creates webhook automatically).") .addChannelOption((option) => option .setName("channel") .setDescription("Channel to enable chatbot in.") .addChannelTypes(ChannelType.GuildText) .setRequired(true), ) .addIntegerOption((option) => option .setName("interval") .setDescription("How often to send a message.") .setRequired(true) .setMinValue(1), ) .addStringOption((option) => option .setName("unit") .setDescription("Interval unit.") .setRequired(true) .addChoices( { name: "Seconds", value: "seconds" }, { name: "Minutes", value: "minutes" }, ), ) .addStringOption((option) => option .setName("mode") .setDescription("Content source mode.") .addChoices( { name: "Global", value: "global" }, { name: "Local", value: "local" }, ), ) .addStringOption((option) => option.setName("repository").setDescription("Local repository name (required if mode is local)."), ), execute: async ({ interaction }) => { const channel = interaction.options.getChannel("channel", true) as TextChannel; const interval = interaction.options.getInteger("interval", true); const unit = interaction.options.getString("unit", true); const mode = (interaction.options.getString("mode") ?? "global") as "global" | "local"; const repoName = interaction.options.getString("repository"); const intervalSeconds = unit === "minutes" ? interval * 60 : interval; // Check if channel already has chatbot const existing = await ChatbotChannel.findOne({ channelId: channel.id }); if (existing) { await interaction.reply({ content: `Chatbot is already set up in <#${channel.id}>.`, flags: [MessageFlags.Ephemeral], }); return; } // Resolve repository for local mode let repositoryId; if (mode === "local") { if (!repoName) { await interaction.reply({ content: "You must specify a repository name when using local mode.", flags: [MessageFlags.Ephemeral], }); return; } const repo = await ChatbotRepository.findOne({ scope: "local", guildId: interaction.guildId, name: repoName, }); if (!repo) { await interaction.reply({ content: `Local repository "${repoName}" not found. Create one first with \`/chatbot repository create\`.`, flags: [MessageFlags.Ephemeral], }); return; } repositoryId = repo._id; } await interaction.deferReply({ flags: [MessageFlags.Ephemeral] }); // Create webhook in channel const webhook = await channel.createWebhook({ name: "Voidy Chatbot" }); await ChatbotChannel.create({ guildId: interaction.guildId, channelId: channel.id, webhookId: webhook.id, webhookToken: webhook.token, mode, repositoryId, enabled: true, intervalSeconds, }); const display = unit === "minutes" ? `${interval} minute(s)` : `${interval} second(s)`; await interaction.editReply({ content: `Chatbot enabled in <#${channel.id}> using **${mode}** mode, posting every **${display}**.`, }); }, });