新しいSlashコマンドを追加する際のチェックリストと手順
新しい Slash コマンドをこのリポジトリへ追加するための標準手順。
AGENTS.md の方針(ボタン優先、flags: MessageFlags.Ephemeral、PR運用、検証手順)に合わせる。
public / restricted / owner-only)を決めたdeferReply 要否)src/commands/{Name}Command.ts を作成src/command-config.ts の に追加COMMANDSsrc/lib/{name}-utils.ts を作成src/interaction-handlers/{Name}ButtonHandler.ts を作成src/interaction-handlers/{Name}ModalHandler.ts を作成docs/HELP.md を更新(新コマンドは必須)docs/COMMAND.md を更新(新コマンドは必須)docs/DETAILS/{name}.md を作成/更新docs/PERMISSIONS.md を更新docs/SPEC.md を更新docs/DB-SCHEMA.md を更新{Name}Command(PascalCase)src/commands/{Name}Command.ts.js 拡張子を付けるimport { Command } from '@sapphire/framework';
import { MessageFlags } from 'discord.js';
export class {Name}Command extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, {
...options,
name: '{name}',
description: '{概要}',
preconditions: ['GuildAllowed'], // 権限タイプに応じて変更
});
}
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerChatInputCommand((builder) =>
builder
.setName('{name}')
.setDescription('{概要}')
// .addStringOption((opt) =>
// opt.setName('option').setDescription('説明').setRequired(true),
// )
);
}
public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
// 長い処理(3秒超想定)がある場合
// await interaction.deferReply({ flags: MessageFlags.Ephemeral });
// const result = await heavyTask();
// await interaction.editReply({ content: result });
// return;
// 短い処理(3秒以内)
await interaction.reply({
content: '...',
flags: MessageFlags.Ephemeral,
});
}
}
try/catch で握るなら notifyErrorToOwner を明示呼び出しfollowUp({ flags: MessageFlags.Ephemeral }) を使う| 権限タイプ | preconditions | 例 |
|---|---|---|
public | ['GuildAllowed'] | bosyu, dice, help |
restricted | ['GuildAllowed', 'RestrictedAllowed'] | verify, mention-reactors |
owner-only | なし(コマンド内で owner 判定) | allow, config |
command-config 追加src/command-config.ts の COMMANDS に必ず追加する。
{ name: '{name}', description: '{概要}', permissionType: '{public|restricted|owner-only}' }
buildXxxCustomId / parseXxxCustomId を src/lib/*-utils.ts に実装するparse 側で prefix と要素数を厳密チェックするimport { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
import type { ButtonInteraction } from 'discord.js';
import { parseXxxCustomId } from '../lib/xxx-utils.js';
export class {Name}ButtonHandler extends InteractionHandler {
public constructor(context: InteractionHandler.LoaderContext, options: InteractionHandler.Options) {
super(context, {
...options,
interactionHandlerType: InteractionHandlerTypes.Button,
});
}
public override parse(interaction: ButtonInteraction) {
const parsed = parseXxxCustomId(interaction.customId);
if (!parsed) return this.none();
return this.some(parsed);
}
public override async run(
interaction: ButtonInteraction,
parsed: InteractionHandler.ParseResult<this>,
) {
// ボタン処理
}
}
docs/HELP.md(必須)## /{name} セクションを追加### 概要 を必ず入れる(/help 一覧生成で使用)概要 / 使い方 / 動作 / 例docs/COMMAND.md(必須)## /{name} を追加使い方 / パラメータ(あれば) / 動作docs/DETAILS/{name}.md(推奨)AGENTS.md に合わせて以下を順に実行する。
pnpm lint:fix
pnpm format
pnpm verify
必要に応じて手動確認:
pnpm dev
確認項目:
/help 一覧と詳細に反映されるagent/<short-task>)で作業しているmain へ直接 push していない目的 / 変更点 / 検証結果 を記載したephemeral: true を使う(必ず flags: MessageFlags.Ephemeral)