mcpField
D
discord-bot-architect

discord-bot-architect

github.com/davila7开发33.1k332 次安装今天更新
代码仓库

关于 discord-bot-architect

discord-bot-architect 是面向 Discord 机器人开发者的技能,涵盖 JavaScript 和 Python。它提供斜杠命令、网关事件及交互组件的实现模式,并说明常见陷阱。

主要功能

  1. 01Discord.js v14 机器人配置
  2. 02Pycord 机器人配置
  3. 03斜杠命令模式
  4. 04按钮、菜单和模态框
  5. 05机器人常见问题指引

适用场景

  1. 01启动 JavaScript 或 TypeScript Discord 机器人
  2. 02使用应用命令构建 Python 机器人
  3. 03添加交互菜单和表单
  4. 04规避常见命令及事件循环问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/davila7/claude-code-templates --skill discord-bot-architect

安装后在 Claude Code 中输入/discord-bot-architect确认已加载。

详细介绍

Discord Bot 架构师

模式

Discord.js v14 基础

使用 Discord.js v14 和斜杠命令的现代 Discord 机器人设置

适用场景:['使用 JavaScript/TypeScript 构建 Discord 机器人', '需要带事件的完整网关连接', '构建具有复杂交互的机器人']

```javascript
// src/index.js
const { Client, Collection, GatewayIntentBits, Events } = require('discord.js');
const fs = require('node:fs');
const path = require('node:path');
require('dotenv').config();

// Create client with minimal required intents
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    // Add only what you need:
    // GatewayIntentBits.GuildMessages,
    // GatewayIntentBits.MessageContent,  // PRIVILEGED - avoid if possible
  ]
});

// Load commands
client.commands = new Collection();
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));

for (const file of commandFiles) {
  const filePath = path.join(commandsPath, file);
  const command = require(filePath);
  if ('data' in command && 'execute' in command) {
    client.commands.set(command.data.name, command);
  }
}

// Load events
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(f => f.endsWith('.js'));

for (const file of eventFiles) {
  const filePath = path.join(eventsPath, file);
  const event = require(filePath);
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args));
  } else {
    client.on(event.name, (...args) => event.execute(...args));
  }
}

client.login(process.env.DISCORD_TOKEN);
// src/commands/ping.js
const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Replies with Pong!'),

  async execute(interaction) {
    const sent = await interaction.reply({
      content: 'Pinging...',
      fetchReply: true
    });

    const latency = sent.createdTimestamp - interaction.createdTimestamp;
    await interaction.editReply(`Pong! Latency: ${latency}ms`);
  }
};
// src/events/interactionCreate.js
const { Events } = require('discord.js');

module.exports = {
  name: Event
Pycord 机器人基础

使用 Pycord(Python)和应用程序命令的 Discord 机器人

适用场景:['使用 Python 构建 Discord 机器人', '偏好 async/await 模式', '需要良好的斜杠命令支持']

```python
# main.py
import os
import discord
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()

# Configure intents - only enable what you need
intents = discord.Intents.default()
# intents.message_content = True  # PRIVILEGED - avoid if possible
# intents.members = True          # PRIVILEGED

bot = commands.Bot(
    command_prefix="!",  # Legacy, prefer slash commands
    intents=intents
)

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")
    # Sync commands (do this carefully - see sharp edges)
    # await bot.sync_commands()

# Slash command
@bot.slash_command(name="ping", description="Check bot latency")
async def ping(ctx: discord.ApplicationContext):
    latency = round(bot.latency * 1000)
    await ctx.respond(f"Pong! Latency: {latency}ms")

# Slash command with options
@bot.slash_command(name="greet", description="Greet a user")
async def greet(
    ctx: discord.ApplicationContext,
    user: discord.Option(discord.Member, "User to greet"),
    message: discord.Option(str, "Custom message", required=False)
):
    msg = message or "Hello!"
    await ctx.respond(f"{user.mention}, {msg}")

