task logs: migrate from filesystem to postgresql; refactor sidecars into submodules

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 11:49:39 +00:00
co-authored by Claude Opus 4.6
parent 5129f7827f
commit d88fe3cac7
22 changed files with 621 additions and 545 deletions
+24 -18
View File
@@ -1,6 +1,4 @@
import { mkdir } from 'node:fs/promises';
import { join } from 'node:path';
import { getTaskLogsDir } from '@@/data-path';
import { db, schema } from 'officerdb';
import type { TaskInfo } from '@@/api/chat-types';
type ChatMessage =
@@ -18,46 +16,41 @@ type ChatMessage =
| { role: 'error'; text: string };
type TaskLog = {
userId: number;
taskName: string;
taskDirName: string;
entryName: string;
entryType: 'file' | 'directory';
provider: string;
model: string;
startedAt: string;
completedAt: string | null;
startedAt: Date;
messages: ChatMessage[];
};
type LogEntry = {
email: string;
filePath: string;
userId: number;
log: TaskLog;
};
const activeLogs = new Map<string, LogEntry>();
let logCounter = 0;
export function createTaskLog(email: string, taskInfo: TaskInfo, provider: string, model: string): string {
export function createTaskLog(userId: number, taskInfo: TaskInfo, provider: string, model: string): string {
const logId = `log_${Date.now()}_${++logCounter}`;
const dir = getTaskLogsDir(email);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `${timestamp}-${taskInfo.taskDirName}.json`;
const filePath = join(dir, filename);
const log: TaskLog = {
userId,
taskName: taskInfo.taskName,
taskDirName: taskInfo.taskDirName,
entryName: taskInfo.entryName,
entryType: taskInfo.entryType,
provider,
model,
startedAt: new Date().toISOString(),
completedAt: null,
startedAt: new Date(),
messages: [],
};
activeLogs.set(logId, { email, filePath, log });
activeLogs.set(logId, { userId, log });
return logId;
}
@@ -82,11 +75,24 @@ export async function finalizeLog(logId: string) {
const entry = activeLogs.get(logId);
if (!entry) return;
entry.log.completedAt = new Date().toISOString();
const { log } = entry;
const lastMessage = log.messages[log.messages.length - 1];
const isError = lastMessage?.role === 'result' ? lastMessage.isError : lastMessage?.role === 'error';
try {
await mkdir(join(entry.filePath, '..'), { recursive: true });
await Bun.write(entry.filePath, JSON.stringify(entry.log, null, 2));
await db.insert(schema.taskLogs).values({
userId: log.userId,
taskName: log.taskName,
taskDirName: log.taskDirName,
entryName: log.entryName,
entryType: log.entryType,
provider: log.provider,
model: log.model,
isError: !!isError,
messages: log.messages,
startedAt: log.startedAt,
completedAt: new Date(),
});
} catch (err) {
console.error('[task-logger] Failed to write log:', err);
}