import { i18n } from '../i18n' import { sdk } from '../sdk' import { listGames } from '../serverApi' import type { GameRow } from '../serverApi' /** "3 Aug 2026, 14:32" — a timestamp a person reads, not an epoch they decode. */ function when(ms: number): string { return new Date(ms).toLocaleString('en-GB', { dateStyle: 'medium', timeStyle: 'short', }) } function describe(g: GameRow): string { const who = g.playerNames.join(', ') if (g.state === 'lobby') { return [ i18n('Waiting to start — nobody has played a turn yet.'), `${i18n('Seats')} (${g.playerCount}): ${who}`, `${i18n('Created')}: ${when(g.createdAt)}`, ].join('\n') } const waiting = g.status === 'finished' ? i18n('Finished — this game is over and waits on nobody.') : g.waitingOn ? `${i18n('Waiting on')}: ${g.waitingOn.name} (${i18n('seat')} ${g.waitingOn.seat})` : `${i18n('Waiting on')}: ${i18n('nobody — the Mainline Phase is running itself')}` return [ `${i18n('Players')} (${g.playerCount}): ${who}`, `${i18n('Day')} ${g.day}, ${i18n('Stage')} ${g.stage} — ${g.phase}`, waiting, `${i18n('Started')}: ${when(g.createdAt)}`, `${i18n('Last move')}: ${g.lastMoveAt === undefined ? i18n('unknown') : when(g.lastMoveAt)}`, ].join('\n') } /** * Read-only, and separate from Manage Game on purpose: this is the one you run without thinking, * so it must not be the one that can delete anything. * * `only-running` because none of this exists on disk in readable form. A save is the seed plus the * intents, so "whose turn is it" is only answerable by replaying the game through the engine — * which lives in the game repo, not in this package. The running server has already done that work * and is asked for the answer. */ export const gamesInProgress = sdk.Action.withoutInput( 'games-in-progress', async () => ({ name: i18n('Games in Progress'), description: i18n( 'List every game and lobby on this server, and where each one has got to', ), warning: null, allowedStatuses: 'only-running', group: null, visibility: 'enabled', }), async ({ effects }) => { const games = await listGames(effects) if (games.length === 0) { return { version: '1', title: i18n('Games in Progress'), message: i18n('There are no games on this server.'), result: null, } } return { version: '1', title: i18n('Games in Progress'), message: `${games.length} ${i18n('game(s) on this server. Use Manage Game to save one for later, or to end it.')}`, result: { type: 'group', value: games.map((g) => ({ type: 'single' as const, name: g.gameCode ?? g.gameId, description: null, value: describe(g), masked: false, copyable: false, qr: false, })), }, } }, )