# Load cogs
for filename in os.listdir("./cogs"):
    if filename.endswith(".py"):
        bot.load_extension(f"cogs.{filename[:-3]}")

bot.run(os.environ["DISCORD_TOKEN"])
# cogs/general.py
import discord
from discord.ext import commands

class General(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.slash_command(name="info", description="Bot information")
    async def info(self, ctx: discord.ApplicationContext):
        embed = discord.Embed(
            title="Bot Info",
            description="A helpful Discord bot",
            color=discord.Color.blue()
        )
        embed.add_field(name="Servers", value=len(self.bot.guilds))
        embed.add_field(name="Latency", value=f"{round(self.bot.latency * 1000)}ms")
        await ctx.respond(embed=embed)

    @commands.Cog.
交互组件模式

使用按钮、选择菜单和模态框实现丰富的用户体验

适用场景:['需要交互式用户界面', '收集超出斜杠命令选项的用户输入', '构建菜单、确认或表单']

```javascript
// Discord.js - Buttons and Select Menus
const {
  SlashCommandBuilder,
  ActionRowBuilder,
  ButtonBuilder,
  ButtonStyle,
  StringSelectMenuBuilder,
  ModalBuilder,
  TextInputBuilder,
  TextInputStyle
} = require('discord.js');

module.exports = {
  data: new SlashCommandBuilder()
    .setName('menu')
    .setDescription('Shows an interactive menu'),

  async execute(interaction) {
    // Button row
    const buttonRow = new ActionRowBuilder()
      .addComponents(
        new ButtonBuilder()
          .setCustomId('confirm')
          .setLabel('Confirm')
          .setStyle(ButtonStyle.Primary),
        new ButtonBuilder()
          .setCustomId('cancel')
          .setLabel('Cancel')
          .setStyle(ButtonStyle.Danger),
        new ButtonBuilder()
          .setLabel('Documentation')
          .setURL('https://discord.js.org')
          .setStyle(ButtonStyle.Link)  // Link buttons don't emit events
      );

    // Select menu row (one per row, takes all 5 slots)
    const selectRow = new ActionRowBuilder()
      .addComponents(
        new StringSelectMenuBuilder()
          .setCustomId('select-role')
          .setPlaceholder('Select a role')
          .setMinValues(1)
          .setMaxValues(3)
          .addOptions([
            { label: 'Developer', value: 'dev', emoji: '💻' },
            { label: 'Designer', value: 'design', emoji: '🎨' },
            { label: 'Community', value: 'community', emoji: '🎉' }
          ])
      );

    await interaction.reply({
      content: 'Choose an option:',
      components: [buttonRow, selectRow]
    });

    // Collect responses
    const collector = interaction.channel.createMessageComponentCollector({
      filter: i => i.user.id === interaction.user.id,
      time: 60_000  // 60 seconds timeout
    });

    collector.on('collect', async i => {
      if (i.customId === 'confirm') {
        await i.update({ content: 'Confirmed!', components: [] });
        collector.stop();
      } else if (i.custo

反模式

❌ 使用消息内容处理命令

为什么不好:Message Content Intent 属于特权权限,且已不推荐用于机器人命令。 斜杠命令才是推荐的方式。

❌ 每次启动时同步命令

为什么不好:命令注册有速率限制。全局命令最多需要 1 小时 才能生效。每次启动时同步会浪费 API 调用,并可能触及限制。

❌ 阻塞事件循环

为什么不好:Discord 网关需要定期发送心跳。阻塞操作 会导致心跳丢失和连接断开。

⚠️ 尖锐边缘

问题严重程度解决方案
问题critical## 立即确认,稍后处理
问题critical## 第 1 步:在开发者门户中启用
问题high## 使用单独的部署脚本(不要放在启动时)
问题critical## 绝不硬编码令牌
问题high## 生成正确的邀请 URL
问题medium## 开发:使用服务器命令
问题medium## 绝不阻塞事件循环
问题medium## 立即显示模态框

评论

支持 Markdown