From 6373aefefe179a49665affee4562f05c9833c597 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Tue, 23 Dec 2025 12:55:42 -0500 Subject: [PATCH 1/2] Adding in staging for faq slash command --- README.md | 27 ++--- src/commands/faq/faq.ts | 144 ++++++++++++++++++++++++ src/commands/faq/subcommands/_shared.ts | 0 src/commands/faq/subcommands/add.ts | 0 src/commands/faq/subcommands/get.ts | 0 src/commands/faq/subcommands/list.ts | 0 src/commands/faq/subcommands/remove.ts | 0 7 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 src/commands/faq/faq.ts create mode 100644 src/commands/faq/subcommands/_shared.ts create mode 100644 src/commands/faq/subcommands/add.ts create mode 100644 src/commands/faq/subcommands/get.ts create mode 100644 src/commands/faq/subcommands/list.ts create mode 100644 src/commands/faq/subcommands/remove.ts diff --git a/README.md b/README.md index 9c51fd0e..f2fe63ec 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,6 @@ OmegaBot is online ``` . -├── .env-example ├── .github │ ├── ISSUE_TEMPLATE │ │ ├── bug.yml @@ -133,24 +132,6 @@ OmegaBot is online │ │ └── OmegaBot.yml │ └── pull_request_template.md ├── .husky -│ ├── _ -│ │ ├── .gitignore -│ │ ├── applypatch-msg -│ │ ├── commit-msg -│ │ ├── h -│ │ ├── husky.sh -│ │ ├── post-applypatch -│ │ ├── post-checkout -│ │ ├── post-commit -│ │ ├── post-merge -│ │ ├── post-rewrite -│ │ ├── pre-applypatch -│ │ ├── pre-auto-gc -│ │ ├── pre-commit -│ │ ├── pre-merge-commit -│ │ ├── pre-push -│ │ ├── pre-rebase -│ │ └── prepare-commit-msg │ ├── pre-commit │ └── pre-push ├── assets @@ -173,6 +154,14 @@ OmegaBot is online │ ├── commands │ │ ├── changelog │ │ │ └── changelog.ts +│ │ ├── faq +│ │ │ ├── subcommands +│ │ │ │ ├── _shared.ts +│ │ │ │ ├── add.ts +│ │ │ │ ├── get.ts +│ │ │ │ ├── list.ts +│ │ │ │ └── remove.ts +│ │ │ └── faq.ts │ │ ├── fun │ │ │ ├── subcommands │ │ │ │ ├── chucknorris.ts diff --git a/src/commands/faq/faq.ts b/src/commands/faq/faq.ts new file mode 100644 index 00000000..2db78d6f --- /dev/null +++ b/src/commands/faq/faq.ts @@ -0,0 +1,144 @@ +// src/commands/faq/faq.ts + +/** + * Base /faq slash command. + * + * Responsibilities of this file: + * - Define the /faq command and its subcommands + * - Handle the Discord interaction lifecycle (defer + reply) + * - Route execution to the correct subcommand handler + * + * Non-goals (by design): + * - No FAQ business logic + * - No file I/O + * - No validation or permissions + * + * All real work is delegated to FAQ services in src/services/faq/. + */ + +import { + MessageFlags, + SlashCommandBuilder, + type ChatInputCommandInteraction, +} from "discord.js"; +import { logger } from "../../utils/logger.js"; + +/** + * Slash command definition. + * + * This defines the public Discord API shape only. + * Each subcommand intentionally mirrors a future service operation: + * - add → create FAQ + * - get → retrieve FAQ + * - list → list FAQs + * - remove → delete FAQ + * + * Each subcommand supports an optional ephemeral flag so users + * can avoid spamming public channels. + */ +export const data = new SlashCommandBuilder() + .setName("faq") + .setDescription("FAQ commands") + + .addSubcommand((s) => + s + .setName("add") + .setDescription("Add a FAQ entry") + .addBooleanOption((o) => + o + .setName("ephemeral") + .setDescription("Only show the result to you") + .setRequired(false), + ), + ) + + .addSubcommand((s) => + s + .setName("get") + .setDescription("Get a FAQ entry by key") + .addBooleanOption((o) => + o + .setName("ephemeral") + .setDescription("Only show the result to you") + .setRequired(false), + ), + ) + + .addSubcommand((s) => + s + .setName("list") + .setDescription("List FAQ entries") + .addBooleanOption((o) => + o + .setName("ephemeral") + .setDescription("Only show the result to you") + .setRequired(false), + ), + ) + + .addSubcommand((s) => + s + .setName("remove") + .setDescription("Remove a FAQ entry by key") + .addBooleanOption((o) => + o + .setName("ephemeral") + .setDescription("Only show the result to you") + .setRequired(false), + ), + ); + +/** + * Command execution entry point. + * + * Pattern used here: + * - Determine subcommand + * - Defer reply immediately (avoid 3s timeout) + * - Route to the correct handler + * + * IMPORTANT: + * This function intentionally contains no business logic. + * Subcommand implementations will live in separate files/services. + */ +export async function execute( + interaction: ChatInputCommandInteraction, +): Promise { + const sub = interaction.options.getSubcommand(true); + const ephemeral = interaction.options.getBoolean("ephemeral") ?? false; + + // Parent command owns the interaction lifecycle + await interaction.deferReply( + ephemeral ? { flags: MessageFlags.Ephemeral } : undefined, + ); + + try { + // Placeholder routing targets. + // Each branch will later call into faqService helpers. + if (sub === "add") { + await interaction.editReply("TODO: /faq add"); + return; + } + + if (sub === "get") { + await interaction.editReply("TODO: /faq get"); + return; + } + + if (sub === "list") { + await interaction.editReply("TODO: /faq list"); + return; + } + + if (sub === "remove") { + await interaction.editReply("TODO: /faq remove"); + return; + } + + // Safety net in case Discord sends something unexpected + await interaction.editReply("Unknown subcommand."); + } catch (err) { + // Centralized error logging, user sees generic failure + logger.error({ err, sub }, "[faq] subcommand failed"); + await interaction.editReply("Something went wrong. Try again in a bit."); + } +} \ No newline at end of file diff --git a/src/commands/faq/subcommands/_shared.ts b/src/commands/faq/subcommands/_shared.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/faq/subcommands/add.ts b/src/commands/faq/subcommands/add.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/faq/subcommands/get.ts b/src/commands/faq/subcommands/get.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/faq/subcommands/list.ts b/src/commands/faq/subcommands/list.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/commands/faq/subcommands/remove.ts b/src/commands/faq/subcommands/remove.ts new file mode 100644 index 00000000..e69de29b From c09504f1a037ef03bdae8adadc40c169fd316122 Mon Sep 17 00:00:00 2001 From: NickTheDevOpsGuy Date: Tue, 23 Dec 2025 12:56:55 -0500 Subject: [PATCH 2/2] style: auto-format with Prettier [skip-precheck] --- src/commands/faq/faq.ts | 10 +++------- src/commands/faq/subcommands/_shared.ts | 1 + src/commands/faq/subcommands/add.ts | 1 + src/commands/faq/subcommands/get.ts | 1 + src/commands/faq/subcommands/list.ts | 1 + src/commands/faq/subcommands/remove.ts | 1 + 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/commands/faq/faq.ts b/src/commands/faq/faq.ts index 2db78d6f..2599fd72 100644 --- a/src/commands/faq/faq.ts +++ b/src/commands/faq/faq.ts @@ -100,16 +100,12 @@ export const data = new SlashCommandBuilder() * This function intentionally contains no business logic. * Subcommand implementations will live in separate files/services. */ -export async function execute( - interaction: ChatInputCommandInteraction, -): Promise { +export async function execute(interaction: ChatInputCommandInteraction): Promise { const sub = interaction.options.getSubcommand(true); const ephemeral = interaction.options.getBoolean("ephemeral") ?? false; // Parent command owns the interaction lifecycle - await interaction.deferReply( - ephemeral ? { flags: MessageFlags.Ephemeral } : undefined, - ); + await interaction.deferReply(ephemeral ? { flags: MessageFlags.Ephemeral } : undefined); try { // Placeholder routing targets. @@ -141,4 +137,4 @@ export async function execute( logger.error({ err, sub }, "[faq] subcommand failed"); await interaction.editReply("Something went wrong. Try again in a bit."); } -} \ No newline at end of file +} diff --git a/src/commands/faq/subcommands/_shared.ts b/src/commands/faq/subcommands/_shared.ts index e69de29b..c5e69167 100644 --- a/src/commands/faq/subcommands/_shared.ts +++ b/src/commands/faq/subcommands/_shared.ts @@ -0,0 +1 @@ +// src/commands/faq/subcommand/_shared.ts diff --git a/src/commands/faq/subcommands/add.ts b/src/commands/faq/subcommands/add.ts index e69de29b..9384a8e1 100644 --- a/src/commands/faq/subcommands/add.ts +++ b/src/commands/faq/subcommands/add.ts @@ -0,0 +1 @@ +// src/commands/faq/subcommand/add.ts diff --git a/src/commands/faq/subcommands/get.ts b/src/commands/faq/subcommands/get.ts index e69de29b..a015d4a4 100644 --- a/src/commands/faq/subcommands/get.ts +++ b/src/commands/faq/subcommands/get.ts @@ -0,0 +1 @@ +// src/commands/faq/subcommand/get.ts diff --git a/src/commands/faq/subcommands/list.ts b/src/commands/faq/subcommands/list.ts index e69de29b..e400e88e 100644 --- a/src/commands/faq/subcommands/list.ts +++ b/src/commands/faq/subcommands/list.ts @@ -0,0 +1 @@ +// src/commands/faq/subcommand/list.ts diff --git a/src/commands/faq/subcommands/remove.ts b/src/commands/faq/subcommands/remove.ts index e69de29b..31f3de28 100644 --- a/src/commands/faq/subcommands/remove.ts +++ b/src/commands/faq/subcommands/remove.ts @@ -0,0 +1 @@ +// src/commands/faq/subcommand/remove.ts