Add forex plugin, stability fixes, and async HTTP dispatch

- Add forex plugin (Frankfurter v2 API) with rate lookups, analysis,
  DM-based alerts, and daily cron poll. Backfills 1 year of history
  on startup for moving averages and buy signal scoring.

- Fix bot hang caused by SQLite lock contention in reminder polling:
  rows cursor was held open while writing to the same DB. Collect
  results first, close cursor, then process. Same fix in milkcarton.

- Add sync retry loop so the bot reconnects after network drops
  instead of silently exiting. StopSync() for clean Ctrl+C shutdown.

- Add panic recovery to all dispatch, syncer, and cron paths.

- Make all HTTP-calling plugin commands async (goroutines) so a slow
  or dead external API cannot block the message dispatch pipeline.
  Affects: lookup, stocks, forex, anime, movies, concerts, gaming,
  retro, wotd, urls, howami.

- Extract DisplayName to Base, add db.Exec helper, convert silent
  error discards across the codebase.

- Fix UNO mercy-kill bug (eliminated bot continues playing), adventure
  DM nag spam, stats column mismatch, per-call regex/replacer allocs.

- Update README: forex commands, Finance section, 47 plugins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-03-26 09:22:02 -07:00
parent c7c1b76589
commit 9c6ded13fa
68 changed files with 5784 additions and 724 deletions

View File

@@ -377,6 +377,7 @@ var SummaryMiningSuccess = []string{
"Mining run at {location}: {ore} recovered, €{value}, no cave-ins.",
"Came back from {location} with {ore} and €{value} and a worse {tool}.",
"{ore} from {location}. €{value}. The back is filing a complaint.",
"You went mining. You tripped. You fell into the wall. You're out cold. But a rock broke free. You may have lost 8 hours. But hell, you gained {ore}. €{value}.",
}
var SummaryMiningDeath = []string{
@@ -400,6 +401,14 @@ var SummaryForagingSuccess = []string{
"Returned from {location} with {item} worth €{value} and zero injuries. Good day.",
"Clean haul from {location}. {item}, €{value}. The forest cooperated.",
"{item} from {location}. €{value}. One bear made eye contact. Moved on.",
"You went foraging. You foraged. Yep. Stuff found. Good job. What was it? Who cares? It's foraging. Does it really matter? Okay. Fine. It was {item}. €{value}.",
}
var SummaryForagingEmpty = []string{
"Wandered through {location}. Found nothing. Not even hornets.",
"{location}: searched every bush. Came home empty-handed.",
"Nothing from {location}. The forest was uncooperative today.",
"Went foraging in {location}. The forest kept its things.",
}
var SummaryForagingDeath = []string{