mirror of
https://github.com/artiemis/artemis.js.git
synced 2026-02-14 10:21:54 +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-non-null-assertion": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "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 { Events } from "discord.js";
|
||||||
import { defineEvent } from ".";
|
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({
|
export default defineEvent({
|
||||||
name: Events.MessageCreate,
|
name: Events.MessageCreate,
|
||||||
@ -17,5 +18,15 @@ export default defineEvent({
|
|||||||
);
|
);
|
||||||
return;
|
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,
|
MessageContextMenuCommandInteraction,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandOptionsOnlyBuilder,
|
SlashCommandOptionsOnlyBuilder,
|
||||||
|
SlashCommandSubcommandsOnlyBuilder,
|
||||||
UserContextMenuCommandInteraction,
|
UserContextMenuCommandInteraction,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
export type CommandBuilder =
|
export type CommandBuilder =
|
||||||
| SlashCommandBuilder
|
| SlashCommandBuilder
|
||||||
|
| SlashCommandSubcommandsOnlyBuilder
|
||||||
| SlashCommandOptionsOnlyBuilder
|
| SlashCommandOptionsOnlyBuilder
|
||||||
| ContextMenuCommandBuilder;
|
| ContextMenuCommandBuilder;
|
||||||
|
|
||||||
type InferInteraction<B> = B extends
|
type InferInteraction<B> = B extends
|
||||||
| SlashCommandBuilder
|
| SlashCommandBuilder
|
||||||
| SlashCommandOptionsOnlyBuilder
|
| SlashCommandOptionsOnlyBuilder
|
||||||
|
| SlashCommandSubcommandsOnlyBuilder
|
||||||
? ChatInputCommandInteraction
|
? ChatInputCommandInteraction
|
||||||
: B extends ContextMenuCommandBuilder
|
: B extends ContextMenuCommandBuilder
|
||||||
? MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction
|
? MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction
|
||||||
|
|||||||
@ -7,3 +7,19 @@ export const PROD = env.NODE_ENV === "production";
|
|||||||
export const USER_AGENT = `artemis (discord.js ${version})`;
|
export const USER_AGENT = `artemis (discord.js ${version})`;
|
||||||
export const FAKE_USER_AGENT =
|
export const FAKE_USER_AGENT =
|
||||||
"Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0";
|
"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