Command registration (for mini)
diff --git a/src/utils/client.ts b/src/utils/client.ts
index 7d608c7..6aa9b43 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -1,14 +1,16 @@
-import { Client } from 'discord.js';
+import Discord, { Client, Interaction } from 'discord.js';
 import { Logger } from "../utils/log.js";
 import Memory from "../utils/memory.js";
 import type { VerifySchema } from "../reflex/verify.js";
 import { Guilds, History, ModNotes, Premium } from "../utils/database.js";
 import EventScheduler from "../utils/eventScheduler.js";
 import type { RoleMenuSchema } from "../actions/roleMenu.js";
+import config from "../config/main.json" assert { type: "json" };
 
 
 class NucleusClient extends Client {
     logger = Logger;
+    config: typeof config = config;
     verify: Record<string, VerifySchema> = {};
     roleMenu: Record<string, RoleMenuSchema> = {};
     memory: Memory = new Memory() as Memory;
@@ -20,6 +22,14 @@
         premium: Premium;
         eventScheduler: EventScheduler;
     };
+    // commands: Record<string, {
+    //     command: Discord.SlashCommandBuilder |
+    //              ((builder: Discord.SlashCommandBuilder) => Discord.SlashCommandBuilder) |
+    //              Discord.SlashCommandSubcommandBuilder | ((builder: Discord.SlashCommandSubcommandBuilder) => Discord.SlashCommandSubcommandBuilder) | Discord.SlashCommandSubcommandGroupBuilder | ((builder: Discord.SlashCommandSubcommandGroupBuilder) => Discord.SlashCommandSubcommandGroupBuilder),
+    //     callback: (interaction: Interaction) => Promise<void>,
+    //     check: (interaction: Interaction) => Promise<boolean> | boolean
+    // }> = {};
+    commands: Discord.Collection<string, [Function, Function]> = new Discord.Collection();
 
     constructor(database: typeof NucleusClient.prototype.database) {
         super({ intents: 32767 });
diff --git a/src/utils/commandRegistration/getFilesInFolder.ts b/src/utils/commandRegistration/getFilesInFolder.ts
index a669065..d8a1298 100644
--- a/src/utils/commandRegistration/getFilesInFolder.ts
+++ b/src/utils/commandRegistration/getFilesInFolder.ts
@@ -1,23 +1,27 @@
 import fs from "fs";
 
-export default async function getSubcommandsInFolder(path: string) {
+export default async function getSubcommandsInFolder(path: string, indent: string = "") {
     const files = fs.readdirSync(path, { withFileTypes: true }).filter(
         file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
     );
     const subcommands = [];
     const subcommandGroups = [];
+    let errors = 0;
     for (const file of files) {
         if (file.name === "_meta.js") continue;
-        // If its a folder
-        if (file.isDirectory()) {
-            // Get the _meta.ts file
-            console.log(`│ ├─ Loading subcommand group ${file.name}}`)
-            subcommandGroups.push((await import(`../../../${path}/${file.name}/_meta.js`)).command);
-        } else if (file.name.endsWith(".js")) {
-            // If its a file
-            console.log(`│ ├─ Loading subcommand ${file.name}}`)
-            subcommands.push((await import(`../../../${path}/${file.name}`)).command);
+        try {
+            if (file.isDirectory()) {
+                // Get the _meta.ts file
+                subcommandGroups.push((await import(`../../../${path}/${file.name}/_meta.js`)).command);
+            } else if (file.name.endsWith(".js")) {
+                // If its a file
+                console.log(`│  ${indent}├─ Loading subcommand ${file.name}`)
+                subcommands.push((await import(`../../../${path}/${file.name}`)).command);
+            }
+        } catch (e) {
+            console.error(`│  ${indent}│  └─ Error loading ${file.name}: ${e}`);
+            errors++;
         }
     }
-    return {subcommands, subcommandGroups};
+    return {subcommands, subcommandGroups, errors};
 }
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index af0b5fc..a734921 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -1,9 +1,16 @@
-import { SlashCommandBuilder } from 'discord.js';
+import { Interaction, SlashCommandBuilder } from 'discord.js';
 import config from "../../config/main.json" assert { type: "json" };
 import client from "../client.js";
 import fs from "fs";
 
 
+const colours = {
+    red: "\x1b[31m",
+    green: "\x1b[32m",
+    yellow: "\x1b[33m",
+    none: "\x1b[0m"
+}
+
 async function registerCommands() {
     const developmentMode = config.enableDevelopment;
     const commands = [];
@@ -14,15 +21,18 @@
     console.log(`Registering ${files.length} commands`)
     let i = 0;
     for (const file of files) {
-        // Box drawing characters: | └ ─ ┌ ┐ ┘ ┬ ┤ ├ ┴ ┼
-        console.log(`├─ ${file.name}`)
+        const last = i === files.length - 1 ? "└" : "├";
         if (file.isDirectory()) {
+            console.log(`${last}─ ${colours.yellow}Loading subcommands of ${file.name}${colours.none}`)
             commands.push((await import(`../../../${config.commandsFolder}/${file.name}/_meta.js`)).command);
         } else if (file.name.endsWith(".js")) {
-            commands.push((await import(`../../../${config.commandsFolder}/${file.name}`)).command);
+            console.log(`${last}─ ${colours.yellow}Loading command ${file.name}${colours.none}`)
+            const fetched = (await import(`../../../${config.commandsFolder}/${file.name}`));
+            commands.push(fetched.command);
+            client.commands.set(fetched.command.name, [fetched.check, fetched.callback]);
         }
         i++;
-        console.log(`├─ Loaded ${file.name} [${i} / ${files.length}]`)
+        console.log(`${last.replace("└", " ").replace("├", "│")}  └─ ${colours.green}Loaded ${file.name} [${i} / ${files.length}]${colours.none}`)
     }
     console.log(`Loaded ${commands.length} commands, processing...`)
     const processed = []
@@ -39,11 +49,9 @@
 
     if (developmentMode) {
         const guild = await client.guilds.fetch(config.developmentGuildID);
-        guild.commands.set([])
         guild.commands.set(processed);
         console.log(`Commands registered in ${guild.name}`)
     } else {
-        client.application!.commands.set([])
         client.application!.commands.set(processed);
         console.log(`Commands registered globally`)
     }
@@ -51,11 +59,83 @@
 };
 
 async function registerEvents() {
-    // pass
+    console.log("Reading events")
+    const files = fs.readdirSync(config.eventsFolder, { withFileTypes: true }).filter(
+        file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
+    );
+    console.log(`Registering ${files.length} events`)
+    let i = 0;
+    let errors = 0;
+    for (const file of files) {
+        const last = i === files.length - 1 ? "└" : "├";
+        i++;
+        try {
+            console.log(`${last}─ ${colours.yellow}Loading event ${file.name}${colours.none}`)
+            const event = (await import(`../../../${config.eventsFolder}/${file.name}`));
+
+            client.on(event.event, event.callback.bind(null, client));
+
+            console.log(`${last.replace("└", " ").replace("├", "│")}  └─ ${colours.green}Loaded ${file.name} [${i} / ${files.length}]${colours.none}`)
+        } catch (e) {
+            errors++;
+            console.log(`${last.replace("└", " ").replace("├", "│")}  └─ ${colours.red}Failed to load ${file.name} [${i} / ${files.length}]${colours.none}`)
+        }
+    }
+    console.log(`Loaded ${files.length - errors} events (${errors} failed)`)
 };
 
+async function registerCommandHandler() {
+    client.on("interactionCreate", async (interaction: Interaction) => {
+        if (!interaction.isCommand()) return;
+
+        const commandName = interaction.commandName;
+        const subcommandGroupName = interaction.options.getSubcommandGroup(false);
+        const subcommandName = interaction.options.getSubcommand(false);
+
+        let fullCommandName = commandName + (subcommandGroupName ? ` ${subcommandGroupName}` : "") + (subcommandName ? ` ${subcommandName}` : "");
+
+        const command = this.commands.get(fullCommandName);
+        if (!command) return;
+
+        const sendErrorMessage = async (error: Error) => {
+            if (this.listenerCount("commandError")) {
+                return this.emit("commandError", interaction, error);
+            }
+            let method = (!interaction.deferred && !interaction.replied) ? interaction.reply.bind(interaction) : interaction.followUp.bind(interaction);
+            await method({
+                embeds: [
+                    new Embed()
+                        .setColor(0xff0000)
+                        .setTitle("I couldn't run that command")
+                        .setDescription(error.message ?? error.toString())
+                ]
+            , ephemeral: true});
+        }
+
+        try {
+            let hasPermission = await command.check(interaction);
+
+            if (!hasPermission) {
+                sendErrorMessage(new CheckFailedError("You don't have permission to run this command"));
+                return;
+            }
+        } catch (error) {
+            sendErrorMessage(error);
+            return;
+        }
+        try {
+            await command.callback(interaction);
+        } catch (error) {
+            this._error(error);
+            sendErrorMessage(error);
+            return;
+        }
+    });
+}
+
 export default async function register() {
-    console.log("> Registering commands")
     await registerCommands();
+    await registerCommandHandler();
     await registerEvents();
+    console.log(`${colours.green}Registered commands and events${colours.none}`)
 };
diff --git a/src/utils/commandRegistration/slashCommandBuilder.ts b/src/utils/commandRegistration/slashCommandBuilder.ts
index 719855f..c7ac55f 100644
--- a/src/utils/commandRegistration/slashCommandBuilder.ts
+++ b/src/utils/commandRegistration/slashCommandBuilder.ts
@@ -4,8 +4,17 @@
 import getSubcommandsInFolder from "./getFilesInFolder.js";
 
 
+const colours = {
+    red: "\x1b[31m",
+    green: "\x1b[32m",
+    none: "\x1b[0m"
+}
+
+
 export async function group(name: string, description: string, path: string) {
-    const fetched = await getSubcommandsInFolder(config.commandsFolder + "/" + path)
+    console.log(`│  ├─ Loading group ${name}`)
+    const fetched = await getSubcommandsInFolder(config.commandsFolder + "/" + path, "│  ")
+    console.log(`│  │  └─ ${fetched.errors ? colours.red : colours.green}Loaded ${fetched.subcommands.length} subcommands for ${name} (${fetched.errors} failed)${colours.none}`)
     return (subcommandGroup: SlashCommandSubcommandGroupBuilder) => {
         subcommandGroup
             .setName(name)
@@ -21,7 +30,7 @@
 
 export async function command(name: string, description: string, path: string) {
     const fetched = await getSubcommandsInFolder(config.commandsFolder + "/" + path);
-    console.log(`│ ├─ Loaded ${fetched.subcommands.length} subcommands and ${fetched.subcommandGroups.length} subcommand groups for ${name}`)
+    console.log(`│  ├─ ${fetched.errors ? colours.red : colours.green}Loaded ${fetched.subcommands.length} subcommands and ${fetched.subcommandGroups.length} subcommand groups for ${name} (${fetched.errors} failed)${colours.none}`)
     return (command: SlashCommandBuilder) => {
         command.setName(name)
         command.setDescription(description)