Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
51e148d
Add image-spam automod with moderator console
max-bromberg Jun 11, 2026
83e2cba
Bump discord.js to 14.26 and Sapphire framework to 5.5
max-bromberg Jun 11, 2026
f2886d6
Migrate Prisma 4 to 7 with the pg driver adapter
max-bromberg Jun 11, 2026
0dbcdbc
Bump TypeScript to 6, dotenv to 17, @types/node to 25
max-bromberg Jun 11, 2026
3f5fb0c
Add tenure-aware detection for new members (automod prong 2)
max-bromberg Jun 11, 2026
5c044d1
Add perceptual (dHash) image hashing to the automod
max-bromberg Jun 11, 2026
f162ea1
Port legacy server-management listeners (parity)
max-bromberg Jun 11, 2026
c7ccb71
Port role-select buttons, tag buttons, and a modern /say (parity)
max-bromberg Jun 11, 2026
2c3b69d
Cleanliness pass: tag refactor, Dockerfile fix, ping + docs
max-bromberg Jun 11, 2026
b75c70a
Resolve PR #22 feedback and fix tag grammar/spelling
max-bromberg Jun 11, 2026
8bb885e
Refactor: extract shared embed out of the entry point
max-bromberg Jun 12, 2026
1e79dff
Release v1.0.0: new README, fix repo URLs
max-bromberg Jun 12, 2026
9fd044f
Add Phase 1 helper-assist features
max-bromberg Jun 12, 2026
acc7ab4
Add text-flooding automod detector
claude Jun 12, 2026
8edd57a
Add cross-channel question-spam automod
claude Jun 12, 2026
00b48aa
Add Phase 2 helper-assist features
max-bromberg Jun 12, 2026
6d809b9
Lengthen stale-post timing; support text + forum help channels
max-bromberg Jun 12, 2026
fd89c40
feat: replace dHash with DCT-based pHash for image spam detection
max-bromberg Jun 15, 2026
e80acb4
feat: complete docker-compose env coverage and add Dockge setup guide
max-bromberg Jun 15, 2026
74effe8
feat: harden helper-assist for community rollout
max-bromberg Jun 15, 2026
c5cbcea
fix: replace implicit role check with explicit SUGGEST_IMMUNE_ROLE_ID…
max-bromberg Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# --- Required ---
# Discord bot token (https://discord.com/developers/applications)
BOT_TOKEN=

# --- Core IDs (defaults target the official Arduino server) ---
# SERVER_ID=420594746990526466
# BOT_COMMANDS_CHANNEL_ID=451158319361556491

# Channel where the automod posts image-spam alerts for moderators.
# REQUIRED to enable the anti-spam console; leave empty to disable automod.
MOD_LOG_CHANNEL_ID=

# --- Server-management features (optional; each self-disables when unset) ---
# JOIN_LEAVE_LOG_CHANNEL_ID= # member join/leave + invite-source logging
# CROSSPOST_LOG_CHANNEL_ID= # where auto-crosspost results are logged
# CROSSPOST_CHANNEL_IDS= # comma-separated announcement channels to auto-publish
# ROLE_SELECT_MESSAGE_ID= # message whose buttons toggle opt-in roles
# EVENT_NOTIFS_ROLE_ID= # role toggled by the "events" button
# SERVER_UPDATE_NOTIFS_ROLE_ID= # role toggled by the "server_updates" button

# --- Helper-assist features ---
# Channels where tag/code/ask suggestions are suppressed (staff channels,
# announcements, etc.). Comma-separated channel IDs. For a forum channel,
# listing the parent channel ID silences all its threads.
# SUGGEST_IGNORE_CHANNEL_IDS=
# Role IDs whose holders never receive suggestions (Trusted, Knowledgeable,
# Helper, Moderator, etc.). Do NOT include self-assignable notification roles.
# SUGGEST_IMMUNE_ROLE_IDS=
# Help channels may be FORUM channels (each post is a thread) or regular TEXT
# channels (threads opened inside them get the same treatment). Comma-separated.
# HELP_CHANNEL_IDS= # help channels (forum or text) — enables solve button, auto-needinfo, sweep, /openposts
# HELP_FORUM_CHANNEL_IDS= # legacy alias for HELP_CHANNEL_IDS (still honoured; merged in)
# TAG_SUGGEST_ENABLED=true # auto-suggest a relevant tag on common error messages (set false to disable)
# CODE_FORMAT_SUGGEST_ENABLED=true # nudge users who paste unformatted code toward the codeblock tag
# ASK_SUGGEST_ENABLED=true # nudge "can I ask?" / "anyone here?" non-questions toward the ask tag
# HELP_AUTO_NEEDINFO=true # auto-post the needinfo checklist when a new help post is too thin
# HELP_NEEDINFO_MIN_CHARS=60 # opening post shorter than this (and without code/image) counts as thin
# HELP_STALE_SWEEP_ENABLED=true # nudge + auto-archive abandoned help posts
# HELP_STALE_NUDGE_HOURS=72 # idle hours before a "still need help?" nudge (default 3 days)
# HELP_STALE_ARCHIVE_HOURS=168 # idle hours after a nudge (no human reply) before auto-archiving (default 7 days)

