first
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { readdir } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { createRouter } from '../../create-router';
|
||||
import { getTaskLogsDir } from '../../data-path';
|
||||
|
||||
type LogMetadata = {
|
||||
filename: string;
|
||||
taskName: string;
|
||||
taskDirName: string;
|
||||
entryName: string;
|
||||
entryType: 'file' | 'directory';
|
||||
provider: string;
|
||||
model: string;
|
||||
startedAt: string;
|
||||
completedAt: string | null;
|
||||
isError: boolean;
|
||||
};
|
||||
|
||||
export const taskLogsRouter = createRouter();
|
||||
|
||||
// GET / — list all log files (metadata only, no messages)
|
||||
taskLogsRouter.get('/', async (ctx) => {
|
||||
const email = ctx.get('user').email;
|
||||
const dir = getTaskLogsDir(email);
|
||||
|
||||
let files: string[];
|
||||
try {
|
||||
files = (await readdir(dir)).filter((f) => f.endsWith('.json'));
|
||||
} catch {
|
||||
return ctx.json([]);
|
||||
}
|
||||
|
||||
// Sort by filename descending (newest first since filenames start with timestamp)
|
||||
files.sort((a, b) => b.localeCompare(a));
|
||||
|
||||
const logs: LogMetadata[] = [];
|
||||
for (const filename of files) {
|
||||
try {
|
||||
const raw = await Bun.file(join(dir, filename)).json();
|
||||
const lastMessage = Array.isArray(raw.messages) ? raw.messages[raw.messages.length - 1] : null;
|
||||
const isError = lastMessage?.role === 'result' ? lastMessage.isError : lastMessage?.role === 'error';
|
||||
logs.push({
|
||||
filename,
|
||||
taskName: raw.taskName ?? '',
|
||||
taskDirName: raw.taskDirName ?? '',
|
||||
entryName: raw.entryName ?? '',
|
||||
entryType: raw.entryType ?? 'file',
|
||||
provider: raw.provider ?? '',
|
||||
model: raw.model ?? '',
|
||||
startedAt: raw.startedAt ?? '',
|
||||
completedAt: raw.completedAt ?? null,
|
||||
isError: !!isError,
|
||||
});
|
||||
} catch {
|
||||
// Skip unreadable files
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.json(logs);
|
||||
});
|
||||
|
||||
// GET /:filename — return full log file content
|
||||
taskLogsRouter.get('/:filename', async (ctx) => {
|
||||
const email = ctx.get('user').email;
|
||||
const filename = ctx.req.param('filename');
|
||||
|
||||
if (!filename.endsWith('.json') || filename.includes('/') || filename.includes('..')) {
|
||||
return ctx.text('Invalid filename', 400);
|
||||
}
|
||||
|
||||
const filePath = join(getTaskLogsDir(email), filename);
|
||||
|
||||
try {
|
||||
const data = await Bun.file(filePath).json();
|
||||
return ctx.json(data);
|
||||
} catch {
|
||||
return ctx.text('Not found', 404);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user