import type { ChatSession, Message, Contact, ContactInfo, ChatRecordItem } from './models' export interface SessionChatWindowOpenOptions { source?: 'chat' | 'export' initialDisplayName?: string initialAvatarUrl?: string initialContactType?: ContactInfo['type'] } export interface TokenUsage { promptTokens?: number completionTokens?: number totalTokens?: number } export interface AgentRuntimeStatus { phase: 'idle' | 'thinking' | 'tool_running' | 'responding' | 'completed' | 'error' | 'aborted' round?: number currentTool?: string toolsUsed?: number updatedAt: number totalUsage?: TokenUsage } export interface AgentStreamChunk { runId: string conversationId?: string type: 'content' | 'think' | 'tool_start' | 'tool_result' | 'status' | 'done' | 'error' content?: string thinkTag?: string thinkDurationMs?: number toolName?: string toolParams?: Record toolResult?: unknown error?: string isFinished?: boolean usage?: TokenUsage status?: AgentRuntimeStatus } export interface ElectronAPI { window: { minimize: () => void maximize: () => void isMaximized: () => Promise onMaximizeStateChanged: (callback: (isMaximized: boolean) => void) => () => void close: () => void onCloseConfirmRequested: (callback: (payload: { canMinimizeToTray: boolean }) => void) => () => void respondCloseConfirm: (action: 'tray' | 'quit' | 'cancel') => Promise openAgreementWindow: () => Promise completeOnboarding: () => Promise openOnboardingWindow: () => Promise setTitleBarOverlay: (options: { symbolColor: string }) => void openVideoPlayerWindow: (videoPath: string, videoWidth?: number, videoHeight?: number) => Promise resizeToFitVideo: (videoWidth: number, videoHeight: number) => Promise openImageViewerWindow: (imagePath: string, liveVideoPath?: string) => Promise openChatHistoryWindow: (sessionId: string, messageId: number) => Promise openChatHistoryPayloadWindow: (payload: { sessionId: string; title?: string; recordList: ChatRecordItem[] }) => Promise getChatHistoryPayload: (payloadId: string) => Promise<{ success: boolean; payload?: { sessionId: string; title?: string; recordList: ChatRecordItem[] }; error?: string }> openSessionChatWindow: (sessionId: string, options?: SessionChatWindowOpenOptions) => Promise } config: { get: (key: string) => Promise set: (key: string, value: unknown) => Promise clear: () => Promise } auth: { hello: (message?: string) => Promise<{ success: boolean; error?: string }> verifyEnabled: () => Promise unlock: (password: string) => Promise<{ success: boolean; error?: string }> enableLock: (password: string) => Promise<{ success: boolean; error?: string }> disableLock: (password: string) => Promise<{ success: boolean; error?: string }> changePassword: (oldPassword: string, newPassword: string) => Promise<{ success: boolean; error?: string }> setHelloSecret: (password: string) => Promise<{ success: boolean }> clearHelloSecret: () => Promise<{ success: boolean }> isLockMode: () => Promise } dialog: { openFile: (options?: Electron.OpenDialogOptions) => Promise openDirectory: (options?: Electron.OpenDialogOptions) => Promise saveFile: (options?: Electron.SaveDialogOptions) => Promise } shell: { openPath: (path: string) => Promise openExternal: (url: string) => Promise } app: { getDownloadsPath: () => Promise getVersion: () => Promise getLaunchAtStartupStatus: () => Promise<{ enabled: boolean; supported: boolean; reason?: string }> setLaunchAtStartup: (enabled: boolean) => Promise<{ success: boolean enabled: boolean supported: boolean reason?: string error?: string }> checkForUpdates: () => Promise<{ hasUpdate: boolean; version?: string; releaseNotes?: string }> downloadAndInstall: () => Promise ignoreUpdate: (version: string) => Promise<{ success: boolean }> onDownloadProgress: (callback: (progress: number) => void) => () => void onUpdateAvailable: (callback: (info: { version: string; releaseNotes: string }) => void) => () => void } notification: { show: (data: { title: string; content: string; avatarUrl?: string; sessionId: string }) => Promise<{ success?: boolean; error?: string } | void> close: () => Promise click: (sessionId: string) => void ready: () => void resize: (width: number, height: number) => void onShow: (callback: (event: any, data: any) => void) => () => void onNavigateToSession: (callback: (sessionId: string) => void) => () => void } log: { getPath: () => Promise read: () => Promise<{ success: boolean; content?: string; error?: string }> clear: () => Promise<{ success: boolean; error?: string }> debug: (data: any) => void } diagnostics: { getExportCardLogs: (options?: { limit?: number }) => Promise<{ logs: Array<{ id: string ts: number source: 'frontend' | 'main' | 'backend' | 'worker' level: 'debug' | 'info' | 'warn' | 'error' message: string traceId?: string stepId?: string stepName?: string status?: 'running' | 'done' | 'failed' | 'timeout' durationMs?: number data?: Record }> activeSteps: Array<{ traceId: string stepId: string stepName: string source: 'frontend' | 'main' | 'backend' | 'worker' elapsedMs: number stallMs: number startedAt: number lastUpdatedAt: number message?: string }> summary: { totalLogs: number activeStepCount: number errorCount: number warnCount: number timeoutCount: number lastUpdatedAt: number } }> clearExportCardLogs: () => Promise<{ success: boolean }> exportExportCardLogs: (payload: { filePath: string frontendLogs?: unknown[] }) => Promise<{ success: boolean filePath?: string summaryPath?: string count?: number error?: string }> } dbPath: { autoDetect: () => Promise<{ success: boolean; path?: string; error?: string }> scanWxids: (rootPath: string) => Promise scanWxidCandidates: (rootPath: string) => Promise getDefault: () => Promise } wcdb: { testConnection: (dbPath: string, hexKey: string, wxid: string) => Promise<{ success: boolean; error?: string; sessionCount?: number }> open: (dbPath: string, hexKey: string, wxid: string) => Promise close: () => Promise } key: { autoGetDbKey: () => Promise<{ success: boolean; key?: string; error?: string; logs?: string[] }> autoGetImageKey: (manualDir?: string, wxid?: string) => Promise<{ success: boolean; xorKey?: number; aesKey?: string; error?: string }> scanImageKeyFromMemory: (userDir: string) => Promise<{ success: boolean; xorKey?: number; aesKey?: string; error?: string }> onDbKeyStatus: (callback: (payload: { message: string; level: number }) => void) => () => void onImageKeyStatus: (callback: (payload: { message: string }) => void) => () => void } chat: { connect: () => Promise<{ success: boolean; error?: string }> getSessions: () => Promise<{ success: boolean; sessions?: ChatSession[]; error?: string }> getSessionStatuses: (usernames: string[]) => Promise<{ success: boolean map?: Record error?: string }> getExportTabCounts: () => Promise<{ success: boolean counts?: { private: number group: number official: number former_friend: number } error?: string }> getContactTypeCounts: () => Promise<{ success: boolean counts?: { private: number group: number official: number former_friend: number } error?: string }> getSessionMessageCounts: (sessionIds: string[]) => Promise<{ success: boolean counts?: Record error?: string }> enrichSessionsContactInfo: ( usernames: string[], options?: { skipDisplayName?: boolean; onlyMissingAvatar?: boolean } ) => Promise<{ success: boolean contacts?: Record error?: string }> getMessages: (sessionId: string, offset?: number, limit?: number, startTime?: number, endTime?: number, ascending?: boolean) => Promise<{ success: boolean; messages?: Message[]; hasMore?: boolean; nextOffset?: number; error?: string }> getLatestMessages: (sessionId: string, limit?: number) => Promise<{ success: boolean messages?: Message[] hasMore?: boolean nextOffset?: number error?: string }> getNewMessages: (sessionId: string, minTime: number, limit?: number) => Promise<{ success: boolean messages?: Message[] error?: string }> getCachedMessages: (sessionId: string) => Promise<{ success: boolean messages?: Message[] error?: string }> clearCurrentAccountData: (options: { clearCache?: boolean; clearExports?: boolean }) => Promise<{ success: boolean removedPaths?: string[] warning?: string error?: string }> getContact: (username: string) => Promise getContactAvatar: (username: string) => Promise<{ avatarUrl?: string; displayName?: string } | null> updateMessage: (sessionId: string, localId: number, createTime: number, newContent: string) => Promise<{ success: boolean; error?: string }> deleteMessage: (sessionId: string, localId: number, createTime: number, dbPathHint?: string) => Promise<{ success: boolean; error?: string }> checkAntiRevokeTriggers: (sessionIds: string[]) => Promise<{ success: boolean rows?: Array<{ sessionId: string; success: boolean; installed?: boolean; error?: string }> error?: string }> installAntiRevokeTriggers: (sessionIds: string[]) => Promise<{ success: boolean rows?: Array<{ sessionId: string; success: boolean; alreadyInstalled?: boolean; error?: string }> error?: string }> uninstallAntiRevokeTriggers: (sessionIds: string[]) => Promise<{ success: boolean rows?: Array<{ sessionId: string; success: boolean; error?: string }> error?: string }> resolveTransferDisplayNames: (chatroomId: string, payerUsername: string, receiverUsername: string) => Promise<{ payerName: string; receiverName: string }> getContacts: (options?: { lite?: boolean }) => Promise<{ success: boolean contacts?: ContactInfo[] error?: string }> getMyAvatarUrl: () => Promise<{ success: boolean; avatarUrl?: string; error?: string }> downloadEmoji: (cdnUrl: string, md5?: string) => Promise<{ success: boolean; localPath?: string; error?: string }> searchMessages: (keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number) => Promise<{ success: boolean; messages?: Message[]; error?: string }> close: () => Promise getSessionDetail: (sessionId: string) => Promise<{ success: boolean detail?: { wxid: string displayName: string remark?: string nickName?: string alias?: string avatarUrl?: string messageCount: number firstMessageTime?: number latestMessageTime?: number messageTables: { dbName: string; tableName: string; count: number }[] } error?: string }> getSessionDetailFast: (sessionId: string) => Promise<{ success: boolean detail?: { wxid: string displayName: string remark?: string nickName?: string alias?: string avatarUrl?: string messageCount: number } error?: string }> getSessionDetailExtra: (sessionId: string) => Promise<{ success: boolean detail?: { firstMessageTime?: number latestMessageTime?: number messageTables: { dbName: string; tableName: string; count: number }[] } error?: string }> getExportSessionStats: ( sessionIds: string[], options?: { includeRelations?: boolean forceRefresh?: boolean allowStaleCache?: boolean preferAccurateSpecialTypes?: boolean cacheOnly?: boolean } ) => Promise<{ success: boolean data?: Record cache?: Record needsRefresh?: string[] error?: string }> getGroupMyMessageCountHint: (chatroomId: string) => Promise<{ success: boolean count?: number updatedAt?: number source?: 'memory' | 'disk' error?: string }> getImageData: (sessionId: string, msgId: string) => Promise<{ success: boolean; data?: string; error?: string }> getVoiceData: (sessionId: string, msgId: string, createTime?: number, serverId?: string | number) => Promise<{ success: boolean; data?: string; error?: string }> getAllVoiceMessages: (sessionId: string) => Promise<{ success: boolean; messages?: Message[]; error?: string }> getAllImageMessages: (sessionId: string) => Promise<{ success: boolean images?: { imageMd5?: string; imageDatName?: string; createTime?: number }[] error?: string }> getMessageDates: (sessionId: string) => Promise<{ success: boolean; dates?: string[]; error?: string }> getMessageDateCounts: (sessionId: string) => Promise<{ success: boolean; counts?: Record; error?: string }> getResourceMessages: (options?: { sessionId?: string types?: Array<'image' | 'video' | 'voice' | 'file'> beginTimestamp?: number endTimestamp?: number limit?: number offset?: number }) => Promise<{ success: boolean items?: Array total?: number hasMore?: boolean error?: string }> getMediaStream: (options?: { sessionId?: string mediaType?: 'image' | 'video' | 'all' beginTimestamp?: number endTimestamp?: number limit?: number offset?: number }) => Promise<{ success: boolean items?: Array<{ sessionId: string sessionDisplayName?: string mediaType: 'image' | 'video' localId: number serverId?: string createTime: number localType: number senderUsername?: string isSend?: number | null imageMd5?: string imageDatName?: string videoMd5?: string content?: string }> hasMore?: boolean nextOffset?: number error?: string }> resolveVoiceCache: (sessionId: string, msgId: string) => Promise<{ success: boolean; hasCache: boolean; data?: string }> getVoiceTranscript: (sessionId: string, msgId: string, createTime?: number) => Promise<{ success: boolean; transcript?: string; error?: string }> onVoiceTranscriptPartial: (callback: (payload: { sessionId?: string; msgId: string; createTime?: number; text: string }) => void) => () => void getMessage: (sessionId: string, localId: number) => Promise<{ success: boolean; message?: Message; error?: string }> getMyFootprintStats: ( beginTimestamp: number, endTimestamp: number, options?: { myWxid?: string privateSessionIds?: string[] groupSessionIds?: string[] mentionLimit?: number privateLimit?: number mentionMode?: 'text_at_me' | string } ) => Promise<{ success: boolean data?: { summary: { private_inbound_people: number private_replied_people: number private_outbound_people: number private_reply_rate: number mention_count: number mention_group_count: number } private_sessions: Array<{ session_id: string incoming_count: number outgoing_count: number replied: boolean first_incoming_ts: number first_reply_ts: number latest_ts: number anchor_local_id: number anchor_create_time: number displayName?: string avatarUrl?: string }> private_segments: Array<{ session_id: string segment_index: number start_ts: number end_ts: number duration_sec: number incoming_count: number outgoing_count: number message_count: number replied: boolean first_incoming_ts: number first_reply_ts: number latest_ts: number anchor_local_id: number anchor_create_time: number displayName?: string avatarUrl?: string }> mentions: Array<{ session_id: string local_id: number create_time: number sender_username: string message_content: string source: string sessionDisplayName?: string senderDisplayName?: string senderAvatarUrl?: string }> mention_groups: Array<{ session_id: string count: number latest_ts: number displayName?: string avatarUrl?: string }> diagnostics: { truncated: boolean scanned_dbs: number elapsed_ms: number } } error?: string }> exportMyFootprint: ( beginTimestamp: number, endTimestamp: number, format: 'csv' | 'json', filePath: string ) => Promise<{ success: boolean filePath?: string error?: string }> getSchema: (payload?: { sessionId?: string }) => Promise<{ success: boolean schema?: { generatedAt: number sources: Array<{ kind: 'message' | 'contact' | 'biz' path: string | null label: string tables: Array<{ name: string; columns: string[] }> }> } schemaText?: string error?: string }> executeSQL: (payload: { kind: 'message' | 'contact' | 'biz' path?: string | null sql: string limit?: number }) => Promise<{ success: boolean rows?: Record[] columns?: string[] total?: number error?: string }> onWcdbChange: (callback: (event: any, data: { type: string; json: string }) => void) => () => void } biz: { listAccounts: (account?: string) => Promise listMessages: (username: string, account?: string, limit?: number, offset?: number) => Promise listPayRecords: (account?: string, limit?: number, offset?: number) => Promise } image: { decrypt: (payload: { sessionId?: string; imageMd5?: string; imageDatName?: string; force?: boolean }) => Promise<{ success: boolean; localPath?: string; liveVideoPath?: string; error?: string }> resolveCache: (payload: { sessionId?: string imageMd5?: string imageDatName?: string disableUpdateCheck?: boolean allowCacheIndex?: boolean }) => Promise<{ success: boolean; localPath?: string; hasUpdate?: boolean; liveVideoPath?: string; error?: string }> resolveCacheBatch: ( payloads: Array<{ sessionId?: string; imageMd5?: string; imageDatName?: string }>, options?: { disableUpdateCheck?: boolean; allowCacheIndex?: boolean } ) => Promise<{ success: boolean rows?: Array<{ success: boolean; localPath?: string; hasUpdate?: boolean; error?: string }> error?: string }> preload: ( payloads: Array<{ sessionId?: string; imageMd5?: string; imageDatName?: string }>, options?: { allowDecrypt?: boolean; allowCacheIndex?: boolean } ) => Promise onUpdateAvailable: (callback: (payload: { cacheKey: string; imageMd5?: string; imageDatName?: string }) => void) => () => void onCacheResolved: (callback: (payload: { cacheKey: string; imageMd5?: string; imageDatName?: string; localPath: string }) => void) => () => void onDecryptProgress: (callback: (payload: { cacheKey: string imageMd5?: string imageDatName?: string stage: 'queued' | 'locating' | 'decrypting' | 'writing' | 'done' | 'failed' progress: number status: 'running' | 'done' | 'error' message?: string }) => void) => () => void } video: { getVideoInfo: (videoMd5: string, options?: { includePoster?: boolean; posterFormat?: 'dataUrl' | 'fileUrl' }) => Promise<{ success: boolean exists: boolean videoUrl?: string coverUrl?: string thumbUrl?: string error?: string }> parseVideoMd5: (content: string) => Promise<{ success: boolean md5?: string error?: string }> } analytics: { getOverallStatistics: (force?: boolean) => Promise<{ success: boolean data?: { totalMessages: number textMessages: number imageMessages: number voiceMessages: number videoMessages: number emojiMessages: number otherMessages: number sentMessages: number receivedMessages: number firstMessageTime: number | null lastMessageTime: number | null activeDays: number messageTypeCounts: Record } error?: string }> getContactRankings: (limit?: number, beginTimestamp?: number, endTimestamp?: number) => Promise<{ success: boolean data?: Array<{ username: string displayName: string avatarUrl?: string wechatId?: string messageCount: number sentCount: number receivedCount: number lastMessageTime: number | null }> error?: string }> getTimeDistribution: () => Promise<{ success: boolean data?: { hourlyDistribution: Record weekdayDistribution: Record monthlyDistribution: Record } error?: string }> getExcludedUsernames: () => Promise<{ success: boolean data?: string[] error?: string }> setExcludedUsernames: (usernames: string[]) => Promise<{ success: boolean data?: string[] error?: string }> getExcludeCandidates: () => Promise<{ success: boolean data?: Array<{ username: string displayName: string avatarUrl?: string wechatId?: string }> error?: string }> onProgress: (callback: (payload: { status: string; progress: number }) => void) => () => void } cache: { clearAnalytics: () => Promise<{ success: boolean; error?: string }> clearImages: () => Promise<{ success: boolean; error?: string }> clearAll: () => Promise<{ success: boolean; error?: string }> } groupAnalytics: { getGroupChats: () => Promise<{ success: boolean data?: Array<{ username: string displayName: string memberCount: number avatarUrl?: string }> error?: string }> getGroupMembers: (chatroomId: string) => Promise<{ success: boolean data?: Array<{ username: string displayName: string avatarUrl?: string nickname?: string alias?: string remark?: string groupNickname?: string isOwner?: boolean }> error?: string }> getGroupMembersPanelData: ( chatroomId: string, options?: { forceRefresh?: boolean; includeMessageCounts?: boolean } ) => Promise<{ success: boolean data?: Array<{ username: string displayName: string avatarUrl?: string nickname?: string alias?: string remark?: string groupNickname?: string isOwner?: boolean isFriend: boolean messageCount: number }> fromCache?: boolean updatedAt?: number error?: string }> getGroupMessageRanking: (chatroomId: string, limit?: number, startTime?: number, endTime?: number) => Promise<{ success: boolean data?: Array<{ member: { username: string displayName: string avatarUrl?: string } messageCount: number }> error?: string }> getGroupActiveHours: (chatroomId: string, startTime?: number, endTime?: number) => Promise<{ success: boolean data?: { hourlyDistribution: Record } error?: string }> getGroupMediaStats: (chatroomId: string, startTime?: number, endTime?: number) => Promise<{ success: boolean data?: { typeCounts: Array<{ type: number name: string count: number }> total: number } error?: string }> getGroupMemberAnalytics: (chatroomId: string, memberUsername: string, startTime?: number, endTime?: number) => Promise<{ success: boolean data?: { statistics: { totalMessages: number textMessages: number imageMessages: number voiceMessages: number videoMessages: number emojiMessages: number otherMessages: number sentMessages: number receivedMessages: number firstMessageTime: number | null lastMessageTime: number | null activeDays: number messageTypeCounts: Record } timeDistribution: Record } error?: string }> getGroupMemberMessages: ( chatroomId: string, memberUsername: string, options?: { startTime?: number; endTime?: number; limit?: number; cursor?: number } ) => Promise<{ success: boolean data?: { messages: Message[] hasMore: boolean nextCursor: number } error?: string }> exportGroupMembers: (chatroomId: string, outputPath: string) => Promise<{ success: boolean count?: number error?: string }> exportGroupMemberMessages: ( chatroomId: string, memberUsername: string, outputPath: string, startTime?: number, endTime?: number ) => Promise<{ success: boolean count?: number error?: string }> } annualReport: { getAvailableYears: () => Promise<{ success: boolean data?: number[] error?: string }> startAvailableYearsLoad: () => Promise<{ success: boolean taskId?: string reused?: boolean snapshot?: { years?: number[] done: boolean error?: string canceled?: boolean strategy?: 'cache' | 'native' | 'hybrid' phase?: 'cache' | 'native' | 'scan' | 'done' statusText?: string nativeElapsedMs?: number scanElapsedMs?: number totalElapsedMs?: number switched?: boolean nativeTimedOut?: boolean } error?: string }> cancelAvailableYearsLoad: (taskId: string) => Promise<{ success: boolean error?: string }> generateReport: (year: number) => Promise<{ success: boolean data?: { year: number totalMessages: number totalFriends: number coreFriends: Array<{ username: string displayName: string avatarUrl?: string messageCount: number sentCount: number receivedCount: number }> monthlyTopFriends: Array<{ month: number displayName: string avatarUrl?: string messageCount: number }> peakDay: { date: string messageCount: number topFriend?: string topFriendCount?: number } | null longestStreak: { friendName: string days: number startDate: string endDate: string } | null activityHeatmap: { data: number[][] } midnightKing: { displayName: string count: number percentage: number } | null selfAvatarUrl?: string mutualFriend: { displayName: string avatarUrl?: string sentCount: number receivedCount: number ratio: number } | null socialInitiative: { initiatedChats: number receivedChats: number initiativeRate: number } | null responseSpeed: { avgResponseTime: number fastestFriend: string fastestTime: number } | null topPhrases: Array<{ phrase: string count: number }> snsStats?: { totalPosts: number typeCounts?: Record topLikers: { username: string; displayName: string; avatarUrl?: string; count: number }[] topLiked: { username: string; displayName: string; avatarUrl?: string; count: number }[] } lostFriend: { username: string displayName: string avatarUrl?: string earlyCount: number lateCount: number periodDesc: string } | null } error?: string }> exportImages: (payload: { baseDir: string; folderName: string; images: Array<{ name: string; dataUrl: string }> }) => Promise<{ success: boolean dir?: string error?: string }> onAvailableYearsProgress: (callback: (payload: { taskId: string years?: number[] done: boolean error?: string canceled?: boolean strategy?: 'cache' | 'native' | 'hybrid' phase?: 'cache' | 'native' | 'scan' | 'done' statusText?: string nativeElapsedMs?: number scanElapsedMs?: number totalElapsedMs?: number switched?: boolean nativeTimedOut?: boolean }) => void) => () => void onProgress: (callback: (payload: { status: string; progress: number }) => void) => () => void } dualReport: { generateReport: (payload: { friendUsername: string; year: number }) => Promise<{ success: boolean data?: { year: number selfName: string selfAvatarUrl?: string friendUsername: string friendName: string friendAvatarUrl?: string firstChat: { createTime: number createTimeStr: string content: string isSentByMe: boolean senderUsername?: string } | null firstChatMessages?: Array<{ content: string isSentByMe: boolean createTime: number createTimeStr: string }> yearFirstChat?: { createTime: number createTimeStr: string content: string isSentByMe: boolean friendName: string firstThreeMessages: Array<{ content: string isSentByMe: boolean createTime: number createTimeStr: string }> } | null stats: { totalMessages: number totalWords: number imageCount: number voiceCount: number emojiCount: number myTopEmojiMd5?: string friendTopEmojiMd5?: string myTopEmojiUrl?: string friendTopEmojiUrl?: string myTopEmojiCount?: number friendTopEmojiCount?: number topPhrases: Array<{ phrase: string; count: number }> myExclusivePhrases: Array<{ phrase: string; count: number }> friendExclusivePhrases: Array<{ phrase: string; count: number }> heatmap?: number[][] initiative?: { initiated: number; received: number } response?: { avg: number; fastest: number; slowest?: number; count: number } monthly?: Record streak?: { days: number; startDate: string; endDate: string } } topPhrases: Array<{ phrase: string; count: number }> myExclusivePhrases: Array<{ phrase: string; count: number }> friendExclusivePhrases: Array<{ phrase: string; count: number }> heatmap?: number[][] initiative?: { initiated: number; received: number } response?: { avg: number; fastest: number; slowest?: number; count: number } monthly?: Record streak?: { days: number; startDate: string; endDate: string } } error?: string }> onProgress: (callback: (payload: { status: string; progress: number }) => void) => () => void } export: { getExportStats: (sessionIds: string[], options: any) => Promise<{ totalMessages: number voiceMessages: number cachedVoiceCount: number needTranscribeCount: number mediaMessages: number estimatedSeconds: number sessions: Array<{ sessionId: string; displayName: string; totalCount: number; voiceCount: number }> }> exportSessions: (sessionIds: string[], outputDir: string, options: ExportOptions) => Promise<{ success: boolean successCount?: number failCount?: number pendingSessionIds?: string[] successSessionIds?: string[] failedSessionIds?: string[] error?: string }> exportSession: (sessionId: string, outputPath: string, options: ExportOptions) => Promise<{ success: boolean error?: string }> exportContacts: (outputDir: string, options: { format: 'json' | 'csv' | 'vcf'; exportAvatars: boolean; contactTypes: { friends: boolean; groups: boolean; officials: boolean }; selectedUsernames?: string[] }) => Promise<{ success: boolean successCount?: number error?: string }> onProgress: (callback: (payload: ExportProgress) => void) => () => void } whisper: { downloadModel: () => Promise<{ success: boolean; modelPath?: string; tokensPath?: string; error?: string }> getModelStatus: () => Promise<{ success: boolean; exists?: boolean; modelPath?: string; tokensPath?: string; sizeBytes?: number; error?: string }> onDownloadProgress: (callback: (payload: { modelName: string; downloadedBytes: number; totalBytes?: number; percent?: number }) => void) => () => void } sns: { getTimeline: (limit: number, offset: number, usernames?: string[], keyword?: string, startTime?: number, endTime?: number) => Promise<{ success: boolean timeline?: Array<{ id: string username: string nickname: string avatarUrl?: string createTime: number contentDesc: string type?: number media: Array<{ url: string thumb: string md5?: string token?: string key?: string encIdx?: string livePhoto?: { url: string thumb: string md5?: string token?: string key?: string encIdx?: string } }> likes: Array comments: Array<{ id: string; nickname: string; content: string; refCommentId: string; refNickname?: string; emojis?: Array<{ url: string; md5: string; width: number; height: number; encryptUrl?: string; aesKey?: string }> }> location?: { latitude?: number longitude?: number city?: string country?: string poiName?: string poiAddress?: string poiAddressName?: string label?: string } rawXml?: string }> error?: string }> debugResource: (url: string) => Promise<{ success: boolean; status?: number; headers?: any; error?: string }> proxyImage: (payload: { url: string; key?: string | number }) => Promise<{ success: boolean; dataUrl?: string; videoPath?: string; error?: string }> downloadImage: (payload: { url: string; key?: string | number }) => Promise<{ success: boolean; data?: any; contentType?: string; error?: string }> exportTimeline: (options: { outputDir: string format: 'json' | 'html' | 'arkmejson' usernames?: string[] keyword?: string exportImages?: boolean exportLivePhotos?: boolean exportVideos?: boolean startTime?: number endTime?: number }) => Promise<{ success: boolean; filePath?: string; postCount?: number; mediaCount?: number; error?: string }> onExportProgress: (callback: (payload: { current: number; total: number; status: string }) => void) => () => void selectExportDir: () => Promise<{ canceled: boolean; filePath?: string }> getSnsUsernames: () => Promise<{ success: boolean; usernames?: string[]; error?: string }> getUserPostCounts: () => Promise<{ success: boolean; counts?: Record; error?: string }> getExportStatsFast: () => Promise<{ success: boolean; data?: { totalPosts: number; totalFriends: number; myPosts: number | null }; error?: string }> getExportStats: () => Promise<{ success: boolean; data?: { totalPosts: number; totalFriends: number; myPosts: number | null }; error?: string }> getUserPostStats: (username: string) => Promise<{ success: boolean; data?: { username: string; totalPosts: number }; error?: string }> installBlockDeleteTrigger: () => Promise<{ success: boolean; alreadyInstalled?: boolean; error?: string }> uninstallBlockDeleteTrigger: () => Promise<{ success: boolean; error?: string }> checkBlockDeleteTrigger: () => Promise<{ success: boolean; installed?: boolean; error?: string }> deleteSnsPost: (postId: string) => Promise<{ success: boolean; error?: string }> downloadEmoji: (params: { url: string; encryptUrl?: string; aesKey?: string }) => Promise<{ success: boolean; localPath?: string; error?: string }> getCacheMigrationStatus: () => Promise<{ success: boolean needed: boolean inProgress?: boolean totalFiles?: number legacyBaseDir?: string currentBaseDir?: string items?: Array<{ label: string; sourceDir: string; targetDir: string; fileCount: number }> error?: string }> startCacheMigration: () => Promise<{ success: boolean; copied?: number; skipped?: number; totalFiles?: number; message?: string; error?: string }> onCacheMigrationProgress: (callback: (payload: { status: 'running' | 'done' | 'error' phase: 'copying' | 'cleanup' | 'done' | 'error' current: number total: number copied: number skipped: number remaining: number message?: string currentItemLabel?: string }) => void) => () => void } cloud: { init: () => Promise recordPage: (pageName: string) => Promise getLogs: () => Promise } http: { start: (port?: number, host?: string) => Promise<{ success: boolean; port?: number; error?: string }> stop: () => Promise<{ success: boolean }> status: () => Promise<{ running: boolean; port: number; mediaExportPath: string }> } insight: { testConnection: () => Promise<{ success: boolean; message: string }> getTodayStats: () => Promise> triggerTest: () => Promise<{ success: boolean; message: string }> generateFootprintInsight: (payload: { rangeLabel: string summary: { private_inbound_people?: number private_replied_people?: number private_outbound_people?: number private_reply_rate?: number mention_count?: number mention_group_count?: number } privateSegments?: Array<{ displayName?: string; session_id?: string; incoming_count?: number; outgoing_count?: number; message_count?: number; replied?: boolean }> mentionGroups?: Array<{ displayName?: string; session_id?: string; count?: number }> }) => Promise<{ success: boolean; message: string; insight?: string }> } aiApi: { listConversations: (payload?: { page?: number; pageSize?: number }) => Promise<{ success: boolean conversations?: Array<{ conversationId: string title: string createdAt: number updatedAt: number lastMessageAt: number }> error?: string }> createConversation: (payload?: { title?: string }) => Promise<{ success: boolean conversationId?: string error?: string }> renameConversation: (payload: { conversationId: string; title: string }) => Promise<{ success: boolean; error?: string }> deleteConversation: (conversationId: string) => Promise<{ success: boolean; error?: string }> listMessages: (payload: { conversationId: string; limit?: number }) => Promise<{ success: boolean messages?: Array<{ messageId: string conversationId: string role: 'user' | 'assistant' | 'system' | 'tool' | string content: string intentType: string components: any[] toolTrace: any[] usage: Record error: string parentMessageId: string createdAt: number }> error?: string }> exportConversation: (payload: { conversationId: string }) => Promise<{ success: boolean conversation?: { conversationId: string; title: string; updatedAt: number } markdown?: string error?: string }> getMessageContext: (sessionId: string, messageIds: number | number[], contextSize?: number) => Promise> getSearchMessageContext: (sessionId: string, messageIds: number[], contextBefore?: number, contextAfter?: number) => Promise> getRecentMessages: (sessionId: string, filter?: { startTs?: number; endTs?: number }, limit?: number) => Promise<{ messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> total: number }> getAllRecentMessages: (sessionId: string, filter?: { startTs?: number; endTs?: number }, limit?: number) => Promise<{ messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> total: number }> getConversationBetween: ( sessionId: string, memberId1: number, memberId2: number, filter?: { startTs?: number; endTs?: number }, limit?: number ) => Promise<{ messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> total: number member1Name: string member2Name: string }> getMessagesBefore: ( sessionId: string, beforeId: number, limit?: number, filter?: { startTs?: number; endTs?: number }, senderId?: number, keywords?: string[] ) => Promise<{ messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> hasMore: boolean }> getMessagesAfter: ( sessionId: string, afterId: number, limit?: number, filter?: { startTs?: number; endTs?: number }, senderId?: number, keywords?: string[] ) => Promise<{ messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> hasMore: boolean }> searchSessions: ( sessionId: string, keywords?: string[], timeFilter?: { startTs?: number; endTs?: number }, limit?: number, previewCount?: number ) => Promise }>> getSessionMessages: (sessionId: string, chatSessionId: string | number, limit?: number) => Promise<{ sessionId: string startTs: number endTs: number messageCount: number returnedCount: number participants: string[] messages: Array<{ id: number localId: number sessionId: string senderName: string senderPlatformId: string senderUsername: string content: string timestamp: number type: number isSend: number | null replyToMessageId: string | null replyToContent: string | null replyToSenderName: string | null }> } | null> getSessionSummaries: ( sessionId: string, options?: { sessionIds?: string[]; limit?: number; previewCount?: number } ) => Promise }>> getToolCatalog: () => Promise }>> executeTool: (payload: { name: string; args?: Record }) => Promise<{ success: boolean result?: unknown error?: string }> cancelToolTest: (payload?: { taskId?: string }) => Promise<{ success: boolean }> } agentApi: { runStream: (payload: { mode?: 'chat' | 'sql' conversationId?: string userInput: string assistantId?: string activeSkillId?: string chatScope?: 'group' | 'private' sqlContext?: { schemaText?: string; targetHint?: string } }, onChunk?: (payload: AgentStreamChunk) => void) => { requestId: string promise: Promise<{ success: boolean result?: { success: boolean; runId?: string; conversationId?: string; error?: string; canceled?: boolean } error?: string }> } abort: (payload: string | { requestId?: string; runId?: string; conversationId?: string }) => Promise<{ success: boolean }> } assistantApi: { getAll: () => Promise supportedLocales?: string[] }>> getConfig: (id: string) => Promise<{ id: string name: string systemPrompt: string presetQuestions: string[] allowedBuiltinTools?: string[] builtinId?: string applicableChatTypes?: Array<'group' | 'private'> supportedLocales?: string[] } | null> create: (payload: any) => Promise<{ success: boolean; id?: string; error?: string }> update: (payload: { id: string; updates: any }) => Promise<{ success: boolean; error?: string }> delete: (id: string) => Promise<{ success: boolean; error?: string }> reset: (id: string) => Promise<{ success: boolean; error?: string }> getBuiltinCatalog: () => Promise supportedLocales?: string[] imported: boolean }>> getBuiltinToolCatalog: () => Promise> importFromMd: (rawMd: string) => Promise<{ success: boolean; id?: string; error?: string }> } skillApi: { getAll: () => Promise> getConfig: (id: string) => Promise<{ id: string name: string description: string tags: string[] chatScope: 'all' | 'group' | 'private' tools: string[] prompt: string builtinId?: string } | null> create: (rawMd: string) => Promise<{ success: boolean; id?: string; error?: string }> update: (payload: { id: string; rawMd: string }) => Promise<{ success: boolean; error?: string }> delete: (id: string) => Promise<{ success: boolean; error?: string }> getBuiltinCatalog: () => Promise> importFromMd: (rawMd: string) => Promise<{ success: boolean; id?: string; error?: string }> } llmApi: { getConfig: () => Promise<{ success: boolean; config: { apiBaseUrl: string; apiKey: string; model: string } }> setConfig: (payload: { apiBaseUrl?: string; apiKey?: string; model?: string }) => Promise<{ success: boolean }> listModels: () => Promise<{ success: boolean; models: Array<{ id: string; label: string }> }> } } export interface ExportOptions { format: 'chatlab' | 'chatlab-jsonl' | 'json' | 'arkme-json' | 'html' | 'txt' | 'excel' | 'weclone' | 'sql' contentType?: 'text' | 'voice' | 'image' | 'video' | 'emoji' | 'file' dateRange?: { start: number; end: number } | null senderUsername?: string fileNameSuffix?: string exportMedia?: boolean exportAvatars?: boolean exportImages?: boolean exportVoices?: boolean exportVideos?: boolean exportEmojis?: boolean exportFiles?: boolean maxFileSizeMb?: number exportVoiceAsText?: boolean excelCompactColumns?: boolean txtColumns?: string[] fileNamingMode?: 'classic' | 'date-range' sessionLayout?: 'shared' | 'per-session' sessionNameWithTypePrefix?: boolean displayNamePreference?: 'group-nickname' | 'remark' | 'nickname' exportConcurrency?: number imageDeepSearchOnMiss?: boolean } export interface ExportProgress { current: number total: number currentSession: string currentSessionId?: string phase: 'preparing' | 'exporting' | 'exporting-media' | 'exporting-voice' | 'writing' | 'complete' phaseProgress?: number phaseTotal?: number phaseLabel?: string collectedMessages?: number exportedMessages?: number estimatedTotalMessages?: number writtenFiles?: number mediaDoneFiles?: number mediaCacheHitFiles?: number mediaCacheMissFiles?: number mediaCacheFillFiles?: number mediaDedupReuseFiles?: number mediaBytesWritten?: number } export interface WxidInfo { wxid: string modifiedTime: number } declare global { interface Window { electronAPI: ElectronAPI aiApi: ElectronAPI['aiApi'] agentApi: ElectronAPI['agentApi'] assistantApi: ElectronAPI['assistantApi'] skillApi: ElectronAPI['skillApi'] llmApi: ElectronAPI['llmApi'] } // Electron 类型声明 namespace Electron { interface OpenDialogOptions { title?: string defaultPath?: string filters?: { name: string; extensions: string[] }[] properties?: ('openFile' | 'openDirectory' | 'multiSelections' | 'createDirectory')[] } interface OpenDialogReturnValue { canceled: boolean filePaths: string[] } interface SaveDialogOptions { title?: string defaultPath?: string filters?: { name: string; extensions: string[] }[] } interface SaveDialogReturnValue { canceled: boolean filePath?: string } } } export { }