// Type definitions for the Electron API exposed via preload export interface ImportExecuteResult { taskId: string; totalItems: number; } export interface ImportExecutionProgress { taskId: string; phase: string; current: number; total: number; detail?: string; eta?: number; } export interface ImportCompleteResult { taskId: string; success: boolean; posts: { imported: number; skipped: number; errors: number }; media: { imported: number; skipped: number; errors: number }; pages: { imported: number; skipped: number; errors: number }; tags: { created: number; skipped: number }; } export interface ImportDefinitionData { id: string; projectId: string; name: string; wxrFilePath: string | null; uploadsFolderPath: string | null; lastAnalysisResult: unknown | null; createdAt: string; updatedAt: string; } export interface ProjectMetadata { name: string; description?: string; dataPath?: string; mainLanguage?: string; } export interface ProjectData { id: string; name: string; slug: string; description?: string; dataPath?: string; isActive: boolean; createdAt: string; updatedAt: string; } export interface PostData { id: string; projectId: string; title: string; slug: string; excerpt?: string; content: string; status: 'draft' | 'published' | 'archived'; author?: string; createdAt: string; updatedAt: string; publishedAt?: string; tags: string[]; categories: string[]; } export interface PostFilter { status?: 'draft' | 'published' | 'archived'; tags?: string[]; categories?: string[]; year?: number; month?: number; from?: string; to?: string; } export interface SearchResult { id: string; title: string; slug: string; excerpt?: string; } export interface MediaData { id: string; projectId: string; filename: string; originalName: string; mimeType: string; size: number; width?: number; height?: number; title?: string; alt?: string; caption?: string; author?: string; createdAt: string; updatedAt: string; tags: string[]; } export interface MediaFilter { tags?: string[]; year?: number; month?: number; } export interface MediaSearchResult { id: string; originalName: string; title?: string; mimeType: string; createdAt: string; } export interface TaskProgress { taskId: string; status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'; progress: number; message: string; startTime: string; endTime?: string; error?: string; } export interface SyncConfig { autoSync: boolean; syncInterval: number; } export interface SyncResult { success: boolean; pushed: number; pulled: number; conflicts: number; errors: string[]; } export interface PaginatedPostsResult { items: PostData[]; hasMore: boolean; total: number; } export interface DashboardStats { totalPosts: number; draftCount: number; publishedCount: number; archivedCount: number; } export interface TagCount { tag: string; count: number; } export interface CategoryCount { category: string; count: number; } export interface TagData { id: string; projectId: string; name: string; color?: string; createdAt: string; updatedAt: string; } export interface TagWithCount { name: string; color: string | null; count: number; } export interface DeleteTagResult { success: boolean; postsUpdated: number; } export interface MergeTagsResult { success: boolean; postsUpdated: number; tagsDeleted: number; targetTag: string; } export interface RenameTagResult { success: boolean; postsUpdated: number; oldName: string; newName: string; } export interface SyncTagsResult { discovered: number; added: string[]; } export interface GitAvailability { gitFound: boolean; version?: string; } export interface GitRepoState { isRepo: boolean; rootPath?: string; currentBranch?: string; hasRemote: boolean; } export type GitFileStatus = 'untracked' | 'modified' | 'deleted' | 'renamed' | 'staged'; export interface GitStatusFile { path: string; status: GitFileStatus; previousPath?: string; } export interface GitStatusCounts { untracked: number; modified: number; deleted: number; renamed: number; staged: number; total: number; } export interface GitStatusDto { files: GitStatusFile[]; counts: GitStatusCounts; } export interface GitInitResult { success: boolean; error?: string; code?: 'git-missing' | 'git-lfs-missing' | 'init-failed' | 'remote-failed'; } // Post-Media Link types export interface MediaLinkData { id: string; projectId: string; postId: string; mediaId: string; sortOrder: number; createdAt: string; } // Chat/AI types export interface ChatConversation { id: string; title: string; model?: string; createdAt: string; updatedAt: string; } export interface ChatMessage { id: string; conversationId: string; role: 'user' | 'assistant' | 'system' | 'tool'; content: string; toolCallId?: string; toolCalls?: string; createdAt: string; } export interface ChatModel { id: string; name: string; provider?: string; } export interface ChatReadyStatus { ready: boolean; error?: string; backend?: string; } export interface ChatApiKeyStatus { hasKey: boolean; maskedKey: string; } export interface ChatStreamDelta { conversationId: string; delta: string; } export interface ChatToolCall { conversationId: string; toolCall: { name: string; arguments: Record; }; } export interface ChatToolResult { conversationId: string; result: unknown; } export interface ChatTitleUpdate { conversationId: string; title: string; } export interface ElectronAPI { git: { checkAvailability: () => Promise; getRepoState: (projectPath: string) => Promise; getStatus: (projectPath: string) => Promise; init: (projectPath: string, remoteUrl?: string) => Promise; }; projects: { create: (data: { name: string; description?: string; slug?: string; dataPath?: string }) => Promise; update: (id: string, data: Partial) => Promise; delete: (id: string) => Promise; deleteWithData: (id: string) => Promise; get: (id: string) => Promise; getAll: () => Promise; getActive: () => Promise; setActive: (id: string) => Promise; }; posts: { create: (data: Partial) => Promise; update: (id: string, data: Partial) => Promise; delete: (id: string) => Promise; get: (id: string) => Promise; getAll: (options?: { limit?: number; offset?: number }) => Promise; getByStatus: (status: string) => Promise; publish: (id: string) => Promise; discard: (id: string) => Promise; hasPublishedVersion: (id: string) => Promise; rebuildFromFiles: () => Promise; reindexText: () => Promise; search: (query: string) => Promise; filter: (filter: PostFilter) => Promise; getTags: () => Promise; getCategories: () => Promise; getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>; getDashboardStats: () => Promise; getTagsWithCounts: () => Promise; getCategoriesWithCounts: () => Promise; getLinksTo: (id: string) => Promise; getLinkedBy: (id: string) => Promise; rebuildLinks: () => Promise; isSlugAvailable: (slug: string, excludePostId?: string) => Promise; generateUniqueSlug: (title: string, excludePostId?: string) => Promise; }; media: { import: (sourcePath: string, metadata?: Partial) => Promise; importDialog: () => Promise; update: (id: string, data: Partial) => Promise; replaceFile: (id: string, newSourcePath: string) => Promise; replaceFileDialog: (id: string) => Promise; delete: (id: string) => Promise; get: (id: string) => Promise; getUrl: (id: string) => Promise; getFilePath: (id: string) => Promise; getAll: () => Promise; rebuildFromFiles: () => Promise; reindexText: () => Promise; getThumbnail: (id: string, size?: 'small' | 'medium' | 'large') => Promise; regenerateThumbnails: (id: string) => Promise | null>; regenerateMissingThumbnails: () => Promise<{ processed: number; generated: number; failed: number }>; filter: (filter: MediaFilter) => Promise; search: (query: string) => Promise; getByYearMonth: () => Promise<{ year: number; month: number; count: number }[]>; getTags: () => Promise; getTagsWithCounts: () => Promise; }; postMedia: { link: (postId: string, mediaId: string) => Promise; unlink: (postId: string, mediaId: string) => Promise; linkMany: (postId: string, mediaIds: string[]) => Promise<{ linked: string[]; skipped: string[] }>; unlinkMany: (postId: string, mediaIds: string[]) => Promise<{ unlinked: string[] }>; getForPost: (postId: string) => Promise; getForMedia: (mediaId: string) => Promise; getMediaDataForPost: (postId: string) => Promise>; reorder: (postId: string, mediaIds: string[]) => Promise; isLinked: (postId: string, mediaId: string) => Promise; import: (postId: string, filePath: string) => Promise; rebuild: () => Promise; }; sync: { configure: (config: SyncConfig) => Promise; start: (direction?: 'push' | 'pull' | 'bidirectional') => Promise; getStatus: () => Promise<'idle' | 'syncing' | 'error'>; isConfigured: () => Promise; getPendingCount: () => Promise<{ posts: number; media: number }>; getLog: (limit?: number) => Promise; stopAutoSync: () => Promise; }; tasks: { getAll: () => Promise; getRunning: () => Promise; cancel: (taskId: string) => Promise; clearCompleted: () => Promise; }; app: { getDataPaths: () => Promise<{ database: string; posts: string; media: string }>; openFolder: (folderPath: string) => Promise; showItemInFolder: (itemPath: string) => Promise; selectFolder: (title?: string) => Promise; getDefaultProjectPath: (projectId: string) => Promise; readProjectMetadata: (folderPath: string) => Promise<{ name?: string; description?: string; mainLanguage?: string } | null>; }; meta: { getTags: () => Promise; getCategories: () => Promise; addTag: (tag: string) => Promise; removeTag: (tag: string) => Promise; addCategory: (category: string) => Promise; removeCategory: (category: string) => Promise; syncOnStartup: () => Promise<{ tags: string[]; categories: string[]; projectMetadata: ProjectMetadata | null }>; getProjectMetadata: () => Promise; setProjectMetadata: (metadata: { name: string; description?: string }) => Promise; updateProjectMetadata: (updates: { name?: string; description?: string; dataPath?: string; mainLanguage?: string }) => Promise; }; tags: { getAll: () => Promise; getWithCounts: () => Promise; get: (id: string) => Promise; getByName: (name: string) => Promise; create: (data: { name: string; color?: string }) => Promise; update: (id: string, data: { name?: string; color?: string | null }) => Promise; delete: (id: string) => Promise; merge: (sourceTagIds: string[], targetTagId: string) => Promise; rename: (id: string, newName: string) => Promise; getPostsWithTag: (tagId: string) => Promise; syncFromPosts: () => Promise; }; import: { selectAndAnalyze: (uploadsFolder?: string) => Promise; analyzeFile: (filePath: string, uploadsFolder?: string) => Promise; selectUploadsFolder: () => Promise; execute: (reportJson: string, uploadsFolder?: string) => Promise; onProgress: (callback: (data: { step: string; detail?: string }) => void) => () => void; onExecutionProgress: (callback: (data: ImportExecutionProgress) => void) => () => void; onComplete: (callback: (data: ImportCompleteResult) => void) => () => void; }; importDefinitions: { create: (name?: string) => Promise; get: (id: string) => Promise; getAll: () => Promise; update: (id: string, updates: Partial>) => Promise; delete: (id: string) => Promise; onNameUpdated: (callback: (data: { definitionId: string; name: string }) => void) => () => void; }; metadataDiff: { getStats: () => Promise<{ totalPosts: number; publishedPosts: number; draftPosts: number; totalMedia: number; }>; scan: () => Promise<{ totalScanned: number; postsWithDifferences: number; differences: Array<{ postId: string; title: string; slug: string; filePath?: string; hasDifferences: boolean; differences: Record; }>; groups: Array<{ field: string; label: string; posts: Array<{ postId: string; title: string; slug: string; dbValue: unknown; fileValue: unknown; }>; }>; }>; syncDbToFile: (postIds: string[], groupLabel: string) => Promise<{ success: number; failed: number }>; syncFileToDb: (postIds: string[], field: string, groupLabel: string) => Promise<{ success: number; failed: number }>; }; chat: { // API Key Management checkReady: () => Promise; validateApiKey: (apiKey: string) => Promise<{ isValid: boolean; models: ChatModel[] }>; setApiKey: (apiKey: string) => Promise<{ success: boolean; error?: string }>; getApiKey: () => Promise; // Settings getAvailableModels: () => Promise<{ success: boolean; models?: ChatModel[]; selectedModel?: string; error?: string }>; setDefaultModel: (modelId: string) => Promise<{ success: boolean; error?: string }>; getSystemPrompt: () => Promise<{ success: boolean; prompt?: string; error?: string }>; setSystemPrompt: (prompt: string) => Promise<{ success: boolean; error?: string }>; // Conversations getConversations: () => Promise; createConversation: (title?: string, model?: string) => Promise; getConversation: (id: string) => Promise; updateConversation: (id: string, updates: { title?: string; model?: string }) => Promise; deleteConversation: (id: string) => Promise; // Messaging sendMessage: (conversationId: string, message: string) => Promise<{ success: boolean; message?: string; error?: string }>; abortMessage: (conversationId: string) => Promise; getHistory: (conversationId: string) => Promise; clearMessages: (conversationId: string) => Promise; setConversationModel: (conversationId: string, modelId: string) => Promise; // Taxonomy Analysis analyzeTaxonomy: (categories: Array<{ name: string; slug: string; existsInProject: boolean }>, tags: Array<{ name: string; slug: string; existsInProject: boolean }>, modelId: string) => Promise<{ success: boolean; categoryMappings?: Record; tagMappings?: Record; error?: string }>; // Media Analysis analyzeMediaImage: (mediaId: string, language?: string) => Promise<{ success: boolean; title?: string; alt?: string; caption?: string; error?: string }>; // Event listeners for streaming/progress onStreamDelta: (callback: (data: ChatStreamDelta) => void) => () => void; onToolCall: (callback: (data: ChatToolCall) => void) => () => void; onToolResult: (callback: (data: ChatToolResult) => void) => () => void; onTitleUpdated: (callback: (data: ChatTitleUpdate) => void) => () => void; }; on: (channel: string, callback: (...args: unknown[]) => void) => () => void; once: (channel: string, callback: (...args: unknown[]) => void) => void; }