From e7eadc66de6010028e160e633faa1b47277b9030 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 15:23:31 -0500 Subject: [PATCH 01/13] Fixing up stuff to have comments --- README.md | 4 ++ package-lock.json | 18 ++++++++- package.json | 4 +- src/bot.ts | 28 ++++++++++++-- src/commands/general/ping.ts | 30 +++++++++++++-- src/commands/summary/summary.ts | 45 ++++++++++++++++++---- src/config/env.ts | 27 ++++++++++++- src/registerCommands.ts | 24 ++++++++---- src/services/discord/commandLoader.ts | 43 +++++++++++++++++++-- src/services/discord/interactionHandler.ts | 20 +++++++--- src/services/summary/llmSummary.ts | 27 +++++++++++-- src/services/summary/localSummary.ts | 23 ++++++++++- src/services/summary/summarizer.ts | 7 +++- tsconfig.json | 2 +- 14 files changed, 262 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 1f6413d5..3275f6d7 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ OmegaBot is a modular Discord bot designed to support development projects with ## Features Current features: + - Slash command system - Ping command for testing - Summary command with local summary mode @@ -23,6 +24,7 @@ Current features: - Simple and readable project structure Planned features: + - FAQ storage and quick lookup - GitHub issues and pull request lookups - Pull request announcements @@ -32,6 +34,7 @@ Planned features: ## Getting Started ### Requirements + - Node 18 or newer - A Discord bot token - A development server where you have Manage Server permissions @@ -127,6 +130,7 @@ OmegaBot is online │ └── summarizer.ts └── tsconfig.json ``` + --- ## Extending OmegaBot diff --git a/package-lock.json b/package-lock.json index 1d6e40f7..6a50abde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", - "openai": "^4.0.0" + "openai": "^4.0.0", + "prettier": "^3.7.4" }, "devDependencies": { "@types/node": "^24.10.2", @@ -811,6 +812,21 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/package.json b/package.json index 3bb162f3..18334873 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "scripts": { "build": "tsc", "dev": "npm run build && node dist/bot.js", - "register": "npm run build && node dist/registerCommands.js" + "register": "npm run build && node dist/registerCommands.js", + "format": "prettier . --write", + "format:check": "prettier . --check" }, "dependencies": { "discord.js": "^14.14.1", diff --git a/src/bot.ts b/src/bot.ts index 5beeaea9..25c7bf9e 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,22 +1,42 @@ import { Client, GatewayIntentBits } from "discord.js"; -import { loadCommands, type CommandClient } from "./services/discord/commandLoader.js"; +import { + loadCommands, + type CommandClient, +} from "./services/discord/commandLoader.js"; import { handleInteraction } from "./services/discord/interactionHandler.js"; import { env } from "./config/env.js"; - +/* + * Create the Discord client with only the intents required for slash-command handling. + */ const client = new Client({ - intents: [GatewayIntentBits.Guilds] + intents: [GatewayIntentBits.Guilds], }) as CommandClient; +/* + * Initialize the command registry where loaded slash commands will be stored. + */ client.commands = new Map(); +/* + * Load and register all compiled command modules before the bot starts handling interactions. + */ await loadCommands(client); -client.on("interactionCreate", async interaction => { +/* + * Forward every incoming interaction to the central interaction handler. + */ +client.on("interactionCreate", async (interaction) => { await handleInteraction(interaction, client); }); +/* + * Log a confirmation once the bot successfully connects. + */ client.once("clientReady", () => { console.log("OmegaBot is online"); }); +/* + * Start the bot session using the configured token. + */ client.login(env.token); diff --git a/src/commands/general/ping.ts b/src/commands/general/ping.ts index d6781ed6..023ee158 100644 --- a/src/commands/general/ping.ts +++ b/src/commands/general/ping.ts @@ -1,24 +1,46 @@ import { SlashCommandBuilder, - type ChatInputCommandInteraction + type ChatInputCommandInteraction, } from "discord.js"; +/** + * Defines the /ping command. + * Used to verify that the bot is responding and to measure latency. + */ export const data = new SlashCommandBuilder() .setName("ping") .setDescription("Ping test with latency"); export async function execute( - interaction: ChatInputCommandInteraction + interaction: ChatInputCommandInteraction, ): Promise { + /** + * First reply (with fetchReply: true) returns the actual message object. + * We use this to calculate round-trip latency between interaction and reply. + */ const sent = await interaction.reply({ content: "Pinging...", - fetchReply: true + fetchReply: true, }); + /** + * Measure latency: + * - interaction.createdTimestamp is when Discord received the slash command + * - sent.createdTimestamp is when Discord created the bot's response + */ const latency = sent.createdTimestamp - interaction.createdTimestamp; + + /** + * WebSocket heartbeat is the current ping between the bot and Discord's gateway. + * Lower numbers mean a healthier connection. + */ const wsPing = interaction.client.ws.ping; + /** + * Edit the original message to show actual latency numbers. + * This keeps the interaction tidy instead of sending another message. + */ await interaction.editReply( - `Pong. Round trip latency is ${latency}ms. WebSocket heartbeat is ${wsPing}ms.` + `Pong. Round trip latency is ${latency}ms. WebSocket heartbeat is ${wsPing}ms.`, ); } diff --git a/src/commands/summary/summary.ts b/src/commands/summary/summary.ts index 75d3a5e1..e16d881d 100644 --- a/src/commands/summary/summary.ts +++ b/src/commands/summary/summary.ts @@ -1,59 +1,88 @@ import { SlashCommandBuilder, AttachmentBuilder, - type ChatInputCommandInteraction + type ChatInputCommandInteraction, } from "discord.js"; import { summarize } from "../../services/summary/summarizer.js"; +/** + * Defines the /summary command. + * Used to summarize the chats. + */ + export const data = new SlashCommandBuilder() .setName("summary") .setDescription("Summarize recent messages") - .addIntegerOption(opt => + .addIntegerOption((opt) => opt .setName("count") .setDescription("How many messages to fetch") .setMinValue(10) - .setMaxValue(100) + .setMaxValue(100), ); +/** + * Caps at 50 lines by default + */ + export async function execute( - interaction: ChatInputCommandInteraction + interaction: ChatInputCommandInteraction, ): Promise { const count = interaction.options.getInteger("count") ?? 50; await interaction.deferReply(); const messages = await interaction.channel?.messages.fetch({ limit: count }); + /** + * Guard: if we could not fetch messages (no channel or API issue), + * tell the user and stop instead of throwing later. + */ if (!messages) { await interaction.editReply("Could not fetch messages for this channel."); return; } + /** + * Filter out bots so summaries don’t include automated noise. + * Sort oldest→newest so the summary respects conversation order. + */ const userMessages = messages - .filter(m => !m.author.bot && m.content) + .filter((m) => !m.author.bot && m.content) .sort((a, b) => a.createdTimestamp - b.createdTimestamp); + /** + * If no non-bot messages remain after filtering, tell the user there is nothing to summarize. + */ if (userMessages.size === 0) { await interaction.editReply("No usable messages found to summarize."); return; } + /** + * Combine messages into a simple “username: content” transcript, one per line. + */ const text = userMessages - .map(m => `${m.author.username}: ${m.content}`) + .map((m) => `${m.author.username}: ${m.content}`) .join("\n"); const output = await summarize(text); + /** + * If the summary exceeds Discord’s 2000-character limit, send it as a text file instead of a normal message. + */ if (output.length > 2000) { const file = new AttachmentBuilder(Buffer.from(output), { - name: "summary.txt" + name: "summary.txt", }); await interaction.editReply({ content: "Summary was too long. Uploaded as file.", - files: [file] + files: [file], }); return; } + /** + * Edit the deferred reply with the final summary text. + */ await interaction.editReply(output); } diff --git a/src/config/env.ts b/src/config/env.ts index 38acf599..96b217dc 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -1,6 +1,11 @@ import dotenv from "dotenv"; dotenv.config(); +/** + * Helper to enforce that required environment variables are present. + * If a variable is missing, the bot fails fast at startup instead of + * crashing later at runtime in unpredictable ways. + */ function requireEnv(name: string): string { const value = process.env[name]; if (!value) { @@ -9,10 +14,30 @@ function requireEnv(name: string): string { return value; } +/** + * Centralized environment configuration for OmegaBot. + * + * Required fields: + * - DISCORD_TOKEN Bot authentication token for connecting to Discord. + * - DISCORD_APP_ID Application ID needed for command registration. + * - DISCORD_GUILD_ID Guild where development commands are registered. + * + * Optional fields: + * - SUMMARY_MODE "local" (default) or "llm" + * Determines which summarizer implementation is used. + * - OPENAI_API_KEY Only required when using LLM summary mode. + * + * Keeping this configuration in one place prevents scattered env lookups + * and makes the bot easier to configure, test, and deploy. + */ export const env = { token: requireEnv("DISCORD_TOKEN"), appId: requireEnv("DISCORD_APP_ID"), guildId: requireEnv("DISCORD_GUILD_ID"), + + // Summary mode defaults to local so the bot can run without AI keys. summaryMode: process.env.SUMMARY_MODE ?? "local", - openAIKey: process.env.OPENAI_API_KEY ?? null + + // Optional, only needed when user chooses LLM summarization. + openAIKey: process.env.OPENAI_API_KEY ?? null, }; diff --git a/src/registerCommands.ts b/src/registerCommands.ts index 2425bd67..a325bf81 100644 --- a/src/registerCommands.ts +++ b/src/registerCommands.ts @@ -3,6 +3,9 @@ import fs from "fs"; import path from "path"; import { env } from "./config/env.js"; +/* + * Read all compiled command definitions and prepare them for registration with the Discord API. + */ async function loadCommandData() { const commands: any[] = []; // Read built JS commands from dist @@ -22,20 +25,27 @@ async function loadCommandData() { } return commands; } - +/* + * Register all slash commands with Discord for the configured application and guild. + */ async function register() { const rest = new REST({ version: "10" }).setToken(env.token); const commands = await loadCommandData(); - await rest.put( - Routes.applicationGuildCommands(env.appId, env.guildId), - { body: commands } - ); + /* + * Overwrite the guild’s existing slash commands with the updated command list. + */ + await rest.put(Routes.applicationGuildCommands(env.appId, env.guildId), { + body: commands, + }); console.log("Commands registered"); } -register().catch(err => { +/* + * Report failures clearly and exit with a non-zero status. + */ +register().catch((err) => { console.error("Failed to register commands:", err); process.exit(1); -}); \ No newline at end of file +}); diff --git a/src/services/discord/commandLoader.ts b/src/services/discord/commandLoader.ts index 04f954da..225e3785 100644 --- a/src/services/discord/commandLoader.ts +++ b/src/services/discord/commandLoader.ts @@ -3,37 +3,74 @@ import path from "path"; import { Client, type ChatInputCommandInteraction, - type SlashCommandBuilder + type SlashCommandBuilder, } from "discord.js"; +/** + * Contract that every slash command module must follow. + * + * - `data` describes the command to Discord (name, description, options) + * using SlashCommandBuilder. + * - `execute` is the handler that runs when a user invokes the command. + */ export interface SlashCommand { data: SlashCommandBuilder; execute: (interaction: ChatInputCommandInteraction) => Promise; } +/** + * Extension of the Discord Client that includes a `commands` map. + * + * This lets us: + * - dynamically load commands at startup + * - look up the correct handler at runtime by command name + * (e.g. "ping" -> ping command module) + */ export type CommandClient = Client & { commands: Map; }; +/** + * Dynamically loads all compiled command modules and registers them on the client. + * + * How it works: + * - Looks under dist/commands for grouped command folders (e.g. general/, summary/) + * - Imports every .js file in those folders at runtime + * - Expects each module to export `data` and `execute` matching the SlashCommand interface + * - Registers each command into `client.commands` keyed by its name + * + * This allows new commands to be added simply by dropping a new file in src/commands, + * then rebuilding the project. + */ export async function loadCommands(client: CommandClient): Promise { - // We run compiled JS from dist/, so load commands from dist/commands + // We run the bot from compiled JS, so commands are discovered in dist/commands, + // not src/commands. const basePath = path.join(process.cwd(), "dist/commands"); const groups = fs.readdirSync(basePath); + // Each "group" is a subfolder under dist/commands (e.g. general/, summary/). for (const group of groups) { const groupPath = path.join(basePath, group); if (!fs.statSync(groupPath).isDirectory()) continue; const files = fs.readdirSync(groupPath); for (const file of files) { + // Only consider compiled .js files. Ignore maps, d.ts, etc. if (!file.endsWith(".js")) continue; const fullPath = path.join(groupPath, file); + + // Dynamically import the command module. We treat it as Partial here + // and validate that it actually has the expected shape before using it. const mod = (await import(fullPath)) as Partial; + // Only register modules that provide both `data` and `execute`. + // This prevents half-configured or broken command files from crashing the bot. if (mod.data && mod.execute) { + // The command name is defined in `data` (SlashCommandBuilder). + // We use that as the key in the commands map. client.commands.set(mod.data.name, mod as SlashCommand); } } } -} \ No newline at end of file +} diff --git a/src/services/discord/interactionHandler.ts b/src/services/discord/interactionHandler.ts index 317d9657..2084cd60 100644 --- a/src/services/discord/interactionHandler.ts +++ b/src/services/discord/interactionHandler.ts @@ -1,21 +1,31 @@ -import type { - Interaction, - ChatInputCommandInteraction -} from "discord.js"; +import type { Interaction, ChatInputCommandInteraction } from "discord.js"; import type { CommandClient } from "./commandLoader.js"; +/** + * Handles incoming interactions and dispatches slash commands to their registered executors. + */ export async function handleInteraction( interaction: Interaction, - client: CommandClient + client: CommandClient, ): Promise { + /** + * Ignore any interaction that is not a slash command. + */ if (!interaction.isChatInputCommand()) return; const command = client.commands.get(interaction.commandName); + /** + * If we have no handler for this command, reply to the user and stop. + */ if (!command) { await interaction.reply("Command not found"); return; } + /** + * Execute the command safely. If it throws, log the error and reply with a generic failure message. + * If the interaction already has a response, use editReply instead. + */ try { await command.execute(interaction as ChatInputCommandInteraction); } catch (err) { diff --git a/src/services/summary/llmSummary.ts b/src/services/summary/llmSummary.ts index 3341cbe2..43f42aba 100644 --- a/src/services/summary/llmSummary.ts +++ b/src/services/summary/llmSummary.ts @@ -1,17 +1,30 @@ import OpenAI from "openai"; import { env } from "../../config/env.js"; +/** + * Set client + */ let client: OpenAI | null = null; +/** + * if OpenAPIKey is set use it for client + */ if (env.openAIKey) { client = new OpenAI({ apiKey: env.openAIKey }); } +/** + * Generates an LLM summary of the provided text. + * Falls back to a safe message if no API key is configured. + */ export async function llmSummary(text: string): Promise { if (!client) { return "LLM mode requested but no API key is configured."; } + /** + * Build a prompt instructing the LLM to summarize messages in a clean, neutral format. + */ const prompt = ` You are a Discord channel summarizer. Summarize the following messages into a short readable summary. @@ -20,14 +33,22 @@ Text: ${text} `; + /** + * Send the summary prompt to the gpt-4o-mini model. + */ const response = await client.chat.completions.create({ model: "gpt-4o-mini", - messages: [{ role: "user", content: prompt }] + messages: [{ role: "user", content: prompt }], }); + /** + * Extract the model output, defaulting to a fallback message if no content is returned. + */ const content = - response.choices?.[0]?.message?.content ?? - "LLM returned no content."; + response.choices?.[0]?.message?.content ?? "LLM returned no content."; + /** + * Return the cleaned summary text. + */ return content.trim(); } diff --git a/src/services/summary/localSummary.ts b/src/services/summary/localSummary.ts index 298911ce..bd36648a 100644 --- a/src/services/summary/localSummary.ts +++ b/src/services/summary/localSummary.ts @@ -1,3 +1,6 @@ +/* + * Select the top 5 most frequent meaningful words to highlight in the summary. + */ export function localSummary(text: string): string { const lines = text.split("\n"); const total = lines.length; @@ -6,16 +9,28 @@ export function localSummary(text: string): string { let longest = ""; const keywords: Record = {}; + /* + * Iterate through each message and extract metadata for the summary. + */ for (const line of lines) { + /* + * Separate the username and message content (format: “user: message”). + */ const [user, msg] = line.split(": "); if (user) users.add(user); + /* + * Track the longest message so we can surface it as the detailed example. + */ if (msg && msg.length > longest.length) { longest = msg; } + /* + * Break the message into lowercase words and count how often each appears. + */ if (msg) { - msg.split(/\s+/).forEach(word => { + msg.split(/\s+/).forEach((word) => { const w = word.toLowerCase(); if (!w) return; if (!keywords[w]) keywords[w] = 0; @@ -24,6 +39,9 @@ export function localSummary(text: string): string { } } + /* + * Break the message into lowercase words and count how often each appears. + */ const topWords = Object.entries(keywords) .filter(([k]) => k.length > 3) .sort((a, b) => b[1] - a[1]) @@ -31,6 +49,9 @@ export function localSummary(text: string): string { .map(([w, c]) => `${w} (${c})`) .join(", "); + /* + * Break the messag + */ return ( "Summary of recent messages:\n" + `Messages: ${total}\n` + diff --git a/src/services/summary/summarizer.ts b/src/services/summary/summarizer.ts index b9f7aebb..2c885bd9 100644 --- a/src/services/summary/summarizer.ts +++ b/src/services/summary/summarizer.ts @@ -2,10 +2,15 @@ import { env } from "../../config/env.js"; import { localSummary } from "./localSummary.js"; import { llmSummary } from "./llmSummary.js"; +/* + * Decide which summarization method to use (LLM or local) based on configuration. + */ export async function summarize(text: string): Promise { if (env.summaryMode === "llm") { return llmSummary(text); } - + /* + * Use the lightweight local summarizer when LLM mode is disabled. + */ return localSummary(text); } diff --git a/tsconfig.json b/tsconfig.json index e3eb543c..cb95833f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,4 +17,4 @@ } }, "include": ["src"] -} \ No newline at end of file +} From 0ff48913b9da0a5fbccdc3eed57b3e436cf917da Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 15:24:34 -0500 Subject: [PATCH 02/13] More comment changes --- src/registerCommands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registerCommands.ts b/src/registerCommands.ts index a325bf81..2030f655 100644 --- a/src/registerCommands.ts +++ b/src/registerCommands.ts @@ -4,7 +4,7 @@ import path from "path"; import { env } from "./config/env.js"; /* - * Read all compiled command definitions and prepare them for registration with the Discord API. + * Load all compiled command JSON definitions from dist/commands and prepare them for registration with Discord. */ async function loadCommandData() { const commands: any[] = []; @@ -33,7 +33,7 @@ async function register() { const commands = await loadCommandData(); /* - * Overwrite the guild’s existing slash commands with the updated command list. + * Replace the guild’s previously registered slash commands with the current build output. */ await rest.put(Routes.applicationGuildCommands(env.appId, env.guildId), { body: commands, From e48e8a5df1a9e87b7db4f0ee1e62e5ce6e687346 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 15:25:06 -0500 Subject: [PATCH 03/13] More comment changes --- src/registerCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registerCommands.ts b/src/registerCommands.ts index 2030f655..82ce7439 100644 --- a/src/registerCommands.ts +++ b/src/registerCommands.ts @@ -33,7 +33,7 @@ async function register() { const commands = await loadCommandData(); /* - * Replace the guild’s previously registered slash commands with the current build output. + * Replace all existing guild slash commands with the freshly built definitions. */ await rest.put(Routes.applicationGuildCommands(env.appId, env.guildId), { body: commands, From 5494e9947979a6f0151b6852d869bd5f1d259be1 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 15:28:38 -0500 Subject: [PATCH 04/13] Adding another tweak --- src/registerCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registerCommands.ts b/src/registerCommands.ts index 82ce7439..7ae55734 100644 --- a/src/registerCommands.ts +++ b/src/registerCommands.ts @@ -7,7 +7,7 @@ import { env } from "./config/env.js"; * Load all compiled command JSON definitions from dist/commands and prepare them for registration with Discord. */ async function loadCommandData() { - const commands: any[] = []; + const commands: Record[] = []; // Read built JS commands from dist const basePath = path.join(process.cwd(), "dist/commands"); const groups = fs.readdirSync(basePath); From 616b3826b171509bcec0778d2f6e05d4a57d9872 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:13:20 -0500 Subject: [PATCH 05/13] Adding in new files --- package-lock.json | 18 +------- src/commands/history/history.ts | 75 +++++++++++++++++++++++++++++++++ src/commands/summary/summary.ts | 22 +++++----- 3 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 src/commands/history/history.ts diff --git a/package-lock.json b/package-lock.json index 6a50abde..1d6e40f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,7 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", - "openai": "^4.0.0", - "prettier": "^3.7.4" + "openai": "^4.0.0" }, "devDependencies": { "@types/node": "^24.10.2", @@ -812,21 +811,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, - "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/src/commands/history/history.ts b/src/commands/history/history.ts new file mode 100644 index 00000000..8173379c --- /dev/null +++ b/src/commands/history/history.ts @@ -0,0 +1,75 @@ +import { + SlashCommandBuilder, + AttachmentBuilder, + type ChatInputCommandInteraction, +} from "discord.js"; + +/** + * /history command + * Returns the last N raw messages (no summarization). + * MVP version for chat playback feature (F1). + */ +export const data = new SlashCommandBuilder() + .setName("history") + .setDescription("Show the most recent messages in plain text") + .addIntegerOption((opt) => + opt + .setName("count") + .setDescription("How many messages to fetch") + .setMinValue(5) + .setMaxValue(50), + ); + +export async function execute( + interaction: ChatInputCommandInteraction, +): Promise { + // Use the requested count, or default to 50 messages. + const count = interaction.options.getInteger("count") ?? 50; + + await interaction.deferReply(); + + const messages = await interaction.channel?.messages.fetch({ limit: count }); + if (!messages) { + await interaction.editReply("Could not fetch messages for this channel."); + return; + } + + /** + * Filter out bots so playback only includes real user messages. + * Sort oldest→newest so the playback follows the conversation flow. + */ + const userMessages = messages + .filter((m) => !m.author.bot && m.content) + .sort((a, b) => a.createdTimestamp - b.createdTimestamp); + + /** + * Nothing to show. + */ + if (userMessages.size === 0) { + await interaction.editReply("No history found."); + return; + } + + /** + * Combine messages into a simple “username: content” transcript, one per line. + */ + const text = userMessages + .map((m) => `${m.author.username}: ${m.content}`) + .join("\n"); + + /** + * If the history exceeds Discord’s 2000-character limit, send it as a text file instead of a normal message. + */ + if (text.length > 2000) { + const file = new AttachmentBuilder(Buffer.from(text), { + name: "history.txt", + }); + await interaction.editReply({ + content: "History was too long to display, so I attached it as a file.", + files: [file], + }); + return; + } + + await interaction.editReply(text); +} diff --git a/src/commands/summary/summary.ts b/src/commands/summary/summary.ts index e16d881d..54228dc7 100644 --- a/src/commands/summary/summary.ts +++ b/src/commands/summary/summary.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder, AttachmentBuilder, - type ChatInputCommandInteraction, + type ChatInputCommandInteraction } from "discord.js"; import { summarize } from "../../services/summary/summarizer.js"; @@ -13,12 +13,12 @@ import { summarize } from "../../services/summary/summarizer.js"; export const data = new SlashCommandBuilder() .setName("summary") .setDescription("Summarize recent messages") - .addIntegerOption((opt) => + .addIntegerOption(opt => opt .setName("count") .setDescription("How many messages to fetch") .setMinValue(10) - .setMaxValue(100), + .setMaxValue(100) ); /** @@ -26,7 +26,7 @@ export const data = new SlashCommandBuilder() */ export async function execute( - interaction: ChatInputCommandInteraction, + interaction: ChatInputCommandInteraction ): Promise { const count = interaction.options.getInteger("count") ?? 50; @@ -42,15 +42,15 @@ export async function execute( return; } - /** + /** * Filter out bots so summaries don’t include automated noise. * Sort oldest→newest so the summary respects conversation order. */ const userMessages = messages - .filter((m) => !m.author.bot && m.content) + .filter(m => !m.author.bot && m.content) .sort((a, b) => a.createdTimestamp - b.createdTimestamp); - /** + /** * If no non-bot messages remain after filtering, tell the user there is nothing to summarize. */ if (userMessages.size === 0) { @@ -58,11 +58,11 @@ export async function execute( return; } - /** + /** * Combine messages into a simple “username: content” transcript, one per line. */ const text = userMessages - .map((m) => `${m.author.username}: ${m.content}`) + .map(m => `${m.author.username}: ${m.content}`) .join("\n"); const output = await summarize(text); @@ -72,11 +72,11 @@ export async function execute( */ if (output.length > 2000) { const file = new AttachmentBuilder(Buffer.from(output), { - name: "summary.txt", + name: "summary.txt" }); await interaction.editReply({ content: "Summary was too long. Uploaded as file.", - files: [file], + files: [file] }); return; } From 93b852928ce4fb43255574c5cc48da8e12678961 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:15:35 -0500 Subject: [PATCH 06/13] Updating file tree --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 3275f6d7..c33de7ae 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,9 @@ OmegaBot is online ## Project Structure +
+📁 Click to expand file structure + ``` . ├── .github @@ -115,6 +118,8 @@ OmegaBot is online │ ├── commands │ │ ├── general │ │ │ └── ping.ts +│ │ ├── history +│ │ │ └── history.ts │ │ └── summary │ │ └── summary.ts │ ├── config @@ -131,6 +136,8 @@ OmegaBot is online └── tsconfig.json ``` +
+ --- ## Extending OmegaBot From a5fd5eeb36d7258f401b8e54b87e3ce2ccde3872 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:34:43 -0500 Subject: [PATCH 07/13] Fixing this up --- .../{FollowTheFlow.yml => OmegaBot.yml} | 15 +- README.md | 3 +- eslint.config.ts | 46 + package-lock.json | 1460 +++++++++++++++-- package.json | 11 +- src/commands/history/history.ts | 2 +- src/commands/summary/summary.ts | 22 +- src/registerCommands.ts | 48 +- 8 files changed, 1422 insertions(+), 185 deletions(-) rename .github/workflows/{FollowTheFlow.yml => OmegaBot.yml} (72%) create mode 100644 eslint.config.ts diff --git a/.github/workflows/FollowTheFlow.yml b/.github/workflows/OmegaBot.yml similarity index 72% rename from .github/workflows/FollowTheFlow.yml rename to .github/workflows/OmegaBot.yml index 58ce67aa..17617112 100644 --- a/.github/workflows/FollowTheFlow.yml +++ b/.github/workflows/OmegaBot.yml @@ -1,5 +1,5 @@ # .github/workflows/OmegaBot.yml -name: OmegaBot +name: 🤖 OmegaBot on: pull_request: @@ -12,7 +12,7 @@ concurrency: jobs: lint-typecheck: - name: 🎨 Prettier · ✨ ESLint · 🛠️ TypeScript + name: runs-on: ubuntu-latest defaults: @@ -32,9 +32,12 @@ jobs: - name: 📦 Install dependencies run: npm ci + + - name: 🧹 ESLint + run: npm run lint - - name: 📦 Install dependencies - run: npm ci + - name: 🧪 TypeScript typecheck + run: npm run typecheck - - name: 🔧 Build App (Vite) - run: npm run build + - name: 🎨 Prettier check + run: npm run format:check diff --git a/README.md b/README.md index c33de7ae..f346777e 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ OmegaBot is online │ │ └── question_discussion.yml │ ├── pull_request_template.md │ └── workflows -│ └── FollowTheFlow.yml +│ └── OmegaBot.yml ├── .gitignore ├── .husky │ ├── pre-commit @@ -107,6 +107,7 @@ OmegaBot is online │ ├── banner.png │ └── omegabot.png ├── CONTRIBUTORS.md +├── eslint.config.ts ├── LICENSE ├── package-lock.json ├── package.json diff --git a/eslint.config.ts b/eslint.config.ts new file mode 100644 index 00000000..f2cf92a5 --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,46 @@ +// eslint.config.ts +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default [ + // Ignore build output and dependencies + { + ignores: ["dist", "node_modules", "coverage"], + }, + + // Base JS rules + js.configs.recommended, + + // TypeScript base rules (non type-aware: no parserOptions.project) + ...tseslint.configs.recommended, + + { + files: ["**/*.ts"], + + languageOptions: { + ecmaVersion: 2020, + sourceType: "module", + globals: { + ...globals.node, + ...globals.es2020, + }, + }, + + plugins: { + "@typescript-eslint": tseslint.plugin, + }, + + rules: { + // Let @typescript-eslint handle unused vars and allow _ + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "no-unused-vars": "off", + }, + }, +]; diff --git a/package-lock.json b/package-lock.json index 1d6e40f7..be5eeb4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,27 +10,19 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", - "openai": "^4.0.0" + "jiti": "^2.6.1", + "openai": "^4.0.0", + "typescript-eslint": "^8.49.0" }, "devDependencies": { + "@eslint/js": "^9.12.0", "@types/node": "^24.10.2", - "ts-node": "^10.9.2", + "eslint": "^9.12.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.3.3", "typescript": "^5.9.3" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@discordjs/builders": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.13.1.tgz", @@ -161,32 +153,186 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "license": "Apache-2.0", "engines": { - "node": ">=6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@sapphire/async-queue": { @@ -222,32 +368,16 @@ "npm": ">=7.0.0" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, "node_modules/@types/node": { @@ -278,6 +408,249 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz", + "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/type-utils": "8.49.0", + "@typescript-eslint/utils": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.49.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz", + "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.49.0.tgz", + "integrity": "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.49.0", + "@typescript-eslint/types": "^8.49.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz", + "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.49.0.tgz", + "integrity": "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz", + "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", + "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz", + "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.49.0", + "@typescript-eslint/tsconfig-utils": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz", + "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz", + "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.49.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@vladfrangu/async_event_emitter": { "version": "2.4.7", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz", @@ -304,7 +677,6 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -313,17 +685,13 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/agentkeepalive": { @@ -338,12 +706,42 @@ "node": ">= 8.0.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/asynckit": { "version": "0.4.0", @@ -351,6 +749,22 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -364,6 +778,49 @@ "node": ">= 0.4" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -376,11 +833,47 @@ "node": ">= 0.8" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, "node_modules/delayed-stream": { @@ -392,16 +885,6 @@ "node": ">=0.4.0" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/discord-api-types": { "version": "0.38.36", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.36.tgz", @@ -509,6 +992,177 @@ "node": ">= 0.4" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -524,6 +1178,82 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "license": "ISC" + }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", @@ -605,6 +1335,30 @@ "node": ">= 0.4" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -617,6 +1371,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -665,12 +1428,155 @@ "ms": "^2.0.0" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "license": "MIT" + }, "node_modules/lodash.snakecase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", @@ -683,13 +1589,6 @@ "integrity": "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==", "license": "MIT" }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -720,12 +1619,30 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "license": "MIT" + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -811,73 +1728,257 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", "license": "MIT" }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -887,6 +1988,29 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.49.0.tgz", + "integrity": "sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.49.0", + "@typescript-eslint/parser": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/undici": { "version": "6.21.3", "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", @@ -902,12 +2026,14 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } }, "node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", @@ -934,6 +2060,30 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", @@ -955,14 +2105,16 @@ } } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index 18334873..9c0938bf 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "dev": "npm run build && node dist/bot.js", "register": "npm run build && node dist/registerCommands.js", "format": "prettier . --write", - "format:check": "prettier . --check" + "format:check": "prettier . --check", + "lint": "eslint . --ext .ts --max-warnings=0", + "typecheck": "tsc --noEmit" }, "dependencies": { "discord.js": "^14.14.1", @@ -16,7 +18,10 @@ }, "devDependencies": { "@types/node": "^24.10.2", - "ts-node": "^10.9.2", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "eslint": "^9.12.0", + "@eslint/js": "^9.12.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.3.3" } } diff --git a/src/commands/history/history.ts b/src/commands/history/history.ts index 8173379c..58b94b4b 100644 --- a/src/commands/history/history.ts +++ b/src/commands/history/history.ts @@ -71,5 +71,5 @@ export async function execute( return; } - await interaction.editReply(text); + await interaction.editReply(text); } diff --git a/src/commands/summary/summary.ts b/src/commands/summary/summary.ts index 54228dc7..e16d881d 100644 --- a/src/commands/summary/summary.ts +++ b/src/commands/summary/summary.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder, AttachmentBuilder, - type ChatInputCommandInteraction + type ChatInputCommandInteraction, } from "discord.js"; import { summarize } from "../../services/summary/summarizer.js"; @@ -13,12 +13,12 @@ import { summarize } from "../../services/summary/summarizer.js"; export const data = new SlashCommandBuilder() .setName("summary") .setDescription("Summarize recent messages") - .addIntegerOption(opt => + .addIntegerOption((opt) => opt .setName("count") .setDescription("How many messages to fetch") .setMinValue(10) - .setMaxValue(100) + .setMaxValue(100), ); /** @@ -26,7 +26,7 @@ export const data = new SlashCommandBuilder() */ export async function execute( - interaction: ChatInputCommandInteraction + interaction: ChatInputCommandInteraction, ): Promise { const count = interaction.options.getInteger("count") ?? 50; @@ -42,15 +42,15 @@ export async function execute( return; } - /** + /** * Filter out bots so summaries don’t include automated noise. * Sort oldest→newest so the summary respects conversation order. */ const userMessages = messages - .filter(m => !m.author.bot && m.content) + .filter((m) => !m.author.bot && m.content) .sort((a, b) => a.createdTimestamp - b.createdTimestamp); - /** + /** * If no non-bot messages remain after filtering, tell the user there is nothing to summarize. */ if (userMessages.size === 0) { @@ -58,11 +58,11 @@ export async function execute( return; } - /** + /** * Combine messages into a simple “username: content” transcript, one per line. */ const text = userMessages - .map(m => `${m.author.username}: ${m.content}`) + .map((m) => `${m.author.username}: ${m.content}`) .join("\n"); const output = await summarize(text); @@ -72,11 +72,11 @@ export async function execute( */ if (output.length > 2000) { const file = new AttachmentBuilder(Buffer.from(output), { - name: "summary.txt" + name: "summary.txt", }); await interaction.editReply({ content: "Summary was too long. Uploaded as file.", - files: [file] + files: [file], }); return; } diff --git a/src/registerCommands.ts b/src/registerCommands.ts index 7ae55734..49fe0b7a 100644 --- a/src/registerCommands.ts +++ b/src/registerCommands.ts @@ -2,48 +2,78 @@ import { REST, Routes } from "discord.js"; import fs from "fs"; import path from "path"; import { env } from "./config/env.js"; +import type { RESTPostAPIChatInputApplicationCommandsJSONBody } from "discord-api-types/v10"; /* - * Load all compiled command JSON definitions from dist/commands and prepare them for registration with Discord. + * Read all compiled command definitions and prepare them for registration + * with the Discord API. + * + * This function: + * - walks through dist/commands/ + * - loads every compiled .js command file + * - extracts each command’s JSON definition + * - returns them in an array for API registration */ async function loadCommandData() { - const commands: Record[] = []; - // Read built JS commands from dist + const commands: RESTPostAPIChatInputApplicationCommandsJSONBody[] = []; + + // Commands are loaded from compiled JS in dist/ const basePath = path.join(process.cwd(), "dist/commands"); const groups = fs.readdirSync(basePath); for (const group of groups) { const groupPath = path.join(basePath, group); + + // Skip stray files — only process folders if (!fs.statSync(groupPath).isDirectory()) continue; const files = fs.readdirSync(groupPath); + for (const file of files) { + // Only load compiled command files if (!file.endsWith(".js")) continue; - const mod = await import(path.join(groupPath, file)); - if (mod.data) commands.push(mod.data.toJSON()); + + const modulePath = path.join(groupPath, file); + const mod = await import(modulePath); + + /* + * Each command module exports `data`, + * which contains a SlashCommandBuilder. + * Convert that builder to JSON and push it into the list. + */ + if (mod.data) { + commands.push(mod.data.toJSON()); + } } } + return commands; } + /* - * Register all slash commands with Discord for the configured application and guild. + * Register all slash commands with Discord for the configured application & guild. + * + * This uses REST.put() to completely replace the current slash-command set + * for the guild. This makes command updates instant for testing. */ async function register() { const rest = new REST({ version: "10" }).setToken(env.token); + const commands = await loadCommandData(); /* - * Replace all existing guild slash commands with the freshly built definitions. + * Overwrite the guild’s existing slash commands with the updated list. + * This is preferred during development because changes propagate immediately. */ await rest.put(Routes.applicationGuildCommands(env.appId, env.guildId), { body: commands, }); - console.log("Commands registered"); + console.log("Commands registered."); } /* - * Report failures clearly and exit with a non-zero status. + * Wrapper so errors throw clearly and stop the script immediately. */ register().catch((err) => { console.error("Failed to register commands:", err); From 4ab6123ea47a84faec714d83179bc46f11584a30 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:35:14 -0500 Subject: [PATCH 08/13] Adding in more changes' --- .github/workflows/OmegaBot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/OmegaBot.yml b/.github/workflows/OmegaBot.yml index 17617112..7a118ca1 100644 --- a/.github/workflows/OmegaBot.yml +++ b/.github/workflows/OmegaBot.yml @@ -12,7 +12,7 @@ concurrency: jobs: lint-typecheck: - name: + name: 🤖 OmegaBot runs-on: ubuntu-latest defaults: From d7fb06e563b9ec7829a92f9bdeba02067ca3dff9 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:40:58 -0500 Subject: [PATCH 09/13] Fixing GitHUb action --- .github/workflows/OmegaBot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/OmegaBot.yml b/.github/workflows/OmegaBot.yml index 7a118ca1..b7a7c3bb 100644 --- a/.github/workflows/OmegaBot.yml +++ b/.github/workflows/OmegaBot.yml @@ -1,5 +1,5 @@ # .github/workflows/OmegaBot.yml -name: 🤖 OmegaBot +name: 🔍 Lint · Typecheck · Format on: pull_request: From a64ffd561ce2ad53b57792f219efa7801ed2d2ec Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:43:18 -0500 Subject: [PATCH 10/13] Fixing one more thing --- .github/workflows/OmegaBot.yml | 2 +- package.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/OmegaBot.yml b/.github/workflows/OmegaBot.yml index b7a7c3bb..a792f594 100644 --- a/.github/workflows/OmegaBot.yml +++ b/.github/workflows/OmegaBot.yml @@ -32,7 +32,7 @@ jobs: - name: 📦 Install dependencies run: npm ci - + - name: 🧹 ESLint run: npm run lint diff --git a/package.json b/package.json index 9c0938bf..4991e711 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "eslint": "^9.12.0", "@eslint/js": "^9.12.0", "eslint-config-prettier": "^9.1.0", - "prettier": "^3.3.3" + "prettier": "^3.3.3", + "globals": "^15.11.0", + "typescript-eslint": "^8.0.0" } } From d9d60d1a7ff20773b0d6fd8d95b261aa513a502b Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:48:03 -0500 Subject: [PATCH 11/13] Updating package.json --- package-lock.json | 133 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index be5eeb4c..368625f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,17 +10,17 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", - "jiti": "^2.6.1", - "openai": "^4.0.0", - "typescript-eslint": "^8.49.0" + "openai": "^4.0.0" }, "devDependencies": { "@eslint/js": "^9.12.0", "@types/node": "^24.10.2", "eslint": "^9.12.0", "eslint-config-prettier": "^9.1.0", + "globals": "^15.11.0", "prettier": "^3.3.3", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "typescript-eslint": "^8.0.0" } }, "node_modules/@discordjs/builders": { @@ -157,6 +157,7 @@ "version": "4.9.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -175,6 +176,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -187,6 +189,7 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -196,6 +199,7 @@ "version": "0.21.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", @@ -210,6 +214,7 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0" @@ -222,6 +227,7 @@ "version": "0.17.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -234,6 +240,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -253,10 +260,24 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { "version": "9.39.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -269,6 +290,7 @@ "version": "2.1.7", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -278,6 +300,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0", @@ -291,6 +314,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -300,6 +324,7 @@ "version": "0.16.7", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -313,6 +338,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -326,6 +352,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -372,12 +399,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, "license": "MIT" }, "node_modules/@types/node": { @@ -412,6 +441,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz", "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==", + "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", @@ -440,6 +470,7 @@ "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -449,6 +480,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz", "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/scope-manager": "8.49.0", @@ -473,6 +505,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.49.0.tgz", "integrity": "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.49.0", @@ -494,6 +527,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz", "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.49.0", @@ -511,6 +545,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.49.0.tgz", "integrity": "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -527,6 +562,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz", "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.49.0", @@ -551,6 +587,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", + "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -564,6 +601,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz", "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/project-service": "8.49.0", @@ -591,6 +629,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -600,6 +639,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -615,6 +655,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz", "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==", + "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", @@ -638,6 +679,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz", "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.49.0", @@ -677,6 +719,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -689,6 +732,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -710,6 +754,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -726,6 +771,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -741,6 +787,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/asynckit": { @@ -753,12 +800,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -782,6 +831,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -791,6 +841,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -807,6 +858,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -819,6 +871,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -837,12 +890,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -857,6 +912,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -874,6 +930,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, "license": "MIT" }, "node_modules/delayed-stream": { @@ -996,6 +1053,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -1008,6 +1066,7 @@ "version": "9.39.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", @@ -1080,6 +1139,7 @@ "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -1096,6 +1156,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1108,6 +1169,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -1125,6 +1187,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -1137,6 +1200,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -1149,6 +1213,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -1158,6 +1223,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -1182,18 +1248,21 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, "license": "MIT" }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -1211,6 +1280,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -1223,6 +1293,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -1239,6 +1310,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -1252,6 +1324,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, "license": "ISC" }, "node_modules/form-data": { @@ -1339,6 +1412,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -1348,9 +1422,10 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -1375,6 +1450,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1432,6 +1508,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -1441,6 +1518,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -1457,6 +1535,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -1466,6 +1545,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -1475,6 +1555,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -1487,13 +1568,17 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -1502,6 +1587,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -1514,24 +1600,28 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, "license": "MIT" }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -1541,6 +1631,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -1554,6 +1645,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -1575,6 +1667,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash.snakecase": { @@ -1623,6 +1716,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -1641,6 +1735,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, "license": "MIT" }, "node_modules/node-domexception": { @@ -1732,6 +1827,7 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -1749,6 +1845,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -1764,6 +1861,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -1779,6 +1877,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -1791,6 +1890,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1800,6 +1900,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1809,6 +1910,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1821,6 +1923,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -1846,6 +1949,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1855,6 +1959,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -1864,6 +1969,7 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1876,6 +1982,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -1888,6 +1995,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1897,6 +2005,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1909,6 +2018,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -1921,6 +2031,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -1943,6 +2054,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18.12" @@ -1967,6 +2079,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -1979,6 +2092,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -1992,6 +2106,7 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.49.0.tgz", "integrity": "sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==", + "dev": true, "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "8.49.0", @@ -2030,6 +2145,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -2064,6 +2180,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -2079,6 +2196,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2109,6 +2227,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" From 0301d30ba4b405c8741edb46a153182526bda58f Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 16:52:22 -0500 Subject: [PATCH 12/13] Adding in files --- src/services/summary/localSummary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/summary/localSummary.ts b/src/services/summary/localSummary.ts index bd36648a..f59e7cb5 100644 --- a/src/services/summary/localSummary.ts +++ b/src/services/summary/localSummary.ts @@ -50,7 +50,7 @@ export function localSummary(text: string): string { .join(", "); /* - * Break the messag + * Produce the final formatted summary string returned to the user. */ return ( "Summary of recent messages:\n" + From 2c25dc7c6b6503a1e5b90e919d30dc3b447d78e4 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Thu, 11 Dec 2025 17:27:28 -0500 Subject: [PATCH 13/13] Adding in .env.exmple file --- .env.example | 9 ++ README.md | 3 + package-lock.json | 16 +++ package.json | 7 +- scripts copy/precheck.sh | 72 ++++++++++ src/commands/summary/summary.ts | 188 +++++++++++++++++++-------- src/services/summary/localSummary.ts | 32 +++-- 7 files changed, 259 insertions(+), 68 deletions(-) create mode 100644 .env.example create mode 100755 scripts copy/precheck.sh diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..d8334b57 --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +DISCORD_TOKEN=your-bot-token-here +DISCORD_APP_ID=your-application-id-here +DISCORD_GUILD_ID=your-test-guild-id-here + +# Summary mode: use "llm" to enable OpenAI, or anything else for local summary +SUMMARY_MODE=local + +# Only required if SUMMARY_MODE=llm +OPENAI_API_KEY=your-openai-key-if-needed \ No newline at end of file diff --git a/README.md b/README.md index f346777e..1a840d58 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ OmegaBot is online ``` . +├── .env.example ├── .github │ ├── ISSUE_TEMPLATE │ │ ├── bug.yml @@ -114,6 +115,8 @@ OmegaBot is online ├── README.md ├── scripts │ └── precheck.sh +├── scripts copy +│ └── precheck.sh ├── src │ ├── bot.ts │ ├── commands diff --git a/package-lock.json b/package-lock.json index 368625f6..81347dad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", + "husky": "^9.1.7", "openai": "^4.0.0" }, "devDependencies": { @@ -1504,6 +1505,21 @@ "ms": "^2.0.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", diff --git a/package.json b/package.json index 4991e711..2882b7ca 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,17 @@ "dependencies": { "discord.js": "^14.14.1", "dotenv": "^16.4.5", + "husky": "^9.1.7", "openai": "^4.0.0" }, "devDependencies": { + "@eslint/js": "^9.12.0", "@types/node": "^24.10.2", - "typescript": "^5.9.3", "eslint": "^9.12.0", - "@eslint/js": "^9.12.0", "eslint-config-prettier": "^9.1.0", - "prettier": "^3.3.3", "globals": "^15.11.0", + "prettier": "^3.3.3", + "typescript": "^5.9.3", "typescript-eslint": "^8.0.0" } } diff --git a/scripts copy/precheck.sh b/scripts copy/precheck.sh new file mode 100755 index 00000000..52762a11 --- /dev/null +++ b/scripts copy/precheck.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Abort on error, unset vars, or pipeline failures +set -euo pipefail + +# Repo root +cd "$(git rev-parse --show-toplevel)" + +# Optional: allow skipping with tag +LAST_COMMIT_MSG="$(git log -1 --pretty=%B || true)" +if echo "$LAST_COMMIT_MSG" | grep -qi '\[skip-precheck\]'; then + echo "⚠️ Skipping pre-push checks due to [skip-precheck] tag." + exit 0 +fi + +echo "🔍 Running Pre-Push Quality Gate..." + +# -------- Empty file check (same behavior you had), scoped to changes -------- +echo "📂 Checking for empty files..." +UPSTREAM="$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || true)" +if [ -n "$UPSTREAM" ]; then + BASE="$(git merge-base HEAD "$UPSTREAM")" + FILES_TO_CHECK="$(git diff --name-only --diff-filter=AM "$BASE"..HEAD)" +else + echo "⚠️ No upstream configured — scanning entire repo..." + FILES_TO_CHECK="$(git ls-files)" +fi + +ALLOW_EMPTY_REGEX='(^|/)\.gitkeep$|(^|/)\.keep$' +EMPTY_FILES="" +while IFS= read -r file; do + [ -z "${file:-}" ] && continue + if echo "$file" | grep -Eq "$ALLOW_EMPTY_REGEX"; then + continue + fi + if [ -f "$file" ] && [ ! -s "$file" ]; then + EMPTY_FILES+="$file"$'\n' + fi +done <<< "$FILES_TO_CHECK" + +if [ -n "$EMPTY_FILES" ]; then + echo -e "🛑 Empty files detected:\n$EMPTY_FILES\nPlease remove or fill them." + exit 1 +fi +echo "✅ No empty files found." + +# -------- Prettier (check → auto-fix & stop) -------- +echo "🎨 Prettier — check" +if ! npx --no-install prettier --config .prettierrc.yml --ignore-path .prettierignore --check .; then + echo "💾 Prettier — writing fixes..." + npx --no-install prettier --config .prettierrc.yml --ignore-path .prettierignore --write . + git add -A + git commit -m "style: auto-format with Prettier [skip-precheck]" + echo "🛑 Prettier fixed files and committed. Push again." + exit 1 +fi +echo "✅ Prettier passed." + +# -------- ESLint (cached src) -------- +echo "🧪 ESLint (cached, src)..." +npx --no-install eslint src --ext .js,.jsx,.ts,.tsx --cache + +# -------- ESLint (strict, repo root) -------- +echo "✨ ESLint (strict)..." +npx --no-install eslint . --max-warnings=0 +echo "✅ ESLint passed." + +# -------- TypeScript -------- +echo "🛠️ TypeScript — type check" +npx --no-install tsc --noEmit --pretty false +echo "✅ TypeScript passed." + +echo "🚀 All checks passed. Ready to push!" \ No newline at end of file diff --git a/src/commands/summary/summary.ts b/src/commands/summary/summary.ts index 3e20de77..c1490a2d 100644 --- a/src/commands/summary/summary.ts +++ b/src/commands/summary/summary.ts @@ -1,18 +1,18 @@ import { SlashCommandBuilder, AttachmentBuilder, + MessageFlags, type ChatInputCommandInteraction, } from "discord.js"; import { summarize } from "../../services/summary/summarizer.js"; /** * Defines the /summary command. - * Used to summarize the chats. + * Summarizes recent messages from the current channel and sends the result via DM. */ - export const data = new SlashCommandBuilder() .setName("summary") - .setDescription("Summarize recent messages") + .setDescription("Summarize recent messages and DM it to you") .addIntegerOption((opt) => opt .setName("count") @@ -22,69 +22,145 @@ export const data = new SlashCommandBuilder() ); /** - * Caps at 50 lines by default + * Handler for the /summary command. + * + * Flow: + * 1. Defer an ephemeral reply so the user sees “working…” without cluttering the channel. + * 2. Validate the channel can provide messages. + * 3. Fetch the last N messages, filter out bots and empty content. + * 4. Build a plain-text transcript. + * 5. Run the transcript through the summarizer. + * 6. Try to DM the summary to the user (text or file). + * 7. Handle and report errors gracefully. */ - export async function execute( interaction: ChatInputCommandInteraction, ): Promise { + // Use the requested count or default to 50 messages. const count = interaction.options.getInteger("count") ?? 50; try { - // FIXED: Use flags instead of ephemeral: true + /** + * Use flags instead of the deprecated `ephemeral: true`. + * This keeps the response visible only to the user while work happens. + */ await interaction.deferReply({ flags: MessageFlags.Ephemeral }); - const messages = await interaction.channel?.messages.fetch({ limit: count }); - /** - * Guard: if we could not fetch messages (no channel or API issue), - * tell the user and stop instead of throwing later. - */ - if (!messages) { - await interaction.editReply("Could not fetch messages for this channel."); - return; - } + /** + * Guard: make sure the interaction channel supports text messages. + * Some interaction contexts (like certain system channels) cannot be summarized. + */ + if (!interaction.channel || !interaction.channel.isTextBased()) { + await interaction.editReply( + "This channel does not support summarizing messages.", + ); + return; + } - /** - * Filter out bots so summaries don’t include automated noise. - * Sort oldest→newest so the summary respects conversation order. - */ - const userMessages = messages - .filter((m) => !m.author.bot && m.content) - .sort((a, b) => a.createdTimestamp - b.createdTimestamp); - - /** - * If no non-bot messages remain after filtering, tell the user there is nothing to summarize. - */ - if (userMessages.size === 0) { - await interaction.editReply("No usable messages found to summarize."); - return; - } + // Fetch the most recent messages up to the requested limit. + const messages = await interaction.channel.messages.fetch({ limit: count }); - /** - * Combine messages into a simple “username: content” transcript, one per line. - */ - const text = userMessages - .map((m) => `${m.author.username}: ${m.content}`) - .join("\n"); - - const output = await summarize(text); - - /** - * If the summary exceeds Discord’s 2000-character limit, send it as a text file instead of a normal message. - */ - if (output.length > 2000) { - const file = new AttachmentBuilder(Buffer.from(output), { - name: "summary.txt", - }); - await interaction.editReply({ - content: "Summary was too long. Uploaded as file.", - files: [file], - }); - return; - } + // Nothing in the channel at all. + if (messages.size === 0) { + await interaction.editReply("No messages found to summarize."); + return; + } + + /** + * Filter out bot messages and anything without content, + * then sort oldest → newest so the transcript reads in conversation order. + */ + const userMessages = messages + .filter((m) => !m.author.bot && m.content) + .sort((a, b) => a.createdTimestamp - b.createdTimestamp); + + // If everything filtered out (all bots or empty content), there is nothing useful to summarize. + if (userMessages.size === 0) { + await interaction.editReply("No usable messages found to summarize."); + return; + } + + /** + * Build a simple “username: content” transcript that the summarizer can consume. + */ + const text = userMessages + .map((m) => `${m.author.username}: ${m.content}`) + .join("\n"); - /** - * Edit the deferred reply with the final summary text. - */ - await interaction.editReply(output); + // Generate the summary using either local or LLM mode, depending on configuration. + const output = await summarize(text); + + // Defensive guard: handle a blank or missing summary result. + if (!output || output.trim().length === 0) { + await interaction.editReply("Summary came back empty."); + return; + } + + /** + * DM-only delivery mode: + * If the summary is too long for a normal Discord message, send it as a file attachment instead. + */ + if (output.length > 2000) { + const file = new AttachmentBuilder(Buffer.from(output, "utf8"), { + name: "summary.txt", + }); + + try { + // Attempt to DM the file to the user. + await interaction.user.send({ + content: "Here is your summary (too long to send as a message):", + files: [file], + }); + + // Confirm in the ephemeral reply that the summary was sent. + await interaction.editReply("Summary sent to your DMs."); + } catch (err) { + console.error("[summary] DM file send failed", err); + await interaction.editReply( + "I generated the summary, but your DMs appear to be closed.", + ); + } + + return; + } + + /** + * Normal-sized summary: + * Send it as a plain DM message, then confirm in the ephemeral reply. + */ + try { + await interaction.user.send(output); + await interaction.editReply("Summary sent to your DMs."); + } catch (err) { + console.error("[summary] DM text send failed", err); + await interaction.editReply( + "I generated the summary, but could not DM you. Your DMs may be closed.", + ); + } + } catch (err) { + /** + * Top-level catch: if anything in the summarization pipeline fails, + * log the error and try to send a generic failure message back to the user. + */ + console.error("[summary] Summary generation failed", err); + + try { + if (interaction.replied || interaction.deferred) { + await interaction.editReply( + "Something went wrong while generating the summary.", + ); + } else { + await interaction.reply({ + content: "Something went wrong while generating the summary.", + flags: MessageFlags.Ephemeral, + }); + } + } catch (replyErr) { + // Final fallback if even the error reply fails. + console.error( + "[summary] Failed to send fallback error message", + replyErr, + ); + } + } } diff --git a/src/services/summary/localSummary.ts b/src/services/summary/localSummary.ts index b87af1c4..0f44f4c0 100644 --- a/src/services/summary/localSummary.ts +++ b/src/services/summary/localSummary.ts @@ -1,22 +1,30 @@ /* - * Select the top 5 most frequent meaningful words to highlight in the summary. + * Produce a simple heuristic summary of recent messages by counting: + * - total messages + * - unique participants + * - frequent words + * - the longest (most detailed) message */ export function localSummary(text: string): string { const lines = text.split("\n"); + const total = lines.length; const users = new Set(); let longest = ""; const keywords: Record = {}; /* - * Iterate through each message and extract metadata for the summary. + * Iterate through each line and extract metadata for the summary. + * Expected format per line: "username: message text" */ for (const line of lines) { /* - * Separate the username and message content (format: “user: message”). + * Separate the username and message content. */ const [user, msg] = line.split(": "); - if (user) users.add(user); + if (user) { + users.add(user); + } /* * Track the longest message so we can surface it as the detailed example. @@ -32,14 +40,17 @@ export function localSummary(text: string): string { msg.split(/\s+/).forEach((word) => { const w = word.toLowerCase(); if (!w) return; - if (!keywords[w]) keywords[w] = 0; + if (!keywords[w]) { + keywords[w] = 0; + } keywords[w]++; }); } } /* - * Break the message into lowercase words and count how often each appears. + * Select the top 5 most frequent meaningful words to highlight in the summary. + * We ignore very short tokens (length <= 3) to skip things like "the", "and". */ const topWords = Object.entries(keywords) .filter(([k]) => k.length > 3) @@ -52,7 +63,10 @@ export function localSummary(text: string): string { * Produce the final formatted summary string returned to the user. */ return ( - "Recent conversation (oldest to newest):\n\n" + - numbered + "Summary of recent messages:\n" + + `Messages: ${total}\n` + + `Participants: ${users.size}\n` + + `Top words: ${topWords || "none"}\n\n` + + `Most detailed message:\n${longest}` ); -} \ No newline at end of file +}