# --- Persistence (optional) ---
# When unset, the bot runs fully in-memory and the spam-image blocklist
# resets on restart. With docker-compose this is wired automatically.
# DATABASE_URL=postgresql://arduino:arduino@db:5432/arduino

# Postgres credentials used by docker-compose
# POSTGRES_USER=arduino
# POSTGRES_PASSWORD=arduino
# POSTGRES_DB=arduino

# --- Automod tunables (optional; defaults in src/utils/config.ts) ---
# AUTOMOD_BURST_THRESHOLD=3 # image messages to flag a same-channel burst
# AUTOMOD_BURST_WINDOW_MS=60000 # window for the burst count
# AUTOMOD_FANOUT_CHANNELS=2 # distinct channels for a cross-channel fan-out
# AUTOMOD_FANOUT_WINDOW_MS=120000 # window for fan-out detection
# AUTOMOD_PHASH_THRESHOLD=6 # max Hamming distance (of 64) for near-dupe images
# AUTOMOD_TIMEOUT_MS=3600000 # auto/console timeout duration (1 hour)
# AUTOMOD_ALERT_COOLDOWN_MS=30000 # min gap between alerts per user
# AUTOMOD_IMMUNE_ROLE_IDS= # comma-separated role ids never inspected
# AUTOMOD_NEW_MEMBER_WINDOW_MS=259200000 # how long a member counts as "new" (72h)
# AUTOMOD_NEW_MEMBER_BURST_THRESHOLD=2 # stricter burst threshold for new members

# --- Text-flooding detector (needs MOD_LOG_CHANNEL_ID to post alerts) ---
# AUTOMOD_FLOOD_ENABLED=true # set false to disable text-flooding detection
# AUTOMOD_FLOOD_THRESHOLD=5 # short messages within the window to flag flooding
# AUTOMOD_FLOOD_WINDOW_MS=15000 # sliding window for the flood count
# AUTOMOD_FLOOD_MAX_CHARS=25 # a message counts as "short" at or below this length
# AUTOMOD_FLOOD_AUTO_TIMEOUT=false # also auto-timeout on a flood hit (default: alert only)

# --- Cross-channel question-spam detector (needs MOD_LOG_CHANNEL_ID) ---
# Catches new users fanning the same question across many channels at once.
# AUTOMOD_CROSSPOST_ENABLED=true # set false to disable
# AUTOMOD_CROSSPOST_CHANNELS=2 # distinct channels for a near-identical repeat
# AUTOMOD_CROSSPOST_SPREAD_CHANNELS=3 # distinct channels for new-member shotgunning
# AUTOMOD_CROSSPOST_WINDOW_MS=120000 # window for cross-channel detection (2 min)
# AUTOMOD_CROSSPOST_MIN_CHARS=12 # ignore messages shorter than this (greetings/reactions)
# AUTOMOD_CROSSPOST_SIMILARITY_PCT=80 # token-overlap % at which two messages are the "same" question
14 changes: 7 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ LABEL org.opencontainers.image.source https://github.com/arduinodiscord/bot

WORKDIR /srv

COPY ./package*.json .
COPY ./prisma ./prisma

COPY . .

RUN apk add --update --no-cache openssl1.1-compat

# Install dependencies first for better layer caching. The postinstall hook runs
# `prisma generate`, which needs the schema, so copy prisma/ before installing.
COPY package*.json ./
COPY prisma ./prisma
COPY prisma.config.ts ./
RUN npm install

# Then copy the rest of the source and build.
COPY . .
RUN npm run build

CMD ["npm", "start"]
Loading