generated from nhcarrigan/template
1ebe240475
## Summary This PR adds a suite of slash commands and a context menu command to Amari, along with shared utilities and quality improvements across the board. ### New Commands - **`/create-issue`** — generates a GitHub issue on a specified repo using AI-drafted content (title, description, acceptance criteria) - **`/create-task`** — creates a task in Naomi's Leantime instance with an AI-drafted description and configurable priority - **`/onboard-mentee`** — automates the mentorship onboarding flow (GitHub invite, forum thread, role assignment) - **Forward to Owner** (context menu, message command) — forwards any message to Naomi with action buttons (contributed by @teklu) ### Shared Utilities - **`src/utils/makeAiRequest.ts`** — a single wrapper around the Anthropic SDK for all AI calls, with Amari's personality prompt baked in and full error handling - **`src/events/handleInteractionCreate.ts`** — extracted interaction handler (was inline in `index.ts`) to keep complexity under control ### Quality Improvements - `ephemeral: true` → `flags: [ MessageFlags.Ephemeral ]` (deprecated API removed) - Full `try/catch` + `logger.error` audit across all modules (`logMenteeJoin`, `checkAchievements`, `processMentorshipRole`, `processGitHubEvent`) - `deployGlobal.ts` replaced with a static `commands.json` payload for manual registration - Amari's personality prompt updated to reflect her actual character — warm, observant, and relentlessly caring ### Notes - `CLIENT_ID` is needed in 1Password at `op://Environment Variables - Naomi/Amari/client id` for the `commands.json` registration call - The forward-to-owner command (PR #13, contributed by @teklu) is fully preserved with original commit authorship ✨ This PR was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Co-authored-by: Teklu <tekluabayneh@gmail.com> Reviewed-on: #16 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
86 lines
2.1 KiB
TypeScript
86 lines
2.1 KiB
TypeScript
/**
|
|
* @copyright NHCarrigan
|
|
* @license Naomi's Public License
|
|
* @author Naomi Carrigan
|
|
*/
|
|
|
|
import {
|
|
MessageFlags,
|
|
type ChatInputCommandInteraction,
|
|
type Interaction,
|
|
} from "discord.js";
|
|
import { createIssue } from "../commands/createIssue.js";
|
|
import { createTask } from "../commands/createTask.js";
|
|
import { forwardToOwner } from "../commands/forwardToOwner.js";
|
|
import { onboardMentee } from "../commands/onboardMentee.js";
|
|
import { ids } from "../config/ids.js";
|
|
import type { Amari } from "../interfaces/amari.js";
|
|
|
|
/**
|
|
* Routes a chat input command to the appropriate handler.
|
|
* @param amari -- Amari's instance.
|
|
* @param interaction -- The incoming slash command to dispatch.
|
|
*/
|
|
const handleChatInputCommand = (
|
|
amari: Amari,
|
|
interaction: ChatInputCommandInteraction,
|
|
): void => {
|
|
const { commandName } = interaction;
|
|
if (commandName === "onboard-mentee") {
|
|
void onboardMentee(amari, interaction);
|
|
return;
|
|
}
|
|
if (commandName === "create-task") {
|
|
void createTask(interaction);
|
|
return;
|
|
}
|
|
if (commandName === "create-issue") {
|
|
void createIssue(interaction);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handles the interaction create event from Discord.
|
|
* Bootstraps all of our custom interaction logic.
|
|
* @param amari -- Amari's instance.
|
|
* @param interaction -- The incoming Discord gateway event to dispatch.
|
|
*/
|
|
export const handleInteractionCreate = (
|
|
amari: Amari,
|
|
interaction: Interaction,
|
|
): void => {
|
|
if (
|
|
interaction.isMessageContextMenuCommand()
|
|
&& interaction.commandName === "Forward to Naomi"
|
|
) {
|
|
void forwardToOwner(interaction);
|
|
return;
|
|
}
|
|
|
|
if (interaction.isButton() && interaction.customId === "resolve") {
|
|
if (interaction.user.id !== ids.users.naomi) {
|
|
void interaction.reply({
|
|
content: "Who are you????",
|
|
flags: [ MessageFlags.Ephemeral ],
|
|
});
|
|
return;
|
|
}
|
|
void interaction.message.delete();
|
|
return;
|
|
}
|
|
|
|
if (interaction.isChatInputCommand()) {
|
|
handleChatInputCommand(amari, interaction);
|
|
return;
|
|
}
|
|
|
|
if (interaction.isAutocomplete()) {
|
|
return;
|
|
}
|
|
|
|
void interaction.reply({
|
|
content: "What?",
|
|
flags: [ MessageFlags.Ephemeral ],
|
|
});
|
|
};
|