Makelore 2.0 initial clean snapshot

This commit is contained in:
inman
2026-07-29 17:22:35 +08:00
commit b8ca3f8eea
694 changed files with 139782 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import { writeFile } from 'node:fs/promises';
import { dialog, ipcMain, type BrowserWindow } from 'electron';
interface TranscriptSaveRequest {
defaultPath?: unknown;
markdown?: unknown;
}
const MAX_TRANSCRIPT_MARKDOWN_BYTES = 10 * 1024 * 1024;
function safeDefaultPath(value: unknown): string {
if (typeof value !== 'string') return 'chat-transcript.md';
const fileName = value.split(/[\\/]/).filter(Boolean).at(-1)?.trim();
if (!fileName) return 'chat-transcript.md';
return fileName.toLowerCase().endsWith('.md') ? fileName : `${fileName}.md`;
}
export function registerTranscriptExportHandler(mainWindow: BrowserWindow): void {
ipcMain.handle('transcript:save', async (_event, request: TranscriptSaveRequest) => {
if (typeof request?.markdown !== 'string') {
throw new Error('Invalid transcript markdown');
}
if (Buffer.byteLength(request.markdown, 'utf8') > MAX_TRANSCRIPT_MARKDOWN_BYTES) {
throw new Error('Transcript is too large');
}
let selected: Electron.SaveDialogReturnValue;
try {
selected = await dialog.showSaveDialog(mainWindow, {
defaultPath: safeDefaultPath(request.defaultPath),
filters: [{ name: 'Markdown', extensions: ['md'] }],
});
} catch {
throw new Error('Failed to save transcript');
}
if (selected.canceled || !selected.filePath) return { status: 'cancelled' as const };
try {
await writeFile(selected.filePath, request.markdown, 'utf8');
} catch {
throw new Error('Failed to save transcript');
}
return { status: 'saved' as const };
});
}