linted
This commit is contained in:
parent
8231b5a105
commit
601e5a703f
6
.eslintignore
Normal file
6
.eslintignore
Normal file
@ -0,0 +1,6 @@
|
||||
node_modules/
|
||||
logs/
|
||||
images/
|
||||
dist/
|
||||
coverage/
|
||||
*.min.js
|
||||
67
.eslintrc.json
Normal file
67
.eslintrc.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es2022": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:import/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"import"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [
|
||||
".js",
|
||||
".mjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
// Error prevention
|
||||
"no-const-assign": "error",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-unreachable": "error",
|
||||
"valid-typeof": "error",
|
||||
|
||||
// Best practices
|
||||
"eqeqeq": "error",
|
||||
"no-eval": "error",
|
||||
"no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
|
||||
"no-var": "error",
|
||||
"prefer-const": "error",
|
||||
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||
|
||||
// Style
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "always"],
|
||||
"no-multiple-empty-lines": ["error", { "max": 1 }],
|
||||
"no-trailing-spaces": "error",
|
||||
"eol-last": "error",
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
|
||||
// Object and array formatting
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
"comma-dangle": ["error", "never"],
|
||||
|
||||
// Import/Export
|
||||
"import/no-duplicates": "error",
|
||||
"import/order": ["error", {
|
||||
"groups": ["builtin", "external", "internal", "parent", "sibling", "index"],
|
||||
"newlines-between": "always",
|
||||
"alphabetize": { "order": "asc" }
|
||||
}]
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
|
||||
import { CODES } from '../_src/ansiColors.js';
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } from 'discord.js';
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } from 'discord.js';
|
||||
|
||||
/**
|
||||
* botUtils module - provides administrative bot control commands
|
||||
@ -53,7 +53,7 @@ export const commands = [
|
||||
},
|
||||
/**
|
||||
* Slash command `/status` (Administrator only):
|
||||
* Shows this bot client’s status including CPU, memory, environment,
|
||||
* Shows this bot client's status including CPU, memory, environment,
|
||||
* uptime, module list, and entity counts. Optionally displays Git info
|
||||
* (Git Reference and Git Status) when the gitUtils module is loaded.
|
||||
* @param {import('discord.js').CommandInteraction} interaction
|
||||
@ -158,6 +158,10 @@ export const commands = [
|
||||
];
|
||||
|
||||
// Module loaded logging
|
||||
export async function init(client, clientConfig) {
|
||||
client.logger.info('[module:botUtils] Module loaded');
|
||||
export async function init(_client, _clientConfig) {
|
||||
_client.logger.info('[module:botUtils] Module loaded');
|
||||
}
|
||||
|
||||
export async function handleInteractionCreate(_client, _clientConfig, _interaction) {
|
||||
// ... existing code ...
|
||||
}
|
||||
@ -78,7 +78,6 @@ export const init = async (client, config) => {
|
||||
// Used as a prefix before any line that runs within a loop.
|
||||
const bullet = '>';
|
||||
|
||||
|
||||
// === OpenAI Interaction ===
|
||||
// Chat completion via OpenAI with provided instructions.
|
||||
async function ai(prompt = '') {
|
||||
@ -86,17 +85,17 @@ export const init = async (client, config) => {
|
||||
debug(`**AI Prompt**: ${prompt}`);
|
||||
|
||||
// Read instructions.
|
||||
let openAIInstructions = fs.readFileSync(openAIInstructionsFile, 'utf8');
|
||||
const openAIInstructions = fs.readFileSync(openAIInstructionsFile, 'utf8');
|
||||
const unmention = /<@(\w+)>/g;
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-4o-mini',
|
||||
messages: [
|
||||
{role: 'user', content: `${prompt.replace(unmention, '$1')}`},
|
||||
{role: 'system', content: `${openAIInstructions}`},
|
||||
],
|
||||
{ role: 'user', content: `${prompt.replace(unmention, '$1')}` },
|
||||
{ role: 'system', content: `${openAIInstructions}` }
|
||||
]
|
||||
});
|
||||
let chunk = completion.choices[0]?.message?.content;
|
||||
if (chunk != '') {
|
||||
const chunk = completion.choices[0]?.message?.content;
|
||||
if (chunk !== '') {
|
||||
for (const line of chunk.split(/\n\s*\n/).filter(Boolean)) {
|
||||
debug(`${bullet} ${line}`);
|
||||
openAIWebhookClient.send(line);
|
||||
@ -142,7 +141,7 @@ export const init = async (client, config) => {
|
||||
|
||||
// === Message Fetching Helpers ===
|
||||
// Retrieve recent messages from every text channel since a given timestamp.
|
||||
async function fetchRecentMessages(since) {
|
||||
async function _fetchRecentMessages(since) {
|
||||
const allMessages = new Collection();
|
||||
|
||||
// Get all text channels in the guild
|
||||
@ -181,7 +180,7 @@ export const init = async (client, config) => {
|
||||
debug(`**Incident Cycle #${incidentCounter++}**`);
|
||||
|
||||
// Rebuild the list of current index cases, if any.
|
||||
let indexesList = guild.members.cache.filter(member => member.roles.cache.has(indexRole.id));
|
||||
const indexesList = guild.members.cache.filter(member => member.roles.cache.has(indexRole.id));
|
||||
debug(`${bullet} Index Cases: **${indexesList.size}**`);
|
||||
|
||||
// Build the victimsList using whitelisted roles.
|
||||
@ -206,7 +205,7 @@ export const init = async (client, config) => {
|
||||
}
|
||||
|
||||
// Conditions for potentially starting an incident.
|
||||
if (indexesList.size == 0 && victimsList.size > 0) {
|
||||
if (indexesList.size === 0 && victimsList.size > 0) {
|
||||
if ((Math.floor(Math.random() * incidenceDenominator) + 1) === 1) {
|
||||
debug(`${bullet} Incidence Check: **Success**`);
|
||||
const newIndex = victimsList.random();
|
||||
@ -240,7 +239,7 @@ export const init = async (client, config) => {
|
||||
}
|
||||
|
||||
// Prepare the next cycle.
|
||||
let interval = cycleInterval + Math.floor(Math.random() * (2 * cycleIntervalRange + 1)) - cycleIntervalRange;
|
||||
const interval = cycleInterval + Math.floor(Math.random() * (2 * cycleIntervalRange + 1)) - cycleIntervalRange;
|
||||
setTimeout(cycleIncidents, interval);
|
||||
debug(`${bullet} Cycle #${incidentCounter} **<t:${Math.floor((Date.now() + interval) / 1000)}:R>** at **<t:${Math.floor((Date.now() + interval) / 1000)}:t>**`);
|
||||
} catch (error) {
|
||||
@ -291,7 +290,6 @@ export const init = async (client, config) => {
|
||||
if (message.webhookId) return;
|
||||
guild = client.guilds.cache.get(guildID);
|
||||
|
||||
|
||||
// Someone mentioned us - respond if openAI is enabled, the message was in the webhook channel, and a trigger was used.
|
||||
if (openAI === true && openAIWebhook.channel.id === message.channel.id && openAITriggers.some(word => message.content.replace(/[^\w\s]/gi, '').toLowerCase().includes(word.toLowerCase()))) {
|
||||
// Also check if an active incident is required to respond.
|
||||
@ -334,7 +332,7 @@ export const init = async (client, config) => {
|
||||
let percentage = Math.min(infections / prox.size * 100, probabilityLimit);
|
||||
|
||||
// Reduce base probability by ${antiViralEffectiveness}% for those with ${antiViralRole}
|
||||
if (message.member.roles.cache.has(antiViralRole.id)) {
|
||||
if (message.member.roles.cache.has(antiViralRole.id) && Math.random() * 100 === antiViralEffectiveness) {
|
||||
percentage = Math.round(percentage - (antiViralEffectiveness * (percentage / 100)));
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { execFile } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
// Use execFile to avoid shell interpretation of arguments
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ import { onMessageQueueEvent } from './pbUtils.js';
|
||||
/**
|
||||
* Example module that listens for 'test' messages in the message_queue collection.
|
||||
*/
|
||||
export const init = async (client, config) => {
|
||||
client.logger.info('[module:messageQueueExample] Initializing Message Queue Example module');
|
||||
export async function init(client, _config) {
|
||||
client.logger.info('[module:messageQueueExample] Message Queue Example module initialized');
|
||||
onMessageQueueEvent(client, async (action, record) => {
|
||||
// Only process newly created records
|
||||
if (action !== 'create') return;
|
||||
@ -25,4 +25,4 @@ export const init = async (client, config) => {
|
||||
client.logger.error(`[module:messageQueueExample] Failed to delete message_queue record ${record.id}: ${err.message}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// _opt/pbutils.js
|
||||
// Polyfill global EventSource for PocketBase realtime in Node.js (using CommonJS require)
|
||||
import { createRequire } from 'module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { EventSource } = require('eventsource');
|
||||
if (typeof global.EventSource === 'undefined') {
|
||||
@ -16,7 +17,7 @@ if (typeof global.EventSource === 'undefined') {
|
||||
* @param {Object} client - Discord client with attached PocketBase instance
|
||||
* @param {Object} config - Client configuration
|
||||
*/
|
||||
export const init = async (client, config) => {
|
||||
export async function init(client, _config) {
|
||||
const { pb, logger } = client;
|
||||
|
||||
logger.info('[module:pbUtils] Initializing PocketBase utilities module');
|
||||
@ -38,10 +39,10 @@ export const init = async (client, config) => {
|
||||
logger.error(`[module:pbUtils] Failed to subscribe to message_queue realtime: ${error.message}`);
|
||||
}
|
||||
|
||||
// end of init()
|
||||
// end of init()
|
||||
|
||||
logger.info('PocketBase utilities module initialized');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler for incoming message_queue pub/sub events.
|
||||
@ -215,9 +216,9 @@ const extendPocketBase = (client, pb, logger) => {
|
||||
const records = [];
|
||||
const pageSize = options.pageSize || 200;
|
||||
let page = 1;
|
||||
|
||||
const isRunning = true;
|
||||
while (isRunning) {
|
||||
try {
|
||||
while (true) {
|
||||
const result = await pb.collection(collection).getList(page, pageSize, options);
|
||||
records.push(...result.items);
|
||||
|
||||
@ -226,13 +227,13 @@ const extendPocketBase = (client, pb, logger) => {
|
||||
}
|
||||
|
||||
page++;
|
||||
}
|
||||
|
||||
return records;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to get all records from ${collection}: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return records;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -361,7 +362,6 @@ const extendPocketBase = (client, pb, logger) => {
|
||||
return await pb.deleteOne('message_queue', id);
|
||||
};
|
||||
|
||||
|
||||
// ===== CACHE MANAGEMENT =====
|
||||
|
||||
// Simple in-memory cache
|
||||
|
||||
@ -4,13 +4,15 @@
|
||||
* and handles text or image (function_call) outputs.
|
||||
*/
|
||||
// Removed local file fallback; prompt now comes exclusively from PocketBase via responsesPrompt module
|
||||
import { OpenAI } from 'openai';
|
||||
import axios from 'axios';
|
||||
import { AttachmentBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
import { expandTemplate } from '../_src/template.js';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import axios from 'axios';
|
||||
import { AttachmentBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
import { OpenAI } from 'openai';
|
||||
|
||||
import { expandTemplate } from '../_src/template.js';
|
||||
|
||||
// Discord message max length
|
||||
const MAX_DISCORD_MSG_LENGTH = 2000;
|
||||
|
||||
@ -26,7 +28,7 @@ function splitMessage(text, maxLength = MAX_DISCORD_MSG_LENGTH) {
|
||||
let chunk = '';
|
||||
let codeBlockOpen = false;
|
||||
let codeBlockFence = '```';
|
||||
for (let line of lines) {
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
const isFenceLine = trimmed.startsWith('```');
|
||||
if (isFenceLine) {
|
||||
@ -72,7 +74,6 @@ function splitMessage(text, maxLength = MAX_DISCORD_MSG_LENGTH) {
|
||||
return chunks.map(c => c.endsWith('\n') ? c.slice(0, -1) : c);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the bot should respond to a message.
|
||||
* Controlled by enableMentions and enableReplies in config.
|
||||
@ -143,7 +144,7 @@ async function handleImage(client, message, resp, cfg) {
|
||||
const promptText = args.prompt;
|
||||
// Determine number of images (1-10); DALL·E-3 only supports 1
|
||||
let count = 1;
|
||||
if (args.n != null) {
|
||||
if (args.n !== null) {
|
||||
const nVal = typeof args.n === 'number' ? args.n : parseInt(args.n, 10);
|
||||
if (!Number.isNaN(nVal)) count = nVal;
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { _fs } from 'fs';
|
||||
import { _path } from 'path';
|
||||
|
||||
import { _MessageFlags } from 'discord-api-types/v10';
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
// Placeholder info for template variables
|
||||
const TEMPLATE_KEYS_INFO = 'Available keys: userName, userId, locationName, locationId, date, time, datetime, clientId';
|
||||
|
||||
@ -27,7 +29,7 @@ export const commands = [
|
||||
.setAutocomplete(true)
|
||||
),
|
||||
async execute(interaction, client) {
|
||||
const clientId = client.config.id;
|
||||
const _clientId = client.config.id;
|
||||
const versionId = interaction.options.getString('version');
|
||||
// Fetch prompt: live latest or selected historic
|
||||
let promptText = client.responsesPrompt || '';
|
||||
@ -87,12 +89,12 @@ export const commands = [
|
||||
const _clients = [];
|
||||
|
||||
export async function init(client, clientConfig) {
|
||||
const clientId = clientConfig.id;
|
||||
const _clientId = client.config.id;
|
||||
client.logger.info('[module:responsesPrompt] initialized');
|
||||
// Load live prompt (latest version)
|
||||
try {
|
||||
const { items } = await client.pb.collection('responses_prompts')
|
||||
.getList(1, 1, { filter: `clientId="${clientId}"`, sort: '-created' });
|
||||
.getList(1, 1, { filter: `clientId="${_clientId}"`, sort: '-created' });
|
||||
client.responsesPrompt = items[0]?.prompt || '';
|
||||
} catch (err) {
|
||||
client.logger.error(`Error loading current prompt: ${err.message}`);
|
||||
@ -106,7 +108,7 @@ export async function init(client, clientConfig) {
|
||||
if (focused.name === 'version') {
|
||||
try {
|
||||
const { items } = await client.pb.collection('responses_prompts')
|
||||
.getList(1, 25, { filter: `clientId="${clientId}"`, sort: '-created' });
|
||||
.getList(1, 25, { filter: `clientId="${_clientId}"`, sort: '-created' });
|
||||
const choices = items.map(r => ({ name: new Date(r.created).toLocaleString(), value: r.id }));
|
||||
await interaction.respond(choices);
|
||||
} catch (err) {
|
||||
@ -129,9 +131,9 @@ export async function init(client, clientConfig) {
|
||||
}
|
||||
const newPrompt = parts.join('\n');
|
||||
// Persist new version
|
||||
let newRec;
|
||||
let _newRec;
|
||||
try {
|
||||
newRec = await client.pb.createOne('responses_prompts', { clientId, prompt: newPrompt, updatedBy: interaction.user.id });
|
||||
_newRec = await client.pb.createOne('responses_prompts', { clientId: _clientId, prompt: newPrompt, updatedBy: interaction.user.id });
|
||||
client.responsesPrompt = newPrompt;
|
||||
} catch (err) {
|
||||
client.logger.error(`Failed to save prompt: ${err.message}`);
|
||||
@ -140,7 +142,7 @@ export async function init(client, clientConfig) {
|
||||
// Prune older versions beyond the 10 most recent
|
||||
try {
|
||||
const { items } = await client.pb.collection('responses_prompts')
|
||||
.getList(1, 100, { filter: `clientId="${clientId}"`, sort: '-created' });
|
||||
.getList(1, 100, { filter: `clientId="${_clientId}"`, sort: '-created' });
|
||||
const toDelete = items.map(r => r.id).slice(10);
|
||||
for (const id of toDelete) {
|
||||
await client.pb.deleteOne('responses_prompts', id);
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import axios from 'axios';
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
/**
|
||||
* Slash command module for '/query'.
|
||||
@ -5,10 +9,8 @@ import { MessageFlags } from 'discord-api-types/v10';
|
||||
* including optional image generation function calls.
|
||||
*/
|
||||
import { SlashCommandBuilder, AttachmentBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
|
||||
import { expandTemplate } from '../_src/template.js';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* Split long text into chunks safe for Discord messaging.
|
||||
@ -58,7 +60,7 @@ async function handleImageInteraction(client, interaction, resp, cfg, ephemeral)
|
||||
const promptText = args.prompt;
|
||||
// Determine number of images (1-10); DALL·E-3 only supports 1
|
||||
let count = 1;
|
||||
if (args.n != null) {
|
||||
if (args.n !== null) {
|
||||
const nVal = typeof args.n === 'number' ? args.n : parseInt(args.n, 10);
|
||||
if (!Number.isNaN(nVal)) count = nVal;
|
||||
}
|
||||
@ -190,7 +192,7 @@ export const commands = [
|
||||
}
|
||||
} catch (err) {
|
||||
client.logger.error(`[cmd:query] Error checking score: ${err.message}`);
|
||||
return interaction.reply({ content: 'Error verifying your score. Please try again later.', flags: MessageFlags.Ephemeral});
|
||||
return interaction.reply({ content: 'Error verifying your score. Please try again later.', flags: MessageFlags.Ephemeral });
|
||||
}
|
||||
}
|
||||
const prompt = interaction.options.getString('prompt');
|
||||
@ -298,7 +300,7 @@ export const commands = [
|
||||
required,
|
||||
additionalProperties: false
|
||||
},
|
||||
strict: true,
|
||||
strict: true
|
||||
});
|
||||
}
|
||||
if (cfg.tools?.webSearch) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { _MessageFlags } from 'discord-api-types/v10';
|
||||
// _opt/schangar.js
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
@ -100,12 +100,12 @@ export const commands = [
|
||||
if (typeof client.pb.updateOne === 'function') {
|
||||
await client.pb.updateOne('command_hangarsync', record.id, {
|
||||
userId: `${interaction.user.id}`,
|
||||
epoch: `${syncEpoch}`,
|
||||
epoch: `${syncEpoch}`
|
||||
});
|
||||
} else {
|
||||
await client.pb.collection('command_hangarsync').update(record.id, {
|
||||
userId: `${interaction.user.id}`,
|
||||
epoch: `${syncEpoch}`,
|
||||
epoch: `${syncEpoch}`
|
||||
});
|
||||
}
|
||||
client.logger.info(`[cmd:hangarsync] Updated hangarsync for guild ${interaction.guildId} by user ${interaction.user.id}`);
|
||||
@ -115,13 +115,13 @@ export const commands = [
|
||||
await client.pb.createOne('command_hangarsync', {
|
||||
guildId: `${interaction.guildId}`,
|
||||
userId: `${interaction.user.id}`,
|
||||
epoch: `${syncEpoch}`,
|
||||
epoch: `${syncEpoch}`
|
||||
});
|
||||
} else {
|
||||
await client.pb.collection('command_hangarsync').create({
|
||||
guildId: `${interaction.guildId}`,
|
||||
userId: `${interaction.user.id}`,
|
||||
epoch: `${syncEpoch}`,
|
||||
epoch: `${syncEpoch}`
|
||||
});
|
||||
}
|
||||
client.logger.info(`[cmd:hangarsync] Created new hangarsync for guild ${interaction.guildId} by user ${interaction.user.id}`);
|
||||
@ -131,7 +131,7 @@ export const commands = [
|
||||
} catch (error) {
|
||||
client.logger.error(`[cmd:hangarsync] Error: ${error.message}`);
|
||||
await interaction.reply({
|
||||
content: `Error syncing hangar status. Please try again later.`,
|
||||
content: 'Error syncing hangar status. Please try again later.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
@ -212,8 +212,8 @@ export const commands = [
|
||||
|
||||
// Key positions in the cycle
|
||||
const allOffDuration = 5;
|
||||
const turningGreenDuration = 5 * 24;
|
||||
const turningOffDuration = 5 * 12;
|
||||
const _turningGreenDuration = 5 * 24 * 1000;
|
||||
const turningOffDuration = 5 * 12 * 1000;
|
||||
|
||||
// Calculate how much time has passed since the epoch
|
||||
const timeSinceEpoch = (currentTime - hangarSync.epoch) / (60 * 1000);
|
||||
@ -222,26 +222,26 @@ export const commands = [
|
||||
const cyclePosition = ((timeSinceEpoch % cycleDuration) + cycleDuration) % cycleDuration;
|
||||
|
||||
// Initialize stuff and things
|
||||
const lights = [":black_circle:", ":black_circle:", ":black_circle:", ":black_circle:", ":black_circle:"];
|
||||
const lights = [':black_circle:', ':black_circle:', ':black_circle:', ':black_circle:', ':black_circle:'];
|
||||
let minutesUntilNextPhase = 0;
|
||||
let currentPhase = "";
|
||||
let currentPhase = '';
|
||||
|
||||
// If the epoch is now, we should be at the all-green position.
|
||||
// From there, we need to determine where we are in the cycle.
|
||||
|
||||
// Case 1: We're in the unlocked phase, right after epoch
|
||||
if (cyclePosition < turningOffDuration) {
|
||||
currentPhase = "Unlocked";
|
||||
currentPhase = 'Unlocked';
|
||||
|
||||
// All lights start as green
|
||||
lights.fill(":green_circle:");
|
||||
lights.fill(':green_circle:');
|
||||
|
||||
// Calculate how many lights have turned off
|
||||
const offLights = Math.floor(cyclePosition / 12);
|
||||
|
||||
// Set the appropriate number of lights to off
|
||||
for (let i = 0; i < offLights; i++) {
|
||||
lights[i] = ":black_circle:";
|
||||
lights[i] = ':black_circle:';
|
||||
}
|
||||
|
||||
// Calculate time until next light turns off
|
||||
@ -251,7 +251,7 @@ export const commands = [
|
||||
|
||||
// Case 2: We're in the reset phase
|
||||
else if (cyclePosition < turningOffDuration + allOffDuration) {
|
||||
currentPhase = "Resetting";
|
||||
currentPhase = 'Resetting';
|
||||
|
||||
// Lights are initialized "off", so do nothing with them
|
||||
|
||||
@ -262,10 +262,10 @@ export const commands = [
|
||||
|
||||
// Case 3: We're in the locked phase
|
||||
else {
|
||||
currentPhase = "Locked";
|
||||
currentPhase = 'Locked';
|
||||
|
||||
// All lights start as red
|
||||
lights.fill(":red_circle:");
|
||||
lights.fill(':red_circle:');
|
||||
|
||||
// Calculate how many lights have turned green
|
||||
const timeIntoPhase = cyclePosition - (turningOffDuration + allOffDuration);
|
||||
@ -273,7 +273,7 @@ export const commands = [
|
||||
|
||||
// Set the appropriate number of lights to green
|
||||
for (let i = 0; i < greenLights; i++) {
|
||||
lights[i] = ":green_circle:";
|
||||
lights[i] = ':green_circle:';
|
||||
}
|
||||
|
||||
// Calculate time until next light turns green
|
||||
@ -323,7 +323,7 @@ export const commands = [
|
||||
} catch (error) {
|
||||
client.logger.error(`Error in hangarstatus command: ${error.message}`);
|
||||
await interaction.reply({
|
||||
content: `Error retrieving hangar status. Please try again later.`,
|
||||
content: 'Error retrieving hangar status. Please try again later.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
@ -345,7 +345,7 @@ function isPocketBaseConnected(client) {
|
||||
}
|
||||
|
||||
// Initialize module
|
||||
export const init = async (client, config) => {
|
||||
export async function init(client, _config) {
|
||||
client.logger.info('Initializing Star Citizen Hangar Status module');
|
||||
|
||||
// Check PocketBase connection
|
||||
@ -361,4 +361,4 @@ export const init = async (client, config) => {
|
||||
}
|
||||
|
||||
client.logger.info('Star Citizen Hangar Status module initialized');
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// Example of another module using scorekeeper
|
||||
export const init = async (client, config) => {
|
||||
export async function init(client, _config) {
|
||||
// Set up message listener that adds input points when users chat
|
||||
client.on('messageCreate', async (message) => {
|
||||
if (message.author.bot) return;
|
||||
@ -76,7 +76,7 @@ export const init = async (client, config) => {
|
||||
// If someone joined or left a channel, update tracking for everyone in that channel
|
||||
updateChannelUserTracking(client, oldState, newState);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Process when a user leaves a voice channel
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
// opt/scorekeeper.js
|
||||
import cron from 'node-cron';
|
||||
import { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } from 'discord.js';
|
||||
import cron from 'node-cron';
|
||||
|
||||
// Module state container
|
||||
const moduleState = {
|
||||
cronJobs: new Map(), // Store cron jobs by client ID
|
||||
cronJobs: new Map() // Store cron jobs by client ID
|
||||
};
|
||||
|
||||
/**
|
||||
@ -435,7 +435,8 @@ async function runDecay(client, guildId) {
|
||||
}
|
||||
}
|
||||
|
||||
client.logger.info(`Decay completed for guild ${guildId}: ${updatedCount} records updated`);
|
||||
const _reason = 'Automated decay';
|
||||
client.logger.info(`[module:scorekeeper] Decayed ${updatedCount} records by ${client.config.scorekeeper.decay}% (${_reason})`);
|
||||
return updatedCount;
|
||||
} catch (error) {
|
||||
client.logger.error(`Error running decay: ${error.message}`);
|
||||
@ -609,7 +610,7 @@ export const commands = [
|
||||
{ name: 'Commendation Value', value: `-# ${commendationValue}`, inline: true },
|
||||
{ name: 'Citation Value', value: `-# ${citationValue}`, inline: true },
|
||||
{ name: 'Multiplier Formula', value: `-# 1 + (${scoreData.commendations} * ${commendationValue}) - (${scoreData.citations} * ${citationValue}) = ${multiplierValue.toFixed(2)}`, inline: false },
|
||||
{ name: 'Priority Score Formula', value: `-# ${multiplierValue.toFixed(2)} × ${scoreData.input} / (${scoreData.output} + ${baseOutput}) = ${scoreData.totalScore.toFixed(2)}`, inline: false },
|
||||
{ name: 'Priority Score Formula', value: `-# ${multiplierValue.toFixed(2)} × ${scoreData.input} / (${scoreData.output} + ${baseOutput}) = ${scoreData.totalScore.toFixed(2)}`, inline: false }
|
||||
)
|
||||
.setFooter({ text: 'Last decay: ' + new Date(scoreData.lastDecay).toLocaleDateString() })
|
||||
.setTimestamp();
|
||||
@ -721,7 +722,7 @@ export const commands = [
|
||||
const cooldown = client.config.scorekeeper.cooldown || 0;
|
||||
if (cooldown > 0) {
|
||||
const recent = await client.pb.collection('scorekeeper_events').getList(1, 1, {
|
||||
filter: `guildId = \"${guildId}\" && userId = \"${targetUser.id}\" && type = \"commendation\" && categoryId = \"${categoryId}\"`,
|
||||
filter: `guildId = "${guildId}" && userId = "${targetUser.id}" && type = "commendation" && categoryId = "${categoryId}"`,
|
||||
sort: '-created'
|
||||
});
|
||||
const lastItem = recent.items?.[0];
|
||||
@ -806,12 +807,13 @@ export const commands = [
|
||||
}
|
||||
const targetUser = interaction.options.getUser('user');
|
||||
const categoryId = interaction.options.getString('category');
|
||||
const reason = interaction.options.getString('reason');
|
||||
const amount = 1;
|
||||
// Enforce per-category cooldown
|
||||
const cooldown = client.config.scorekeeper.cooldown || 0;
|
||||
if (cooldown > 0) {
|
||||
const recent = await client.pb.collection('scorekeeper_events').getList(1, 1, {
|
||||
filter: `guildId = \"${guildId}\" && userId = \"${targetUser.id}\" && type = \"citation\" && categoryId = \"${categoryId}\"`,
|
||||
filter: `guildId = "${guildId}" && userId = "${targetUser.id}" && type = "citation" && categoryId = "${categoryId}"`,
|
||||
sort: '-created'
|
||||
});
|
||||
const lastItem = recent.items?.[0];
|
||||
@ -834,7 +836,6 @@ export const commands = [
|
||||
try {
|
||||
await client.scorekeeper.addCitation(interaction.guildId, targetUser.id, amount);
|
||||
// Log event
|
||||
// Log event (timestamp managed by PocketBase "created" field)
|
||||
await client.pb.collection('scorekeeper_events').create({
|
||||
guildId: interaction.guildId,
|
||||
userId: targetUser.id,
|
||||
@ -909,7 +910,7 @@ export const commands = [
|
||||
await interaction.reply({ content: `Category '${name}' created.`, ephemeral: true });
|
||||
} catch (err) {
|
||||
client.logger.error(`Error in addcategory: ${err.message}`);
|
||||
await interaction.reply({ content: 'Failed to create category.', flags: MessageFlags.Ephemeral});
|
||||
await interaction.reply({ content: 'Failed to create category.', flags: MessageFlags.Ephemeral });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -938,7 +939,7 @@ export const commands = [
|
||||
await interaction.reply({ content: `Category '${name}' removed.`, ephemeral: true });
|
||||
} catch (err) {
|
||||
client.logger.error(`Error in removecategory: ${err.message}`);
|
||||
await interaction.reply({ content: 'Failed to remove category.', flags: MessageFlags.Ephemeral});
|
||||
await interaction.reply({ content: 'Failed to remove category.', flags: MessageFlags.Ephemeral });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, ChannelType, EmbedBuilder } from 'discord.js';
|
||||
import { MessageFlags } from 'discord-api-types/v10';
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, ChannelType, EmbedBuilder } from 'discord.js';
|
||||
// Init function to handle autocomplete for /vc invite
|
||||
/**
|
||||
* tempvc module: temporary voice channel manager
|
||||
@ -266,7 +266,7 @@ export const commands = [
|
||||
} catch {}
|
||||
await interaction.reply({ content: `Kicked <@${u.id}>.`, flags: MessageFlags.Ephemeral });
|
||||
} else if (sub === 'limit') {
|
||||
let num = interaction.options.getInteger('number', true);
|
||||
const num = interaction.options.getInteger('number', true);
|
||||
// enforce range 0-99
|
||||
if (num < 0 || num > 99) {
|
||||
return interaction.reply({ content: 'User limit must be between 0 (no limit) and 99.', flags: MessageFlags.Ephemeral });
|
||||
@ -571,21 +571,21 @@ export async function init(client) {
|
||||
'• /vc kick <user> — Kick a user from this channel\n' +
|
||||
'• /vc role <role> — Set a role to allow/deny access\n' +
|
||||
'• /vc mode <whitelist|blacklist> — Switch role mode\n' +
|
||||
'• /vc limit <number> — Set user limit (0–99)',
|
||||
'• /vc limit <number> — Set user limit (0–99)'
|
||||
},
|
||||
{
|
||||
name: 'Presets',
|
||||
value:
|
||||
'• /vc save <name> — Save current settings as a preset\n' +
|
||||
'• /vc restore <name> — Restore settings from a preset\n' +
|
||||
'• /vc reset — Reset channel to default settings',
|
||||
'• /vc reset — Reset channel to default settings'
|
||||
},
|
||||
{
|
||||
name: 'Utilities',
|
||||
value:
|
||||
'• /vc rename <new_name> — Rename this channel\n' +
|
||||
'• /vc info — Show channel info\n' +
|
||||
'• /vc delete — Delete this channel',
|
||||
'• /vc delete — Delete this channel'
|
||||
}
|
||||
);
|
||||
await ch.send({ embeds: [helpEmbed] });
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const rootDir = path.dirname(__dirname);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
/**
|
||||
* expandTemplate: simple variable substitution in {{key}} placeholders.
|
||||
* @param {string} template - The template string with {{key}} tokens.
|
||||
|
||||
208
config.js
208
config.js
@ -1,6 +1,38 @@
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
const logging = {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly'
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d'
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const pocketbase = {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
clients: [
|
||||
@ -14,37 +46,9 @@ export default {
|
||||
token: process.env.SYSAI_DISCORD_TOKEN
|
||||
},
|
||||
|
||||
logging: {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly',
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d',
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d',
|
||||
}
|
||||
}
|
||||
},
|
||||
logging: { ...logging },
|
||||
|
||||
pocketbase: {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
},
|
||||
pocketbase: { ...pocketbase },
|
||||
|
||||
responses: {
|
||||
apiKey: process.env.SHARED_OPENAI_API_KEY,
|
||||
@ -58,7 +62,7 @@ export default {
|
||||
tools: {
|
||||
webSearch: true,
|
||||
fileSearch: false,
|
||||
imageGeneration: true,
|
||||
imageGeneration: true
|
||||
},
|
||||
imageGeneration: {
|
||||
defaultModel: 'gpt-image-1',
|
||||
@ -90,31 +94,7 @@ export default {
|
||||
token: process.env.ASOP_DISCORD_TOKEN
|
||||
},
|
||||
|
||||
logging: {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly',
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d',
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d',
|
||||
}
|
||||
}
|
||||
},
|
||||
logging: { ...logging },
|
||||
|
||||
condimentX: {
|
||||
dryRun: false,
|
||||
@ -163,11 +143,7 @@ export default {
|
||||
openAIToken: process.env.SHARED_OPENAI_API_KEY
|
||||
},
|
||||
|
||||
pocketbase: {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
},
|
||||
pocketbase: { ...pocketbase },
|
||||
|
||||
responses: {
|
||||
apiKey: process.env.SHARED_OPENAI_API_KEY,
|
||||
@ -181,7 +157,7 @@ export default {
|
||||
tools: {
|
||||
webSearch: false,
|
||||
fileSearch: false,
|
||||
imageGeneration: true,
|
||||
imageGeneration: true
|
||||
},
|
||||
imageGeneration: {
|
||||
defaultModel: 'gpt-image-1',
|
||||
@ -225,37 +201,9 @@ export default {
|
||||
token: process.env.CROWLEY_DISCORD_TOKEN
|
||||
},
|
||||
|
||||
logging: {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly',
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d',
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d',
|
||||
}
|
||||
}
|
||||
},
|
||||
logging: { ...logging },
|
||||
|
||||
pocketbase: {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
},
|
||||
pocketbase: { ...pocketbase },
|
||||
|
||||
responses: {
|
||||
apiKey: process.env.SHARED_OPENAI_API_KEY,
|
||||
@ -269,7 +217,7 @@ export default {
|
||||
tools: {
|
||||
webSearch: false,
|
||||
fileSearch: false,
|
||||
imageGeneration: false,
|
||||
imageGeneration: false
|
||||
},
|
||||
imageGeneration: {
|
||||
defaultModel: 'gpt-image-1',
|
||||
@ -298,37 +246,9 @@ export default {
|
||||
token: process.env.GRANDPA_DISCORD_TOKEN
|
||||
},
|
||||
|
||||
logging: {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly',
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d',
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d',
|
||||
}
|
||||
}
|
||||
},
|
||||
logging: { ...logging },
|
||||
|
||||
pocketbase: {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
},
|
||||
pocketbase: { ...pocketbase },
|
||||
|
||||
responses: {
|
||||
apiKey: process.env.SHARED_OPENAI_API_KEY,
|
||||
@ -342,7 +262,7 @@ export default {
|
||||
tools: {
|
||||
webSearch: false,
|
||||
fileSearch: false,
|
||||
imageGeneration: false,
|
||||
imageGeneration: false
|
||||
},
|
||||
imageGeneration: {
|
||||
defaultModel: 'gpt-image-1',
|
||||
@ -352,7 +272,7 @@ export default {
|
||||
},
|
||||
|
||||
responsesRandomizer: {
|
||||
chance: 0.01,
|
||||
chance: 0.01
|
||||
},
|
||||
modules: [
|
||||
'botUtils',
|
||||
@ -374,37 +294,9 @@ export default {
|
||||
token: process.env.SMUUUSH_DISCORD_TOKEN
|
||||
},
|
||||
|
||||
logging: {
|
||||
console: {
|
||||
enabled: true,
|
||||
colorize: true,
|
||||
level: 'silly',
|
||||
},
|
||||
file: {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
combined: {
|
||||
enabled: true,
|
||||
level: 'silly',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '30d',
|
||||
},
|
||||
error: {
|
||||
enabled: true,
|
||||
level: 'error',
|
||||
location: 'logs',
|
||||
maxSize: '12m',
|
||||
maxFiles: '365d',
|
||||
}
|
||||
}
|
||||
},
|
||||
logging: { ...logging },
|
||||
|
||||
pocketbase: {
|
||||
url: process.env.SHARED_POCKETBASE_URL,
|
||||
username: process.env.SHARED_POCKETBASE_USERNAME,
|
||||
password: process.env.SHARED_POCKETBASE_PASSWORD
|
||||
},
|
||||
pocketbase: { ...pocketbase },
|
||||
|
||||
responses: {
|
||||
apiKey: process.env.SHARED_OPENAI_API_KEY,
|
||||
@ -418,7 +310,7 @@ export default {
|
||||
tools: {
|
||||
webSearch: false,
|
||||
fileSearch: false,
|
||||
imageGeneration: true,
|
||||
imageGeneration: true
|
||||
},
|
||||
imageGeneration: {
|
||||
defaultModel: 'gpt-image-1',
|
||||
@ -433,8 +325,8 @@ export default {
|
||||
'responses',
|
||||
'responsesPrompt',
|
||||
'responsesQuery'
|
||||
],
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
6
index.js
6
index.js
@ -1,10 +1,11 @@
|
||||
import { Client, Collection, GatewayIntentBits } from 'discord.js';
|
||||
|
||||
import { ansi, wrapAnsi } from './_src/ansiColors.js';
|
||||
import { loadModules } from './_src/loader.js';
|
||||
import { createLogger } from './_src/logger.js';
|
||||
import { initializePocketbase } from './_src/pocketbase.js';
|
||||
import { loadModules } from './_src/loader.js';
|
||||
import config from './config.js';
|
||||
// For deprecated ephemeral option: convert to flags
|
||||
import { ansi, wrapAnsi } from './_src/ansiColors.js';
|
||||
|
||||
// Initialize Discord client
|
||||
const initializeClient = async (clientConfig) => {
|
||||
@ -45,7 +46,6 @@ const initializeClient = async (clientConfig) => {
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
|
||||
const commandName = interaction.commandName;
|
||||
|
||||
try {
|
||||
|
||||
2883
package-lock.json
generated
2883
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,9 +11,12 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"registry": "node registry.js"
|
||||
"registry": "node registry.js",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/rest": "^2.2.0",
|
||||
"axios": "^1.8.4",
|
||||
"discord-api-types": "^0.37.120",
|
||||
"discord.js": "^14.18.0",
|
||||
@ -24,5 +27,9 @@
|
||||
"pocketbase": "^0.25.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
// registry.js
|
||||
import { REST } from '@discordjs/rest';
|
||||
import { Routes } from 'discord-api-types/v10';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { REST } from '@discordjs/rest'; // eslint-disable-line import/no-unresolved
|
||||
import { Routes } from 'discord-api-types/v10';
|
||||
|
||||
import config from './config.js';
|
||||
|
||||
// Get directory name in ES module
|
||||
@ -46,7 +48,7 @@ Examples:
|
||||
// Validate action parameter
|
||||
const validActions = ['register', 'unregister', 'list'];
|
||||
if (!validActions.includes(actionArg.toLowerCase())) {
|
||||
console.error(`[registry] Error: Invalid action "${actionArg}". Must be one of: ${validActions.join(', ')}`);
|
||||
console.error(`[registry] Error: Invalid action "${actionArg}". Must be one of: ${validActions.join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
const action = actionArg.toLowerCase();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user