Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
89 changes: 82 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,87 @@
DISCORD_TOKEN=your-bot-token-here
DISCORD_APP_ID=your-application-id-here
DISCORD_GUILD_ID=your-test-guild-id-here
# ============================================================
# OmegaBot Environment Configuration
# ============================================================
#
# Copy this file to `.env` and fill in real values.
# NEVER commit `.env` with secrets.
#
# ============================================================
# Discord (required)
# ============================================================

# Summary mode: use "llm" to enable OpenAI, or anything else for local summary
# Bot authentication token used to connect to Discord
DISCORD_TOKEN=your-discord-bot-token-here

# Application ID required for slash command registration
DISCORD_APP_ID=your-discord-application-id

# Guild where development slash commands are registered
# (guild commands update instantly)
DISCORD_GUILD_ID=your-discord-guild-id


# ============================================================
# Summaries
# ============================================================

# Summary mode:
# - "local" → simple local summarizer (default)
# - "llm" → OpenAI-powered summaries
SUMMARY_MODE=local

# Only required if SUMMARY_MODE=llm
# OpenAI API key
# Required ONLY when SUMMARY_MODE=llm
OPENAI_API_KEY=your-openai-key-if-needed

# GitHub token
GITHUB_TOKEN=your-token-here

# ============================================================
# GitHub Integration
# ============================================================

# Personal Access Token (PAT) for GitHub REST API
#
# Required for:
# - Issue lookup
# - Pull request lookup
# - PR announcements
#
# Fine-grained token recommended.
# Minimum permissions:
# - Contents: Read
# - Pull requests: Read
# - Issues: Read
GITHUB_TOKEN=your-github-pat-here


# ============================================================
# GitHub PR Announcements (optional)
# ============================================================

# Default GitHub repo owner/org for PR polling
# Example: NickTheDevOpsGuy
GITHUB_OWNER=your-github-owner

# Repository name for PR polling
# Example: OmegaBot
GITHUB_REPO=your-repo-name

# Discord channel ID where PR announcements will be posted
#
# IMPORTANT:
# This must be a numeric channel ID, not a channel name.
# Enable Developer Mode in Discord → right-click channel → Copy ID
GITHUB_ANNOUNCE_CHANNEL_ID=your-discord-channel-id


# ============================================================
# GitHub PR Polling Interval
# ============================================================

# Polling interval in milliseconds
#
# Examples:
# 60000 → every 1 minute
# 300000 → every 5 minutes
#
# Defaults to 60000 (1 minute) if not set
GITHUB_POLL_INTERVAL_MS=60000
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ Thumbs.db
*.zip

# Runtime data
data/timezones.json
*.json
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ OmegaBot is online

