import type { FastifyInstance } from 'fastify'; import { z } from 'zod'; import type { Sql } from '../db.js'; const CostQuery = z.object({ group_by: z.enum(['project', 'agent', 'day']).default('project'), }); export function registerStatsRoutes(app: FastifyInstance, sql: Sql): void { // GET /api/stats/costs — aggregate cost_tokens by project, agent, or day app.get('/api/stats/costs', async (req, reply) => { const parsed = CostQuery.safeParse(req.query); if (!parsed.success) { reply.code(400); return { error: 'invalid query', details: parsed.error.flatten() }; } const { group_by } = parsed.data; switch (group_by) { case 'project': return sql` SELECT project_id, COUNT(*)::int AS task_count, COALESCE(SUM(cost_tokens), 0)::int AS total_tokens FROM tasks WHERE cost_tokens IS NOT NULL GROUP BY project_id ORDER BY total_tokens DESC `; case 'agent': return sql` SELECT COALESCE(agent, 'native') AS agent, COUNT(*)::int AS task_count, COALESCE(SUM(cost_tokens), 0)::int AS total_tokens FROM tasks WHERE cost_tokens IS NOT NULL GROUP BY agent ORDER BY total_tokens DESC `; case 'day': return sql` SELECT DATE(created_at) AS day, COUNT(*)::int AS task_count, COALESCE(SUM(cost_tokens), 0)::int AS total_tokens FROM tasks WHERE cost_tokens IS NOT NULL GROUP BY DATE(created_at) ORDER BY day DESC LIMIT 90 `; } }); }