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>
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { NextRequest } from 'next/server'
|
|
import { getCurrentUser } from '@/lib/session'
|
|
import { readRunLog, WorkerLogError } from '@/lib/worker-logs'
|
|
import { parseRunLog } from '@/lib/parse-worker-log'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
// GET /api/worker-logs/<file>.log — full parsed timeline for one run-log.
|
|
export async function GET(
|
|
_request: NextRequest,
|
|
{ params }: { params: Promise<{ name: string }> },
|
|
) {
|
|
const user = await getCurrentUser()
|
|
if (!user) {
|
|
return Response.json({ error: 'unauthorized' }, { status: 401 })
|
|
}
|
|
|
|
const { name: rawName } = await params
|
|
const name = decodeURIComponent(rawName)
|
|
|
|
try {
|
|
const raw = await readRunLog(name)
|
|
return Response.json(parseRunLog(raw, name))
|
|
} catch (err) {
|
|
if (err instanceof WorkerLogError) {
|
|
const status = err.code === 'invalid' ? 400 : err.code === 'not-found' ? 404 : 500
|
|
return Response.json({ error: err.message }, { status })
|
|
}
|
|
const message = err instanceof Error ? err.message : 'failed to read worker log'
|
|
return Response.json({ error: message }, { status: 500 })
|
|
}
|
|
}
|