generated from nhcarrigan/template
1c31a49bc4
## Summary - Replaces the old AI companion bot with a full Discord moderation system - Adds 8 slash commands: `warn`, `mute`, `unmute`, `kick`, `softban`, `ban`, `unban`, `prune` - Adds logging for member join/leave, activity (messages, threads, voice), and moderation actions - Audit log integration captures manual bans, kicks, timeouts, and unbans - All applicable actions post sanctions to the Hikari sanction API - All commands are ephemeral, use Components v2, and enforce permission + role hierarchy checks ## Test plan - [ ] Run `pnpm register` to register all 8 commands to the guild - [ ] Verify each command appears in Discord and is only visible to members with the appropriate permissions - [ ] Test each command against a valid target and confirm mod log entry, DM notification, and sanction record - [ ] Test each command against an invalid target (equal/higher role, self, bot) and confirm correct error response - [ ] Perform a manual ban, kick, and timeout in the Discord UI and confirm audit log handler picks them up - [ ] Perform a manual unban and confirm it logs correctly without creating a sanction - [ ] Verify join/leave messages appear in the welcome log channel - [ ] Verify message edits, deletes, thread events, and voice state changes appear in the activity log channel ✨ This issue was created with help from Hikari~ 🌸 Reviewed-on: #11 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
4.3 KiB
4.3 KiB
Keiko — Moderation Bot Rewrite
Overview
Complete rewrite of Keiko from an AI companion bot into a full-featured community moderation bot for Naomi's Discord server.
Tech Stack
- Language: TypeScript
- Runtime: Node.js
- Discord Library: discord.js v14
- Config:
@nhcarrigan/typescript-config - Linting:
@nhcarrigan/eslint-config - Logging:
@nhcarrigan/logger - Package Manager: pnpm
Planned Commands
All moderation commands respond ephemerally using Discord Components v2.
| Command | Description | Sanction Type |
|---|---|---|
/warn <user> <reason> |
Issues a formal warning | warning |
/mute <user> <duration> <reason> |
Applies Discord native timeout | mute |
/unmute <user> <reason> |
Removes Discord native timeout | (none) |
/kick <user> <reason> |
Kicks user from server | kick |
/softban <user> <reason> |
Bans + immediately unbans (message purge) | kick |
/ban <user> <reason> [days] |
Permanently bans user | ban |
/prune <amount max:100> |
Deletes last N messages in current channel | (none — logged to mod channel only) |
Logging Channels
Three configurable logging channels (set via environment/config):
| Channel | Events |
|---|---|
| Welcome/Goodbye | guildMemberAdd, guildMemberRemove |
| Activity Log | Message create/edit/delete, thread create/delete/update, voice channel join/leave/move |
| Moderation Log | All command-issued sanctions + parsed audit log actions (manual bans, kicks, timeouts) |
Sanction API Integration
Endpoint: POST https://hikari.nhcarrigan.com/sanction
Auth: Authorization: {SANCTION_TOKEN}
Payload:
{
"platform": "discord",
"uuid": "<target user ID>",
"username": "<target username>",
"type": "warning | kick | mute | ban",
"reason": "<reason>"
}
Triggers (sanction created for each):
/warn→warning/mute→mute/kick→kick/softban→kick/ban→ban- Audit log: manual ban detected →
ban - Audit log: manual kick detected →
kick - Audit log: manual timeout detected →
mute
No sanction: /unmute, /prune
Confirmed Decisions
| Question | Decision |
|---|---|
| Softban sanction type | Maps to kick |
| Mute mechanism | Discord native timeout |
| Prune scope | Last N messages (up to 100) in current channel; no sanction, log to mod channel |
| Channel config | Config object in src/config/ (single-server) |
| Deployment scope | Single guild only |
| Repo strategy | Replace in-place on feat/modbot branch |
Project Structure (Planned)
keiko/
├── src/
│ ├── commands/ # Slash command definitions
│ ├── events/ # Discord event handlers
│ ├── modules/ # Business logic (sanction sending, audit log parsing, etc.)
│ ├── utils/ # Shared utilities
│ └── index.ts # Entry point
├── prod.env # 1Password secret references (safe to commit)
├── package.json
├── tsconfig.json
├── eslint.config.js
└── vitest.config.ts
Implementation Phases
- Phase 1 — Project scaffold (package.json, tsconfig, eslint, entry point)
- Phase 2 — Commands (all 7 slash commands with ephemeral Components v2 responses)
- Phase 3 — Sanction API integration (send sanctions on command, handle errors)
- Phase 4 — Logging events (welcome/goodbye, activity, moderation channel)
- Phase 5 — Audit log parsing (detect manual moderation actions, send to sanction API)
- Phase 6 — Deploy (fill in channel IDs in
src/config/channels.ts, fill inclientIdinsrc/config/guild.ts, runpnpm registerto register commands, thenpnpm start)
Next Steps Before Deploying
- Fill in actual channel IDs in
src/config/channels.ts - Fill in Keiko's bot client ID in
src/config/guild.ts - Ensure
SANCTION_TOKENis in 1Password at the vault path inprod.env - Run
pnpm registeronce to register slash commands with Discord - Enable privileged intents in Discord Developer Portal:
Server Members IntentandMessage Content Intent - Start the bot with
pnpm start