mirror of
https://github.com/artiemis/artemis.js.git
synced 2026-02-14 02:11:55 +00:00
add pm2 config, license, merge dev commands into a subcommand, add message triggers
This commit is contained in:
parent
3044206a52
commit
49ccedfdcc
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2025 artie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
14
ecosystem.config.cjs
Normal file
14
ecosystem.config.cjs
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: "artemis",
|
||||
interpreter: "bun",
|
||||
script: "src/index.ts",
|
||||
time: true,
|
||||
env: {
|
||||
NODE_ENV: "production",
|
||||
PATH: `${process.env.HOME}/.bun/bin:${process.env.PATH}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -15,5 +15,8 @@ export default tseslint.config(
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["ecosystem.config.cjs"],
|
||||
}
|
||||
);
|
||||
|
||||
116
src/commands/owner/dev.ts
Normal file
116
src/commands/owner/dev.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ChatInputCommandInteraction,
|
||||
codeBlock,
|
||||
ComponentType,
|
||||
MessageFlags,
|
||||
SlashCommandBuilder,
|
||||
} from "discord.js";
|
||||
import { defineCommand } from "..";
|
||||
import { client } from "../../client";
|
||||
import { abort } from "../../utils/error";
|
||||
import { restart as restartBot } from "../../utils/restart";
|
||||
import { shell } from "../../utils/functions";
|
||||
|
||||
export async function sync(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
const counts = await client.syncCommands();
|
||||
|
||||
if (!counts) {
|
||||
abort("No commands to sync");
|
||||
}
|
||||
|
||||
const { guildCount, globalCount } = counts;
|
||||
|
||||
await interaction.followUp(
|
||||
`Successfully synced ${guildCount} guild and ${globalCount} global application commands`
|
||||
);
|
||||
}
|
||||
|
||||
export async function restart(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.reply({
|
||||
content: "Restarting...",
|
||||
flags: MessageFlags.Ephemeral,
|
||||
});
|
||||
|
||||
await restartBot({ token: interaction.token });
|
||||
}
|
||||
|
||||
export async function update(interaction: ChatInputCommandInteraction) {
|
||||
const response = await interaction.deferReply({ withResponse: true });
|
||||
const result = await shell`git pull`;
|
||||
const output = result.stdout + result.stderr;
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("restart")
|
||||
.setLabel("Restart")
|
||||
.setStyle(ButtonStyle.Success)
|
||||
);
|
||||
|
||||
const isUpToDate = output.trim() === "Already up to date.";
|
||||
|
||||
await interaction.editReply({
|
||||
components: isUpToDate || result.failed ? [] : [row],
|
||||
embeds: [
|
||||
{
|
||||
description: codeBlock(output),
|
||||
color: isUpToDate ? 0x00ff00 : 0xff0000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!isUpToDate && !result.failed) {
|
||||
response.resource?.message
|
||||
?.awaitMessageComponent({
|
||||
componentType: ComponentType.Button,
|
||||
time: 30000,
|
||||
filter: (i) => i.user.id === interaction.user.id,
|
||||
dispose: true,
|
||||
})
|
||||
.then(async (interaction) => {
|
||||
await interaction.update({
|
||||
components: [],
|
||||
});
|
||||
await interaction.message.react("🔄");
|
||||
await restartBot({
|
||||
message: {
|
||||
id: interaction.message.id,
|
||||
channelId: interaction.message.channelId,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default defineCommand({
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("dev")
|
||||
.setDescription("Owner commands")
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand.setName("sync").setDescription("Sync application commands")
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand.setName("restart").setDescription("Restarts the bot")
|
||||
)
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand.setName("update").setDescription("Updates the bot")
|
||||
),
|
||||
isOwnerOnly: true,
|
||||
|
||||
async execute(interaction) {
|
||||
switch (interaction.options.getSubcommand()) {
|
||||
case "sync":
|
||||
await sync(interaction);
|
||||
break;
|
||||
case "restart":
|
||||
await restart(interaction);
|
||||
break;
|
||||
case "update":
|
||||
await update(interaction);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -1,19 +0,0 @@
|
||||
import { MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "..";
|
||||
import { restart } from "../../utils/restart";
|
||||
|
||||
export default defineCommand({
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("restart")
|
||||
.setDescription("Restarts the bot"),
|
||||
isOwnerOnly: true,
|
||||
|
||||
async execute(interaction) {
|
||||
await interaction.reply({
|
||||
content: "Restarting...",
|
||||
flags: MessageFlags.Ephemeral,
|
||||
});
|
||||
|
||||
await restart({ token: interaction.token });
|
||||
},
|
||||
});
|
||||
@ -1,26 +0,0 @@
|
||||
import { MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { client } from "../../client";
|
||||
import { defineCommand } from "..";
|
||||
import { abort } from "../../utils/error";
|
||||
|
||||
export default defineCommand({
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("sync")
|
||||
.setDescription("Sync application commands"),
|
||||
isOwnerOnly: true,
|
||||
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
const counts = await client.syncCommands();
|
||||
|
||||
if (!counts) {
|
||||
abort("No commands to sync");
|
||||
}
|
||||
|
||||
const { guildCount, globalCount } = counts;
|
||||
|
||||
await interaction.followUp(
|
||||
`Successfully synced ${guildCount} guild and ${globalCount} global application commands`
|
||||
);
|
||||
},
|
||||
});
|
||||
@ -1,65 +0,0 @@
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
codeBlock,
|
||||
ComponentType,
|
||||
SlashCommandBuilder,
|
||||
} from "discord.js";
|
||||
import { defineCommand } from "..";
|
||||
import { restart } from "../../utils/restart";
|
||||
import { shell } from "../../utils/functions";
|
||||
|
||||
export default defineCommand({
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("update")
|
||||
.setDescription("Updates the bot"),
|
||||
isOwnerOnly: true,
|
||||
|
||||
async execute(interaction) {
|
||||
const response = await interaction.deferReply({ withResponse: true });
|
||||
const result = await shell`git pull`;
|
||||
const output = result.stdout + result.stderr;
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("restart")
|
||||
.setLabel("Restart")
|
||||
.setStyle(ButtonStyle.Success)
|
||||
);
|
||||
|
||||
const isUpToDate = output.trim() === "Already up to date.";
|
||||
|
||||
await interaction.editReply({
|
||||
components: isUpToDate || result.failed ? [] : [row],
|
||||
embeds: [
|
||||
{
|
||||
description: codeBlock(output),
|
||||
color: isUpToDate ? 0x00ff00 : 0xff0000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (!isUpToDate && !result.failed) {
|
||||
response.resource?.message
|
||||
?.awaitMessageComponent({
|
||||
componentType: ComponentType.Button,
|
||||
time: 30000,
|
||||
filter: (i) => i.user.id === interaction.user.id,
|
||||
dispose: true,
|
||||
})
|
||||
.then(async (interaction) => {
|
||||
await interaction.update({
|
||||
components: [],
|
||||
});
|
||||
await interaction.message.react("🔄");
|
||||
await restart({
|
||||
message: {
|
||||
id: interaction.message.id,
|
||||
channelId: interaction.message.channelId,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -1,6 +1,7 @@
|
||||
import { Events } from "discord.js";
|
||||
import { defineEvent } from ".";
|
||||
import { dedent } from "../utils/functions";
|
||||
import { dedent, pickRandom } from "../utils/functions";
|
||||
import { BAD_BOT_EMOJIS, GOOD_BOT_EMOJIS } from "../utils/constants";
|
||||
|
||||
export default defineEvent({
|
||||
name: Events.MessageCreate,
|
||||
@ -17,5 +18,15 @@ export default defineEvent({
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const trigger = message.content.match(/^(?<side>good|bad)\s+bot\b/i);
|
||||
if (trigger) {
|
||||
const emojis =
|
||||
trigger.groups?.side.toLowerCase() === "good"
|
||||
? GOOD_BOT_EMOJIS
|
||||
: BAD_BOT_EMOJIS;
|
||||
await message.reply(pickRandom(emojis));
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -5,17 +5,20 @@ import type {
|
||||
MessageContextMenuCommandInteraction,
|
||||
SlashCommandBuilder,
|
||||
SlashCommandOptionsOnlyBuilder,
|
||||
SlashCommandSubcommandsOnlyBuilder,
|
||||
UserContextMenuCommandInteraction,
|
||||
} from "discord.js";
|
||||
|
||||
export type CommandBuilder =
|
||||
| SlashCommandBuilder
|
||||
| SlashCommandSubcommandsOnlyBuilder
|
||||
| SlashCommandOptionsOnlyBuilder
|
||||
| ContextMenuCommandBuilder;
|
||||
|
||||
type InferInteraction<B> = B extends
|
||||
| SlashCommandBuilder
|
||||
| SlashCommandOptionsOnlyBuilder
|
||||
| SlashCommandSubcommandsOnlyBuilder
|
||||
? ChatInputCommandInteraction
|
||||
: B extends ContextMenuCommandBuilder
|
||||
? MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction
|
||||
|
||||
@ -7,3 +7,19 @@ export const PROD = env.NODE_ENV === "production";
|
||||
export const USER_AGENT = `artemis (discord.js ${version})`;
|
||||
export const FAKE_USER_AGENT =
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0";
|
||||
|
||||
export const GOOD_BOT_EMOJIS = [
|
||||
"<:teehee:825098257742299136>",
|
||||
"<:teehee2:825098258741067787>",
|
||||
"<:teehee3:825098263820632066>",
|
||||
"<:teehee4:825098262884778026>",
|
||||
"<:teehee5:825098263437901825>",
|
||||
];
|
||||
|
||||
export const BAD_BOT_EMOJIS = [
|
||||
"<:rip:825101664939147285>",
|
||||
"<:rip2:825101666373206086>",
|
||||
"<:rip3:825101667434889236>",
|
||||
"<:rip4:825101668428546058>",
|
||||
"<:rip5:825101671436255243>",
|
||||
];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user