```
.
├── .env.example
├── .env
├── .github
│ ├── ISSUE_TEMPLATE
│ │ ├── bug.yml
Expand Down Expand Up @@ -166,6 +166,9 @@ OmegaBot is online
│ ├── github
│ │ ├── githubApi.ts
│ │ ├── githubClient.ts
│ │ ├── lastSeenStore.ts
│ │ ├── prFormatter.ts
│ │ ├── prPoller.ts
│ │ └── types.ts
│ ├── summary
│ │ ├── llmSummary.ts
Expand Down
58 changes: 48 additions & 10 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,77 @@
// src/bot.ts

import { Client, GatewayIntentBits } from "discord.js";
import { loadCommands, type CommandClient } from "./services/discord/commandLoader.js";
import { handleInteraction } from "./services/discord/interactionHandler.js";
import { pollPullRequestsOnce } from "./services/github/prPoller.js";
import { env } from "./config/env.js";
/*
* Create the Discord client with only the intents required for slash-command handling.

/**
* Create the Discord client with only the intents required for slash commands.
*/
const client = new Client({
intents: [GatewayIntentBits.Guilds],
}) as CommandClient;

/*
* Initialize the command registry where loaded slash commands will be stored.
/**
* Command registry populated by the command loader.
*/
client.commands = new Map();

/*
* Load and register all compiled command modules before the bot starts handling interactions.
/**
* Load compiled command modules and attach them to client.commands.
*/
await loadCommands(client);

/*
* Forward every incoming interaction to the central interaction handler.
/**
* Forward every incoming interaction to the central handler.
*/
client.on("interactionCreate", async (interaction) => {
await handleInteraction(interaction, client);
});

/*
/**
* GitHub PR polling is optional.
* We only enable it when all required env vars are present.
*/
const githubPollingEnabled =
!!env.githubToken &&
!!env.githubOwner &&
!!env.githubRepo &&
!!env.githubAnnounceChannelId;

/**
* Log a confirmation once the bot successfully connects.
*/
client.once("clientReady", () => {
console.log("OmegaBot is online");

if (githubPollingEnabled) {
console.log(
`GitHub PR polling enabled for ${env.githubOwner}/${env.githubRepo} -> channel ${env.githubAnnounceChannelId}`,
);
console.log(`GitHub PR polling interval: ${env.githubPollIntervalMs}ms`);
} else {
console.log("GitHub PR polling disabled (missing env config)");
}
});

/*
/**
* Start the bot session using the configured token.
*/
client.login(env.token);

/**
* Schedule PR polling (if enabled).
* Uses void to avoid unhandled promise warnings.
*/
if (githubPollingEnabled) {
setInterval(() => {
void pollPullRequestsOnce({
client,
owner: env.githubOwner!,
repo: env.githubRepo!,
announceChannelId: env.githubAnnounceChannelId!,
});
}, env.githubPollIntervalMs);
}
92 changes: 79 additions & 13 deletions src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ dotenv.config();

/**
* Helper to enforce that required environment variables are present.
*
* If a variable is missing, the bot fails fast at startup instead of
* crashing later at runtime in unpredictable ways.
*/
Expand All @@ -17,30 +18,95 @@ function requireEnv(name: string): string {
/**
* Centralized environment configuration for OmegaBot.
*
* Required fields:
* - DISCORD_TOKEN Bot authentication token for connecting to Discord.
* - DISCORD_APP_ID Application ID needed for command registration.
* - DISCORD_GUILD_ID Guild where development commands are registered.
* Keeping this configuration in one place:
* - Prevents scattered process.env lookups
* - Makes configuration explicit and auditable
* - Allows optional features to be gated cleanly
*
* ------------------------------------------------------------------
* Required (core bot functionality)
* ------------------------------------------------------------------
*
* - DISCORD_TOKEN
* Bot authentication token used to connect to Discord.
*
* - DISCORD_APP_ID
* Application ID required for slash command registration.
*
* - DISCORD_GUILD_ID
* Guild where development commands are registered.
*
* ------------------------------------------------------------------
* Optional (feature flags / enhancements)
* ------------------------------------------------------------------
*
* - SUMMARY_MODE
* "local" (default) or "llm"
* Determines which summarizer implementation is used.
*
* - OPENAI_API_KEY
* Required only when SUMMARY_MODE === "llm".
*
* ------------------------------------------------------------------
* GitHub integration
* ------------------------------------------------------------------
*
* - GITHUB_TOKEN
* Personal Access Token used for authenticated GitHub REST calls.
* Required for:
* - Issue lookup
* - PR lookup
* - PR announcements
*
* Optional fields:
* - SUMMARY_MODE "local" (default) or "llm"
* Determines which summarizer implementation is used.
* - OPENAI_API_KEY Only required when using LLM summary mode.
* - GITHUB_OWNER
* Default repository owner for polling PRs (optional).
*
* Keeping this configuration in one place prevents scattered env lookups
* and makes the bot easier to configure, test, and deploy.
* - GITHUB_REPO
* Default repository name for polling PRs (optional).
*
* - GITHUB_ANNOUNCE_CHANNEL_ID
* Discord channel ID where PR announcements are posted (optional).
*
* - GITHUB_POLL_INTERVAL_MS
* Polling interval for PR announcements.
* Defaults to 60 seconds if not provided.
*
* All GitHub announcement fields are optional so the bot can run
* without polling enabled.
*/
export const env = {
/* ---------------------------------------------------------------- */
/* Discord (required) */
/* ---------------------------------------------------------------- */

token: requireEnv("DISCORD_TOKEN"),
appId: requireEnv("DISCORD_APP_ID"),
guildId: requireEnv("DISCORD_GUILD_ID"),

// Summary mode defaults to local so the bot can run without AI keys.
/* ---------------------------------------------------------------- */
/* Summaries */
/* ---------------------------------------------------------------- */

// Defaults to local so the bot runs without AI keys.
summaryMode: process.env.SUMMARY_MODE ?? "local",

// Optional, only needed when user chooses LLM summarization.
// Only required when summaryMode === "llm"
openAIKey: process.env.OPENAI_API_KEY ?? null,

// GitHub
/* ---------------------------------------------------------------- */
/* GitHub */
/* ---------------------------------------------------------------- */

// Auth token for GitHub REST API
githubToken: process.env.GITHUB_TOKEN ?? null,

// Default repo configuration for PR polling (optional)
githubOwner: process.env.GITHUB_OWNER ?? null,
githubRepo: process.env.GITHUB_REPO ?? null,

// Where PR announcements should be posted
githubAnnounceChannelId: process.env.GITHUB_ANNOUNCE_CHANNEL_ID ?? null,

// Polling interval (ms). Defaults to 60s.
githubPollIntervalMs: Number(process.env.GITHUB_POLL_INTERVAL_MS ?? "60000"),
};
Loading