export interface Step { id: string; requirement: string; // Path (relative to the kata's spec.ts) of the authoritative test file. // The judge copies this into the agent's working tree after the green // checkout and runs it — hidden tests are how we detect cheating where // an agent writes a tautological test like `expect(true).toBe(true)`. hiddenTestFile: string; } export interface Game { id: string; // One-line summary shown on the games index and OG previews. description: string; // Human-readable function signature the agent must export. Documented // on the kata page so authors know what to build. signature: string; // The module path the hidden tests will import from. Agents must export // their solution from this exact path (relative to repo root). importPath: string; steps: Step[]; } import { readdir } from "node:fs/promises"; // Reads every kata under content/games/ and returns the loaded specs in // alphabetical order. Used to build the games index and sitemap without // hard-coding individual kata ids. export async function listGames(): Promise { let entries; try { entries = await readdir("./content/games", { withFileTypes: true }); } catch { return []; } const ids = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort(); const games: Game[] = []; for (const id of ids) { try { games.push(await loadGame(id)); } catch { // skip katas that fail to load (missing spec.ts, etc.) } } return games; } export async function loadGame(id: string): Promise { const file = Bun.file(`./content/games/${id}/spec.ts`); if (!(await file.exists())) { throw new Error(`unknown game: ${id}`); } const mod = await import(`../content/games/${id}/spec.ts`); return mod.spec as Game; }