stage-4: discord bot minimal with channel/admin management

Discord.py bot with slash commands (/ping, /help, /setup, /channel, /admin), PID file, graceful shutdown. 30 new tests (119 total).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MoltBot Service
2026-02-13 12:42:28 +00:00
parent 339866baa1
commit 6cd155b71e
3 changed files with 659 additions and 0 deletions

69
src/main.py Normal file
View File

@@ -0,0 +1,69 @@
"""Echo Core — main entry point."""
import asyncio
import logging
import os
import signal
import sys
from pathlib import Path
from src.config import load_config
from src.secrets import get_secret
from src.adapters.discord_bot import create_bot
PROJECT_ROOT = Path(__file__).resolve().parent.parent
PID_FILE = PROJECT_ROOT / "echo-core.pid"
LOG_DIR = PROJECT_ROOT / "logs"
def setup_logging():
LOG_DIR.mkdir(parents=True, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
handlers=[
logging.FileHandler(LOG_DIR / "echo-core.log"),
logging.StreamHandler(sys.stderr),
],
)
def main():
setup_logging()
logger = logging.getLogger("echo-core")
token = get_secret("discord_token")
if not token:
logger.error(
"discord_token not found in keyring. "
"Run: python cli.py secrets set discord_token"
)
sys.exit(1)
config = load_config()
client = create_bot(config)
# PID file
PID_FILE.write_text(str(os.getpid()))
# Signal handlers for graceful shutdown
loop = asyncio.new_event_loop()
def handle_signal(sig, frame):
logger.info("Received signal %s, shutting down...", sig)
loop.create_task(client.close())
signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGINT, handle_signal)
try:
loop.run_until_complete(client.start(token))
except KeyboardInterrupt:
loop.run_until_complete(client.close())
finally:
PID_FILE.unlink(missing_ok=True)
logger.info("Echo Core shut down.")
if __name__ == "__main__":
main()