Ops-dashboard/app/api/worker-logs/route.ts
Janpeter Visser 7e049ebdef feat(worker-logs): add worker run-log viewer page
Nieuwe /worker-logs pagina: een tabel van de laatste N (10/25/50/100)
worker-runs met een inline detailpaneel dat de stream-json output van
Claude Code als leesbare timeline toont (system-init, assistant-tekst,
tool-calls/results, result-kaart).

- lib/parse-worker-log.ts: pure parser — summarizeRunLog (tabel) +
  parseRunLog (timeline), discriminated-union events, server-side
  truncatie van grote tool-results.
- lib/worker-logs.ts: server-only fs-toegang, leest uit WORKER_LOGS_DIR
  (read-only bind mount), naam-regex + pad-confinement, .gz support.
- app/api/worker-logs[/[name]]: GET-routes, auth-guarded, force-dynamic.
- app/worker-logs: server page + client view (tabel, N-selector,
  auto-refresh) + detail (timeline, auto-refresh tijdens in-progress run).

Vereist een read-only bind mount van /srv/scrum4me/worker-logs in de
ops-dashboard-container (docker-compose.yml + WORKER_LOGS_DIR in .env).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 01:58:03 +02:00

25 lines
893 B
TypeScript

import { NextRequest } from 'next/server'
import { getCurrentUser } from '@/lib/session'
import { listRunLogs } from '@/lib/worker-logs'
export const dynamic = 'force-dynamic'
// GET /api/worker-logs?limit=10 — newest-first run-log summaries for the table.
export async function GET(request: NextRequest) {
const user = await getCurrentUser()
if (!user) {
return Response.json({ error: 'unauthorized' }, { status: 401 })
}
const limitParam = request.nextUrl.searchParams.get('limit')
const limit = limitParam ? Number(limitParam) : 10
try {
const logs = await listRunLogs(limit)
return Response.json({ logs })
} catch (err) {
// Surfaces a missing bind mount legibly (e.g. WORKER_LOGS_DIR not mounted).
const message = err instanceof Error ? err.message : 'failed to list worker logs'
return Response.json({ error: message }, { status: 500 })
}
}