feat: v3 — fight loop, expanded challenges, FightPage ownership guard

- Add fight-loop CLI for automated mock fights with elo-based matchmaking
- Expand challenge types, scoring narrations, arenas, and mock bot pool
- FightPage "Fight again" buttons now only show for your own bot
- FightViewer async scene init, live fight polling with round counter
- Extract mock answers into separate answers module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-06 23:44:40 +00:00
co-authored by Claude Opus 4.6
parent 47d20fbe66
commit 2c0323d5fb
14 changed files with 2669 additions and 996 deletions
+15
View File
@@ -4,6 +4,7 @@ import { db, schema } from '../db/index.js'
import { eq, desc } from 'drizzle-orm'
import { ARENAS } from '../engine/arenas.js'
import { runMockFight } from '../engine/mock.js'
import { startFightLoop } from '../engine/fight-loop.js'
import { runFight, runFightAsync } from '../engine/orchestrator.js'
import { fightEvents } from '../engine/events.js'
@@ -200,6 +201,20 @@ fightsRouter.post('/fight/:botId', async (c) => {
return c.json({ fightId: 'pending', botId, opponentId, message: 'Real fight starting...' })
})
// Start a batch of mock fights (for seeding or overnight loop)
fightsRouter.post('/mock/batch/:count', async (c) => {
const count = parseInt(c.req.param('count')) || 10
const capped = Math.min(count, 500) // Safety cap
// Run in background
startFightLoop({ maxFights: capped, intervalMs: 500, matchmakingStyle: 'mixed' })
.then(() => console.log(`[botfights] batch of ${capped} fights completed`))
.catch(err => console.error('[botfights] batch error:', err))
return c.json({ message: `Started batch of ${capped} fights in background.` })
})
// SSE stream for live fight events
fightsRouter.get('/:id/stream', (c) => {
const fightId = c.req.param('id')