From 37ed157e4a4f826e53b84ad8da2fc277836e3792 Mon Sep 17 00:00:00 2001 From: duanshuwen Date: Sat, 11 Apr 2026 17:22:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8DMac=E6=89=93=E5=8C=85?= =?UTF-8?q?=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist-electron/main/main.js | 1646 +----------------------------- dist-electron/main/main.js.bak | 2 +- dist-electron/main/main.jsc | Bin 106224 -> 111944 bytes dist-electron/preload/preload.js | 100 +- dist/assets/index-CvK9ZwFP.css | 1 - dist/assets/index-tccZ5UIk.css | 1 - dist/index.html | 34 +- package.json | 14 +- package_mac_diagnosis_report.md | 145 +++ scripts/after-pack.cjs | 28 +- 10 files changed, 191 insertions(+), 1780 deletions(-) delete mode 100644 dist/assets/index-CvK9ZwFP.css delete mode 100644 dist/assets/index-tccZ5UIk.css create mode 100644 package_mac_diagnosis_report.md diff --git a/dist-electron/main/main.js b/dist-electron/main/main.js index 5639b8d..a8c04dd 100644 --- a/dist-electron/main/main.js +++ b/dist-electron/main/main.js @@ -1,1644 +1,2 @@ -"use strict"; -const electron = require("electron"); -const OpenAI = require("openai"); -const util = require("util"); -const log = require("electron-log"); -const path = require("path"); -const fs = require("fs"); -const jsBase64 = require("js-base64"); -const path$1 = require("node:path"); -const crypto = require("crypto"); -const started = require("electron-squirrel-startup"); -const net = require("net"); -const http = require("http"); -const child_process = require("child_process"); -const events = require("events"); -require("bytenode"); -const electronUpdater = require("electron-updater"); -function _interopNamespaceDefault(e) { - const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); - if (e) { - for (const k in e) { - if (k !== "default") { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: () => e[k] - }); - } - } - } - n.default = e; - return Object.freeze(n); -} -const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path); -const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs); -var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => { - IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open"; - IPC_EVENTS2["WINDOW_MINIMIZE"] = "window-minimize"; - IPC_EVENTS2["WINDOW_MAXIMIZE"] = "window-maximize"; - IPC_EVENTS2["WINDOW_CLOSE"] = "window-close"; - IPC_EVENTS2["IS_WINDOW_MAXIMIZED"] = "is-window-maximized"; - IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless"; - IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page"; - IPC_EVENTS2["TAB_CREATE"] = "tab:create"; - IPC_EVENTS2["TAB_LIST"] = "tab:list"; - IPC_EVENTS2["TAB_NAVIGATE"] = "tab:navigate"; - IPC_EVENTS2["TAB_RELOAD"] = "tab:reload"; - IPC_EVENTS2["TAB_BACK"] = "tab:back"; - IPC_EVENTS2["TAB_FORWARD"] = "tab:forward"; - IPC_EVENTS2["TAB_SWITCH"] = "tab:switch"; - IPC_EVENTS2["TAB_CLOSE"] = "tab:close"; - IPC_EVENTS2["LOG_TO_MAIN"] = "log-to-main"; - IPC_EVENTS2["READ_FILE"] = "read-file"; - IPC_EVENTS2["INVOKE"] = "ipc:invoke"; - IPC_EVENTS2["INVOKE_ASYNC"] = "ipc:invokeAsync"; - IPC_EVENTS2["APP_MINIMIZE"] = "app:minimize"; - IPC_EVENTS2["APP_MAXIMIZE"] = "app:maximize"; - IPC_EVENTS2["APP_QUIT"] = "app:quit"; - IPC_EVENTS2["FILE_READ"] = "file:read"; - IPC_EVENTS2["FILE_WRITE"] = "file:write"; - IPC_EVENTS2["GET_WINDOW_ID"] = "get-window-id"; - IPC_EVENTS2["CUSTOM_EVENT"] = "custom:event"; - IPC_EVENTS2["TIME_UPDATE"] = "time:update"; - IPC_EVENTS2["RENDERER_IS_READY"] = "renderer-ready"; - IPC_EVENTS2["SHOW_CONTEXT_MENU"] = "show-context-menu"; - IPC_EVENTS2["START_A_DIALOGUE"] = "start-a-dialogue"; - IPC_EVENTS2["OPEN_WINDOW"] = "open-window"; - IPC_EVENTS2["LOG_DEBUG"] = "log-debug"; - IPC_EVENTS2["LOG_INFO"] = "log-info"; - IPC_EVENTS2["LOG_WARN"] = "log-warn"; - IPC_EVENTS2["LOG_ERROR"] = "log-error"; - IPC_EVENTS2["CONFIG_UPDATED"] = "config-updated"; - IPC_EVENTS2["SET_CONFIG"] = "set-config"; - IPC_EVENTS2["GET_CONFIG"] = "get-config"; - IPC_EVENTS2["UPDATE_CONFIG"] = "update-config"; - IPC_EVENTS2["SET_THEME_MODE"] = "set-theme-mode"; - IPC_EVENTS2["GET_THEME_MODE"] = "get-theme-mode"; - IPC_EVENTS2["IS_DARK_THEME"] = "is-dark-theme"; - IPC_EVENTS2["THEME_MODE_UPDATED"] = "theme-mode-updated"; - IPC_EVENTS2["EXECUTE_SCRIPT"] = "execute-script"; - IPC_EVENTS2["OPEN_CHANNEL"] = "open-channel"; - IPC_EVENTS2["UPDATE_CHECK"] = "update:check"; - IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download"; - IPC_EVENTS2["UPDATE_INSTALL"] = "update:install"; - IPC_EVENTS2["UPDATE_VERSION"] = "update:version"; - IPC_EVENTS2["UPDATE_STATUS_CHANGED"] = "update:status-changed"; - return IPC_EVENTS2; -})(IPC_EVENTS || {}); -const MAIN_WIN_SIZE = { - width: 1440, - height: 900, - minWidth: 1440, - minHeight: 900 -}; -var WINDOW_NAMES = /* @__PURE__ */ ((WINDOW_NAMES2) => { - WINDOW_NAMES2["MAIN"] = "main"; - WINDOW_NAMES2["SETTING"] = "setting"; - WINDOW_NAMES2["DIALOG"] = "dialog"; - WINDOW_NAMES2["LOADING"] = "loading"; - return WINDOW_NAMES2; -})(WINDOW_NAMES || {}); -var CONFIG_KEYS = /* @__PURE__ */ ((CONFIG_KEYS2) => { - CONFIG_KEYS2["THEME_MODE"] = "themeMode"; - CONFIG_KEYS2["PRIMARY_COLOR"] = "primaryColor"; - CONFIG_KEYS2["LANGUAGE"] = "language"; - CONFIG_KEYS2["FONT_SIZE"] = "fontSize"; - CONFIG_KEYS2["MINIMIZE_TO_TRAY"] = "minimizeToTray"; - CONFIG_KEYS2["PROVIDER"] = "provider"; - CONFIG_KEYS2["DEFAULT_MODEL"] = "defaultModel"; - CONFIG_KEYS2["AUTO_CHECK_UPDATE"] = "autoCheckUpdate"; - CONFIG_KEYS2["AUTO_DOWNLOAD_UPDATE"] = "autoDownloadUpdate"; - return CONFIG_KEYS2; -})(CONFIG_KEYS || {}); -var MENU_IDS = /* @__PURE__ */ ((MENU_IDS2) => { - MENU_IDS2["CONVERSATION_ITEM"] = "conversation-item"; - MENU_IDS2["CONVERSATION_LIST"] = "conversation-list"; - MENU_IDS2["MESSAGE_ITEM"] = "message-item"; - return MENU_IDS2; -})(MENU_IDS || {}); -var CONVERSATION_ITEM_MENU_IDS = /* @__PURE__ */ ((CONVERSATION_ITEM_MENU_IDS2) => { - CONVERSATION_ITEM_MENU_IDS2["PIN"] = "pin"; - CONVERSATION_ITEM_MENU_IDS2["RENAME"] = "rename"; - CONVERSATION_ITEM_MENU_IDS2["DEL"] = "del"; - return CONVERSATION_ITEM_MENU_IDS2; -})(CONVERSATION_ITEM_MENU_IDS || {}); -var CONVERSATION_LIST_MENU_IDS = /* @__PURE__ */ ((CONVERSATION_LIST_MENU_IDS2) => { - CONVERSATION_LIST_MENU_IDS2["NEW_CONVERSATION"] = "newConversation"; - CONVERSATION_LIST_MENU_IDS2["SORT_BY"] = "sortBy"; - CONVERSATION_LIST_MENU_IDS2["SORT_BY_CREATE_TIME"] = "sortByCreateTime"; - CONVERSATION_LIST_MENU_IDS2["SORT_BY_UPDATE_TIME"] = "sortByUpdateTime"; - CONVERSATION_LIST_MENU_IDS2["SORT_BY_NAME"] = "sortByName"; - CONVERSATION_LIST_MENU_IDS2["SORT_BY_MODEL"] = "sortByModel"; - CONVERSATION_LIST_MENU_IDS2["SORT_ASCENDING"] = "sortAscending"; - CONVERSATION_LIST_MENU_IDS2["SORT_DESCENDING"] = "sortDescending"; - CONVERSATION_LIST_MENU_IDS2["BATCH_OPERATIONS"] = "batchOperations"; - return CONVERSATION_LIST_MENU_IDS2; -})(CONVERSATION_LIST_MENU_IDS || {}); -var MESSAGE_ITEM_MENU_IDS = /* @__PURE__ */ ((MESSAGE_ITEM_MENU_IDS2) => { - MESSAGE_ITEM_MENU_IDS2["COPY"] = "copy"; - MESSAGE_ITEM_MENU_IDS2["DELETE"] = "delete"; - MESSAGE_ITEM_MENU_IDS2["SELECT"] = "select"; - return MESSAGE_ITEM_MENU_IDS2; -})(MESSAGE_ITEM_MENU_IDS || {}); -class BaseProvider { -} -const readdirAsync = util.promisify(fs__namespace.readdir); -const statAsync = util.promisify(fs__namespace.stat); -const unlinkAsync = util.promisify(fs__namespace.unlink); -class LogService { - static _instance; - // 日志保留天数,默认7天 - LOG_RETENTION_DAYS = 7; - // 清理间隔,默认24小时(毫秒) - CLEANUP_INTERVAL_MS = 24 * 60 * 60 * 1e3; - constructor() { - const logPath = path__namespace.join(electron.app.getPath("userData"), "logs"); - try { - if (!fs__namespace.existsSync(logPath)) { - fs__namespace.mkdirSync(logPath, { recursive: true }); - } - } catch (err) { - this.error("Failed to create log directory:", err); - } - log.transports.file.resolvePathFn = () => { - const today = /* @__PURE__ */ new Date(); - const formattedDate = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`; - return path__namespace.join(logPath, `${formattedDate}.log`); - }; - log.transports.file.format = "[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}"; - log.transports.file.maxSize = 10 * 1024 * 1024; - log.transports.console.level = process.env.NODE_ENV === "development" ? "debug" : "info"; - log.transports.file.level = "debug"; - this._setupIpcEvents(); - this._rewriteConsole(); - this.info("LogService initialized successfully."); - this._cleanupOldLogs(); - setInterval(() => this._cleanupOldLogs(), this.CLEANUP_INTERVAL_MS); - } - _setupIpcEvents() { - electron.ipcMain.on(IPC_EVENTS.LOG_DEBUG, (_e, message, ...meta) => this.debug(message, ...meta)); - electron.ipcMain.on(IPC_EVENTS.LOG_INFO, (_e, message, ...meta) => this.info(message, ...meta)); - electron.ipcMain.on(IPC_EVENTS.LOG_WARN, (_e, message, ...meta) => this.warn(message, ...meta)); - electron.ipcMain.on(IPC_EVENTS.LOG_ERROR, (_e, message, ...meta) => this.error(message, ...meta)); - } - _rewriteConsole() { - console.debug = log.debug; - console.log = log.info; - console.info = log.info; - console.warn = log.warn; - console.error = log.error; - } - async _cleanupOldLogs() { - try { - const logPath = path__namespace.join(electron.app.getPath("userData"), "logs"); - if (!fs__namespace.existsSync(logPath)) return; - const now = /* @__PURE__ */ new Date(); - const expirationDate = new Date(now.getTime() - this.LOG_RETENTION_DAYS * 24 * 60 * 60 * 1e3); - const files = await readdirAsync(logPath); - let deletedCount = 0; - for (const file of files) { - if (!file.endsWith(".log")) continue; - const filePath = path__namespace.join(logPath, file); - try { - const stats = await statAsync(filePath); - if (stats.isFile() && stats.birthtime < expirationDate) { - await unlinkAsync(filePath); - deletedCount++; - } - } catch (error) { - this.error(`Failed to delete old log file ${filePath}:`, error); - } - } - if (deletedCount > 0) { - this.info(`Successfully cleaned up ${deletedCount} old log files.`); - } - } catch (err) { - this.error("Failed to cleanup old logs:", err); - } - } - static getInstance() { - if (!this._instance) { - this._instance = new LogService(); - } - return this._instance; - } - /** - * 记录调试信息 - * @param {string} message - 日志消息 - * @param {any[]} meta - 附加的元数据 - */ - debug(message, ...meta) { - log.debug(message, ...meta); - } - /** - * 记录一般信息 - * @param {string} message - 日志消息 - * @param {any[]} meta - 附加的元数据 - */ - info(message, ...meta) { - log.info(message, ...meta); - } - /** - * 记录警告信息 - * @param {string} message - 日志消息 - * @param {any[]} meta - 附加的元数据 - */ - warn(message, ...meta) { - log.warn(message, ...meta); - } - /** - * 记录错误信息 - * @param {string} message - 日志消息 - * @param {any[]} meta - 附加的元数据,通常是错误对象 - */ - error(message, ...meta) { - log.error(message, ...meta); - } - logApiRequest(endpoint, data = {}, method = "POST") { - this.info(`API Request: ${endpoint}, Method: ${method}, Request: ${JSON.stringify(data)}`); - } - logApiResponse(endpoint, response = {}, statusCode = 200, responseTime = 0) { - if (statusCode >= 400) { - this.error(`API Error Response: ${endpoint}, Status: ${statusCode}, Response Time: ${responseTime}ms, Response: ${JSON.stringify(response)}`); - } else { - this.debug(`API Response: ${endpoint}, Status: ${statusCode}, Response Time: ${responseTime}ms, Response: ${JSON.stringify(response)}`); - } - } - logUserOperation(operation, userId = "unknown", details = {}) { - this.info(`User Operation: ${operation} by ${userId}, Details: ${JSON.stringify(details)}`); - } -} -const logManager = LogService.getInstance(); -function _transformChunk(chunk) { - const choice = chunk.choices[0]; - return { - isEnd: choice?.finish_reason === "stop", - result: choice?.delta?.content ?? "" - }; -} -class OpenAIProvider extends BaseProvider { - client; - constructor(apiKey, baseURL) { - super(); - this.client = new OpenAI({ apiKey, baseURL }); - } - async chat(messages2, model) { - const startTime = Date.now(); - const lastMessage = messages2[messages2.length - 1]; - logManager.logApiRequest("chat.completions.create", { - model, - lastMessage: lastMessage?.content?.substring(0, 100) + (lastMessage?.content?.length > 100 ? "..." : ""), - messageCount: messages2.length - }, "POST"); - try { - const chunks = await this.client.chat.completions.create({ - model, - messages: messages2, - stream: true - }); - const responseTime = Date.now() - startTime; - logManager.logApiResponse("chat.completions.create", { success: true }, 200, responseTime); - return { - async *[Symbol.asyncIterator]() { - for await (const chunk of chunks) { - yield _transformChunk(chunk); - } - } - }; - } catch (error) { - const responseTime = Date.now() - startTime; - logManager.logApiResponse("chat.completions.create", { error: error instanceof Error ? error.message : String(error) }, 500, responseTime); - throw error; - } - } -} -function debounce(fn, delay) { - let timer = null; - return function(...args) { - if (timer) { - clearTimeout(timer); - } - timer = setTimeout(() => { - fn.apply(this, args); - }, delay); - }; -} -function cloneDeep(obj) { - if (obj === null || typeof obj !== "object") { - return obj; - } - if (Array.isArray(obj)) { - return obj.map((item) => cloneDeep(item)); - } - const clone = Object.assign({}, obj); - for (const key in clone) { - if (Object.prototype.hasOwnProperty.call(clone, key)) { - clone[key] = cloneDeep(clone[key]); - } - } - return clone; -} -function simpleCloneDeep(obj) { - try { - return JSON.parse(JSON.stringify(obj)); - } catch (error) { - console.error("simpleCloneDeep failed:", error); - return obj; - } -} -function parseOpenAISetting(setting) { - try { - return JSON.parse(jsBase64.decode(setting)); - } catch (error) { - console.error("parseOpenAISetting failed:", error); - return {}; - } -} -const DEFAULT_CONFIG = { - [CONFIG_KEYS.THEME_MODE]: "system", - [CONFIG_KEYS.PRIMARY_COLOR]: "#BB5BE7", - [CONFIG_KEYS.LANGUAGE]: "zh", - [CONFIG_KEYS.FONT_SIZE]: 14, - [CONFIG_KEYS.MINIMIZE_TO_TRAY]: false, - [CONFIG_KEYS.PROVIDER]: "", - [CONFIG_KEYS.DEFAULT_MODEL]: null -}; -class ConfigService { - static _instance; - _config; - _configPath; - _defaultConfig = DEFAULT_CONFIG; - _listeners = []; - constructor() { - this._configPath = path__namespace.join(electron.app.getPath("userData"), "config.json"); - this._config = this._loadConfig(); - this._setupIpcEvents(); - logManager.info("ConfigService initialized successfully."); - } - _setupIpcEvents() { - const duration = 200; - const handelUpdate = debounce((val) => this.update(val), duration); - electron.ipcMain.handle(IPC_EVENTS.GET_CONFIG, (_, key) => this.get(key)); - electron.ipcMain.on(IPC_EVENTS.SET_CONFIG, (_, key, val) => this.set(key, val)); - electron.ipcMain.on(IPC_EVENTS.UPDATE_CONFIG, (_, updates) => handelUpdate(updates)); - } - static getInstance() { - if (!this._instance) { - this._instance = new ConfigService(); - } - return this._instance; - } - _loadConfig() { - try { - if (fs__namespace.existsSync(this._configPath)) { - const configContent = fs__namespace.readFileSync(this._configPath, "utf-8"); - const config = { ...this._defaultConfig, ...JSON.parse(configContent) }; - logManager.info("Config loaded successfully from:", this._configPath); - return config; - } - } catch (error) { - logManager.error("Failed to load config:", error); - } - return { ...this._defaultConfig }; - } - _saveConfig() { - try { - fs__namespace.mkdirSync(path__namespace.dirname(this._configPath), { recursive: true }); - fs__namespace.writeFileSync(this._configPath, JSON.stringify(this._config, null, 2), "utf-8"); - this._notifyListeners(); - logManager.info("Config saved successfully to:", this._configPath); - } catch (error) { - logManager.error("Failed to save config:", error); - } - } - _notifyListeners() { - electron.BrowserWindow.getAllWindows().forEach((win) => win.webContents.send(IPC_EVENTS.CONFIG_UPDATED, this._config)); - this._listeners.forEach((listener) => listener({ ...this._config })); - } - getConfig() { - return simpleCloneDeep(this._config); - } - get(key) { - return this._config[key]; - } - set(key, value, autoSave = true) { - if (!(key in this._config)) return; - const oldValue = this._config[key]; - if (oldValue === value) return; - this._config[key] = value; - logManager.debug(`Config set: ${key} = ${value}`); - autoSave && this._saveConfig(); - } - update(updates, autoSave = true) { - this._config = { ...this._config, ...updates }; - autoSave && this._saveConfig(); - } - resetToDefault() { - this._config = { ...this._defaultConfig }; - logManager.info("Config reset to default."); - this._saveConfig(); - } - onConfigChange(listener) { - this._listeners.push(listener); - return () => this._listeners = this._listeners.filter((l) => l !== listener); - } -} -const configManager = ConfigService.getInstance(); -[ - { - id: 1, - name: "bigmodel", - title: "智谱AI", - models: ["glm-4.5-flash"], - openAISetting: { - baseURL: "https://open.bigmodel.cn/api/paas/v4", - apiKey: process.env.BIGMODEL_API_KEY || "" - }, - createdAt: (/* @__PURE__ */ new Date()).getTime(), - updatedAt: (/* @__PURE__ */ new Date()).getTime() - }, - { - id: 2, - name: "deepseek", - title: "深度求索 (DeepSeek)", - models: ["deepseek-chat"], - openAISetting: { - baseURL: "https://api.deepseek.com/v1", - apiKey: process.env.DEEPSEEK_API_KEY || "" - }, - createdAt: (/* @__PURE__ */ new Date()).getTime(), - updatedAt: (/* @__PURE__ */ new Date()).getTime() - }, - { - id: 3, - name: "siliconflow", - title: "硅基流动", - models: ["Qwen/Qwen3-8B", "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B"], - openAISetting: { - baseURL: "https://api.siliconflow.cn/v1", - apiKey: process.env.SILICONFLOW_API_KEY || "" - }, - createdAt: (/* @__PURE__ */ new Date()).getTime(), - updatedAt: (/* @__PURE__ */ new Date()).getTime() - }, - { - id: 4, - name: "qianfan", - title: "百度千帆", - models: ["ernie-speed-128k", "ernie-4.0-8k", "ernie-3.5-8k"], - openAISetting: { - baseURL: "https://qianfan.baidubce.com/v2", - apiKey: process.env.QIANFAN_API_KEY || "" - }, - createdAt: (/* @__PURE__ */ new Date()).getTime(), - updatedAt: (/* @__PURE__ */ new Date()).getTime() - } -]; -const _parseProvider = () => { - let result = []; - let isBase64Parsed = false; - const providerConfig = configManager.get(CONFIG_KEYS.PROVIDER); - const mapCallback = (provider) => ({ - ...provider, - openAISetting: typeof provider.openAISetting === "string" ? parseOpenAISetting(provider.openAISetting ?? "") : provider.openAISetting - }); - try { - result = JSON.parse(jsBase64.decode(providerConfig)); - isBase64Parsed = true; - } catch (error) { - logManager.error(`parse base64 provider failed: ${error}`); - } - if (!isBase64Parsed) try { - result = JSON.parse(providerConfig); - } catch (error) { - logManager.error(`parse provider failed: ${error}`); - } - if (!result.length) return; - return result.map(mapCallback); -}; -const getProviderConfig = () => { - try { - return _parseProvider(); - } catch (error) { - logManager.error(`get provider config failed: ${error}`); - return null; - } -}; -function createProvider(name) { - const providers2 = getProviderConfig(); - if (!providers2) { - throw new Error("provider config not found"); - } - for (const provider of providers2) { - if (provider.name === name) { - if (!provider.openAISetting?.apiKey || !provider.openAISetting?.baseURL) { - throw new Error("apiKey or baseURL not found"); - } - return new OpenAIProvider(provider.openAISetting.apiKey, provider.openAISetting.baseURL); - } - } -} -const window$1 = { "minimize": "Minimize", "maximize": "Maximize", "restore": "Restore", "close": "Close" }; -const main$1 = { "welcome": { "helloMessage": "Hello, I'm Diona" }, "conversation": { "placeholder": "Type a message...", "newConversation": "New Conversation", "selectModel": "Please select model", "createConversation": "Create Conversation", "searchPlaceholder": "Search conversations...", "goSettings": "Go to", "settings": "Settings Window", "addModel": "to add a model", "dialog": { "title": "Confirm Deletion", "content": "Are you sure you want to delete this conversation?", "content_1": "Are you sure you want to delete the selected conversations? This action cannot be undone." }, "operations": { "pin": "Pin Selected", "del": "Delete Selected", "selectAll": "Select All", "cancel": "Cancel" } }, "sidebar": { "conversations": "Conversations", "settings": "Settings", "help": "Help" }, "message": { "dialog": { "title": "Confirm Deletion", "messageDelete": "Are you sure you want to delete this message?", "batchDelete": "Are you sure you want to delete the selected messages?", "copySuccess": "Copied successfully" }, "batchActions": { "deleteSelected": "Delete Selected" }, "rendering": "Thinking...", "stoppedGeneration": "(Stopped generating)", "sending": "Sending", "stopGeneration": "Stop generating", "send": "Send" } }; -const dialog$1 = { "cancel": "Cancel", "confirm": "Confirm" }; -const settings$1 = { "title": "Settings", "base": "Basic Settings", "provider": { "modelConfig": "Model Configuration" }, "theme": { "label": "Theme Settings", "dark": "Dark Theme", "light": "Light Theme", "system": "System Theme", "primaryColor": "Primary Color" }, "appearance": { "fontSize": "Font Size", "fontSizeOptions": { "10": "Tiny (10px)", "12": "Small (12px)", "14": "Normal (14px)", "16": "Medium (16px)", "18": "Large (18px)", "20": "Larger (20px)", "24": "Extra Large (24px)" } }, "behavior": { "minimizeToTray": "Minimize to tray when closed" }, "language": { "label": "Language" }, "providers": { "defaultModel": "Default Model", "apiKey": "API Key", "apiUrl": "API URL" } }; -const menu$1 = { "conversation": { "newConversation": "New Conversation", "sortBy": "Sort By", "sortByCreateTime": "Sort by Creation Time", "sortByUpdateTime": "Sort by Update Time", "sortByName": "Sort by Name", "sortByModel": "Sort by Model", "sortAscending": "Ascending", "sortDescending": "Descending", "pinConversation": "Pin Conversation", "unpinConversation": "Unpin Conversation", "renameConversation": "Rename Conversation", "delConversation": "Delete Conversation", "batchOperations": "Batch Operations" }, "message": { "copyMessage": "Copy Message", "deleteMessage": "Delete Message", "selectMessage": "Select Message" } }; -const tray$1 = { "tooltip": "Diona Application", "showWindow": "Show Window", "exit": "Exit" }; -const timeAgo$1 = { "justNow": "Just now", "minutes": "{count} minutes ago", "hours": "{count} hours ago", "days": "{count} days ago", "months": "{count} months ago", "years": "{count} years ago", "weekday": { "sun": "Sunday", "mon": "Monday", "tue": "Tuesday", "wed": "Wednesday", "thu": "Thursday", "fri": "Friday", "sat": "Saturday" } }; -const app$1 = { "title": "Diona Application" }; -const en = { - window: window$1, - main: main$1, - dialog: dialog$1, - settings: settings$1, - menu: menu$1, - tray: tray$1, - timeAgo: timeAgo$1, - app: app$1 -}; -const window = { "minimize": "最小化", "maximize": "最大化", "restore": "还原", "close": "关闭" }; -const main = { "welcome": { "helloMessage": "你好,我是迪奥娜" }, "conversation": { "placeholder": "输入消息...", "newConversation": "新对话", "selectModel": "请选择模型", "createConversation": "创建对话", "searchPlaceholder": "搜索对话...", "goSettings": "快去", "settings": "设置窗口", "addModel": "添加模型", "dialog": { "title": "确认删除", "content": "确定要删除这个对话吗?", "content_1": "确定要删除选中的对话吗?此操作不可撤销。" }, "operations": { "pin": "置顶所选", "del": "删除所选", "selectAll": "全选", "cancel": "取消" } }, "sidebar": { "conversations": "对话", "settings": "设置", "help": "帮助" }, "message": { "dialog": { "title": "确认删除", "messageDelete": "确认删除该条消息?", "batchDelete": "确认删除选中的消息?", "copySuccess": "复制成功" }, "batchActions": { "deleteSelected": "删除选中项" }, "rendering": "思考中...", "stoppedGeneration": "(已停止生成)", "sending": "发送中", "stopGeneration": "停止生成", "send": "发送" } }; -const dialog = { "cancel": "取消", "confirm": "确认" }; -const settings = { "title": "设置", "base": "基础设置", "provider": { "modelConfig": "模型配置" }, "providers": { "defaultModel": "默认模型", "apiKey": "API密钥", "apiUrl": "API地址" }, "theme": { "label": "主题设置", "dark": "深色主题", "light": "浅色主题", "system": "跟随系统", "primaryColor": "主题颜色" }, "appearance": { "fontSize": "字体大小", "fontSizeOptions": { "10": "极小 (10px)", "12": "小 (12px)", "14": "正常 (14px)", "16": "中 (16px)", "18": "大 (18px)", "20": "较大 (20px)", "24": "超大 (24px)" } }, "behavior": { "minimizeToTray": "关闭时最小化到托盘" }, "language": { "label": "语言设置" } }; -const menu = { "conversation": { "newConversation": "新建对话", "sortBy": "排序方式", "sortByCreateTime": "按创建时间排序", "sortByUpdateTime": "按更新时间排序", "sortByName": "按名称排序", "sortByModel": "按模型排序", "sortAscending": "递增", "sortDescending": "递减", "pinConversation": "置顶对话", "unpinConversation": "取消置顶", "renameConversation": "重命名对话", "delConversation": "删除对话", "batchOperations": "批量操作" }, "message": { "copyMessage": "复制消息", "deleteMessage": "删除消息", "selectMessage": "选择消息" } }; -const tray = { "tooltip": "迪奥娜", "showWindow": "显示窗口", "exit": "退出" }; -const timeAgo = { "justNow": "刚刚", "minutes": "{count}分钟前", "hours": "{count}小时前", "days": "{count}天前", "months": "{count}个月前", "years": "{count}年前", "weekday": { "sun": "星期日", "mon": "星期一", "tue": "星期二", "wed": "星期三", "thu": "星期四", "fri": "星期五", "sat": "星期六" } }; -const app = { "title": "迪奥娜" }; -const zh = { - window, - main, - dialog, - settings, - menu, - tray, - timeAgo, - app -}; -const messages = { en, zh }; -function createTranslator() { - return (key) => { - if (!key) return void 0; - try { - const keys = key?.split("."); - let result = messages[configManager.get(CONFIG_KEYS.LANGUAGE)]; - for (const _key of keys) { - result = result[_key]; - } - return result; - } catch (e) { - logManager.error("failed to translate key:", key, e); - return key; - } - }; -} -let logo = void 0; -function createLogo() { - if (logo != null) { - return logo; - } - const appPath = electron.app.getAppPath(); - const iconPath = path$1.join(appPath, "resources", "icons", "icon.ico"); - logo = iconPath; - return logo; -} -class ThemeService { - static _instance; - _isDark = electron.nativeTheme.shouldUseDarkColors; - constructor() { - const themeMode = configManager.get(CONFIG_KEYS.THEME_MODE); - if (themeMode) { - electron.nativeTheme.themeSource = themeMode; - this._isDark = electron.nativeTheme.shouldUseDarkColors; - } - this._setupIpcEvent(); - logManager.info("ThemeService initialized successfully."); - } - _setupIpcEvent() { - electron.ipcMain.handle(IPC_EVENTS.SET_THEME_MODE, (_e, mode) => { - electron.nativeTheme.themeSource = mode; - configManager.set(CONFIG_KEYS.THEME_MODE, mode); - return electron.nativeTheme.shouldUseDarkColors; - }); - electron.ipcMain.handle(IPC_EVENTS.GET_THEME_MODE, () => { - return electron.nativeTheme.themeSource; - }); - electron.ipcMain.handle(IPC_EVENTS.IS_DARK_THEME, () => { - return electron.nativeTheme.shouldUseDarkColors; - }); - electron.nativeTheme.on("updated", () => { - this._isDark = electron.nativeTheme.shouldUseDarkColors; - electron.BrowserWindow.getAllWindows().forEach( - (win) => win.webContents.send(IPC_EVENTS.THEME_MODE_UPDATED, this._isDark) - ); - }); - } - static getInstance() { - if (!this._instance) { - this._instance = new ThemeService(); - } - return this._instance; - } - get isDark() { - return this._isDark; - } - get themeMode() { - return electron.nativeTheme.themeSource; - } -} -const themeManager = ThemeService.getInstance(); -const SHARED_WINDOW_OPTIONS = { - frame: false, - titleBarStyle: "hidden", - trafficLightPosition: { x: -100, y: -100 }, - show: false, - title: "NIANXX", - darkTheme: themeManager.isDark, - backgroundColor: themeManager.isDark ? "#2C2C2C" : "#FFFFFF", - webPreferences: { - nodeIntegration: false, - // 禁用 Node.js 集成,提高安全性 - contextIsolation: true, - // 启用上下文隔离,防止渲染进程访问主进程 API - sandbox: true, - // 启用沙箱模式,进一步增强安全性 - backgroundThrottling: false, - preload: path$1.join(process.cwd(), "dist-electron/preload/preload.js") - } -}; -class WindowService { - static _instance; - _logo = createLogo(); - isDev = true; - _winStates = { - main: { instance: void 0, isHidden: false, onCreate: [], onClosed: [] }, - setting: { instance: void 0, isHidden: false, onCreate: [], onClosed: [] }, - dialog: { instance: void 0, isHidden: false, onCreate: [], onClosed: [] }, - login: { instance: void 0, isHidden: false, onCreate: [], onClosed: [] }, - loading: { instance: void 0, isHidden: false, onCreate: [], onClosed: [] } - }; - constructor() { - this._setupIpcEvents(); - logManager.info("WindowService initialized successfully."); - } - _isReallyClose(windowName) { - if (windowName === WINDOW_NAMES.MAIN) return configManager.get(CONFIG_KEYS.MINIMIZE_TO_TRAY) === false; - if (windowName === WINDOW_NAMES.SETTING) return false; - return true; - } - _setupIpcEvents() { - const handleCloseWindow = (e) => { - const target = electron.BrowserWindow.fromWebContents(e.sender); - const winName = this.getName(target); - this.close(target, this._isReallyClose(winName)); - }; - const handleMinimizeWindow = (e) => { - electron.BrowserWindow.fromWebContents(e.sender)?.minimize(); - }; - const handleMaximizeWindow = (e) => { - this.toggleMax(electron.BrowserWindow.fromWebContents(e.sender)); - }; - const handleIsWindowMaximized = (e) => { - return electron.BrowserWindow.fromWebContents(e.sender)?.isMaximized() ?? false; - }; - electron.ipcMain.on(IPC_EVENTS.WINDOW_CLOSE, handleCloseWindow); - electron.ipcMain.on(IPC_EVENTS.WINDOW_MINIMIZE, handleMinimizeWindow); - electron.ipcMain.on(IPC_EVENTS.WINDOW_MAXIMIZE, handleMaximizeWindow); - electron.ipcMain.handle(IPC_EVENTS.IS_WINDOW_MAXIMIZED, handleIsWindowMaximized); - electron.ipcMain.handle(IPC_EVENTS.APP_LOAD_PAGE, (e, page) => { - const win = electron.BrowserWindow.fromWebContents(e.sender); - if (win) this._loadPage(win, page); - }); - } - static getInstance() { - if (!this._instance) { - this._instance = new WindowService(); - } - return this._instance; - } - create(name, size, moreOpts) { - if (this.get(name)) return; - const isHiddenWin = this._isHiddenWin(name); - let window2 = this._createWinInstance(name, { ...size, ...moreOpts }); - if (this.isDev) window2.webContents.openDevTools(); - !isHiddenWin && this._setupWinLifecycle(window2, name)._loadWindowTemplate(window2, name); - this._listenWinReady({ - win: window2, - isHiddenWin, - size - }); - if (!isHiddenWin) { - this._winStates[name].instance = window2; - this._winStates[name].onCreate.forEach((callback) => callback(window2)); - } - if (isHiddenWin) { - this._winStates[name].isHidden = false; - logManager.info(`Hidden window show: ${name}`); - } - return window2; - } - _setupWinLifecycle(window2, name) { - const updateWinStatus = debounce(() => !window2?.isDestroyed() && window2?.webContents?.send(IPC_EVENTS.WINDOW_MAXIMIZE + "back", window2?.isMaximized()), 80); - window2.once("closed", () => { - this._winStates[name].onClosed.forEach((callback) => callback(window2)); - window2?.destroy(); - window2?.removeListener("resize", updateWinStatus); - this._winStates[name].instance = void 0; - this._winStates[name].isHidden = false; - logManager.info(`Window closed: ${name}`); - }); - window2.on("resize", updateWinStatus); - return this; - } - _listenWinReady(params) { - const onReady = () => { - params.win?.once("show", () => setTimeout(() => this._applySizeConstraints(params.win, params.size), 2)); - params.win?.show(); - }; - if (!params.isHiddenWin) { - const loadingHandler = this._addLoadingView(params.win, params.size); - loadingHandler?.(onReady); - } else { - onReady(); - } - } - _addLoadingView(window2, size) { - let rendererIsReady = false; - const onRendererIsReady = (e) => { - if (e.sender !== window2?.webContents || rendererIsReady) return; - rendererIsReady = true; - electron.ipcMain.removeListener(IPC_EVENTS.RENDERER_IS_READY, onRendererIsReady); - }; - electron.ipcMain.on(IPC_EVENTS.RENDERER_IS_READY, onRendererIsReady); - return (cb) => { - cb(); - }; - } - _applySizeConstraints(win, size) { - if (size.maxHeight && size.maxWidth) { - win.setMaximumSize(size.maxWidth, size.maxHeight); - } - if (size.minHeight && size.minWidth) { - win.setMinimumSize(size.minWidth, size.minHeight); - } - } - _loadPage(window2, pageName) { - { - return window2.loadURL(`${"http://localhost:5173"}/${pageName}.html`); - } - } - _loadWindowTemplate(window2, name) { - const page = "index"; - this._loadPage(window2, page); - } - _handleCloseWindowState(target, really) { - const name = this.getName(target); - if (name) { - if (!really) this._winStates[name].isHidden = true; - else this._winStates[name].instance = void 0; - } - setTimeout(() => { - target[really ? "close" : "hide"]?.(); - this._checkAndCloseAllWinodws(); - }, 210); - } - _checkAndCloseAllWinodws() { - if (!this._winStates[WINDOW_NAMES.MAIN].instance || this._winStates[WINDOW_NAMES.MAIN].instance?.isDestroyed()) - return Object.values(this._winStates).forEach((win) => win?.instance?.close()); - const minimizeToTray = configManager.get(CONFIG_KEYS.MINIMIZE_TO_TRAY); - if (!minimizeToTray && !this.get(WINDOW_NAMES.MAIN)?.isVisible()) - return Object.values(this._winStates).forEach((win) => !win?.instance?.isVisible() && win?.instance?.close()); - } - _isHiddenWin(name) { - return this._winStates[name] && this._winStates[name].isHidden; - } - _createWinInstance(name, opts) { - return this._isHiddenWin(name) ? this._winStates[name].instance : new electron.BrowserWindow({ - ...SHARED_WINDOW_OPTIONS, - icon: this._logo, - ...opts - }); - } - focus(target) { - if (!target) return; - const name = this.getName(target); - if (target?.isMaximized()) { - target?.restore(); - logManager.debug(`Window ${name} restored and focused`); - } else { - logManager.debug(`Window ${name} focused`); - } - target?.focus(); - } - close(target, really = true) { - if (!target) return; - const name = this.getName(target); - logManager.info(`Close window: ${name}, really: ${really}`); - this._handleCloseWindowState(target, really); - } - toggleMax(target) { - if (!target) return; - target.isMaximized() ? target.unmaximize() : target.maximize(); - } - getName(target) { - if (!target) return; - for (const [name, win] of Object.entries(this._winStates)) { - if (win?.instance === target) return name; - } - } - get(name) { - if (this._winStates[name].isHidden) return void 0; - return this._winStates[name].instance; - } - onWindowCreate(name, callback) { - this._winStates[name].onCreate.push(callback); - } - onWindowClosed(name, callback) { - this._winStates[name].onClosed.push(callback); - } -} -const windowManager = WindowService.getInstance(); -let t$1 = createTranslator(); -class MenuService { - static _instance; - _menuTemplates = /* @__PURE__ */ new Map(); - _currentMenu = void 0; - constructor() { - this._setupIpcListener(); - this._setupLanguageChangeListener(); - logManager.info("MenuService initialized successfully."); - } - _setupIpcListener() { - electron.ipcMain.handle(IPC_EVENTS.SHOW_CONTEXT_MENU, (_, menuId, dynamicOptions) => new Promise((resolve) => this.showMenu(menuId, () => resolve(true), dynamicOptions))); - } - _setupLanguageChangeListener() { - configManager.onConfigChange((config) => { - if (!config[CONFIG_KEYS.LANGUAGE]) return; - t$1 = createTranslator(); - }); - } - static getInstance() { - if (!this._instance) - this._instance = new MenuService(); - return this._instance; - } - register(menuId, template) { - this._menuTemplates.set(menuId, template); - return menuId; - } - showMenu(menuId, onClose, dynamicOptions) { - if (this._currentMenu) return; - const template = cloneDeep(this._menuTemplates.get(menuId)); - if (!template) { - logManager.warn(`Menu ${menuId} not found.`); - onClose?.(); - return; - } - let _dynamicOptions = []; - try { - _dynamicOptions = Array.isArray(dynamicOptions) ? dynamicOptions : JSON.parse(dynamicOptions ?? "[]"); - } catch (error) { - logManager.error(`Failed to parse dynamicOptions for menu ${menuId}: ${error}`); - } - const translationItem = (item) => { - if (item.submenu) { - return { - ...item, - label: t$1(item?.label) ?? void 0, - submenu: item.submenu?.map((item2) => translationItem(item2)) - }; - } - return { - ...item, - label: t$1(item?.label) ?? void 0 - }; - }; - const localizedTemplate = template.map((item) => { - if (!Array.isArray(_dynamicOptions) || !_dynamicOptions.length) { - return translationItem(item); - } - const dynamicItem = _dynamicOptions.find((_item) => _item.id === item.id); - if (dynamicItem) { - const mergedItem = { ...item, ...dynamicItem }; - return translationItem(mergedItem); - } - if (item.submenu) { - return translationItem({ - ...item, - submenu: item.submenu?.map((__item) => { - const dynamicItem2 = _dynamicOptions.find((_item) => _item.id === __item.id); - return { ...__item, ...dynamicItem2 }; - }) - }); - } - return translationItem(item); - }); - const menu2 = electron.Menu.buildFromTemplate(localizedTemplate); - this._currentMenu = menu2; - menu2.popup({ - callback: () => { - this._currentMenu = void 0; - onClose?.(); - } - }); - } - destroyMenu(menuId) { - this._menuTemplates.delete(menuId); - } - destroyed() { - this._menuTemplates.clear(); - this._currentMenu = void 0; - } -} -const menuManager = MenuService.getInstance(); -let t = createTranslator(); -class TrayService { - static _instance; - _tray = null; - _removeLanguageListener; - _setupLanguageChangeListener() { - this._removeLanguageListener = configManager.onConfigChange((config) => { - if (!config[CONFIG_KEYS.LANGUAGE]) return; - t = createTranslator(); - if (this._tray) { - this._updateTray(); - } - }); - } - _updateTray() { - if (!this._tray) { - this._tray = new electron.Tray(createLogo()); - } - const showWindow = () => { - const mainWindow = windowManager.get(WINDOW_NAMES.MAIN); - if (mainWindow && !mainWindow?.isDestroyed() && mainWindow?.isVisible() && !mainWindow?.isFocused()) { - return mainWindow.focus(); - } - if (mainWindow?.isMinimized()) { - return mainWindow?.restore(); - } - if (mainWindow?.isVisible() && mainWindow?.isFocused()) return; - windowManager.create(WINDOW_NAMES.MAIN, MAIN_WIN_SIZE); - }; - this._tray.setToolTip(t("tray.tooltip") ?? "Diona Application"); - this._tray.setContextMenu(electron.Menu.buildFromTemplate([ - { label: t("tray.showWindow"), accelerator: "CmdOrCtrl+N", click: showWindow }, - { type: "separator" }, - { label: t("settings.title"), click: () => electron.ipcMain.emit(`${IPC_EVENTS.OPEN_WINDOW}:${WINDOW_NAMES.SETTING}`) }, - { role: "quit", label: t("tray.exit") } - ])); - this._tray.removeAllListeners("click"); - this._tray.on("click", showWindow); - } - constructor() { - this._setupLanguageChangeListener(); - logManager.info("TrayService initialized successfully."); - } - static getInstance() { - if (!this._instance) { - this._instance = new TrayService(); - } - return this._instance; - } - create() { - if (this._tray) return; - this._updateTray(); - electron.app.on("quit", () => { - this.destroy(); - }); - } - destroy() { - this._tray?.destroy(); - this._tray = null; - if (this._removeLanguageListener) { - this._removeLanguageListener(); - this._removeLanguageListener = void 0; - } - } -} -const trayManager = TrayService.getInstance(); -class TabManager { - win; - views = /* @__PURE__ */ new Map(); - activeId = null; - skipNextNavigate = /* @__PURE__ */ new Map(); - enabled = false; - constructor(win) { - this.win = win; - this.win.on("resize", () => this.updateActiveBounds()); - this._setupIpcEvents(); - } - _setupIpcEvents() { - electron.ipcMain.handle(IPC_EVENTS.TAB_CREATE, (_e, url) => { - const info = this.create(url); - return info; - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_LIST, () => { - return this.list(); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_NAVIGATE, (_e, { tabId, url }) => { - this.navigate(tabId, url); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_RELOAD, (_e, tabId) => { - this.reload(tabId); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_BACK, (_e, tabId) => { - this.goBack(tabId); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_FORWARD, (_e, tabId) => { - this.goForward(tabId); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_SWITCH, (_e, tabId) => { - this.switch(tabId); - }); - electron.ipcMain.handle(IPC_EVENTS.TAB_CLOSE, (_e, tabId) => { - this.close(tabId); - }); - } - enable() { - this.enabled = true; - this.updateActiveBounds(); - if (this.activeId) this.attach(this.activeId); - } - disable() { - this.enabled = false; - const view = this.activeId ? this.views.get(this.activeId) : null; - if (view) this.win.removeBrowserView(view); - } - destroy() { - this.disable(); - this.views.forEach((view) => { - view.webContents.destroy(); - }); - this.views.clear(); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_CREATE); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_LIST); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_NAVIGATE); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_RELOAD); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_BACK); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_FORWARD); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_SWITCH); - electron.ipcMain.removeHandler(IPC_EVENTS.TAB_CLOSE); - } - list() { - return Array.from(this.views.entries()).map(([id, view]) => this.info(id, view)); - } - create(url, active = true) { - const id = crypto.randomUUID(); - const view = new electron.BrowserView({ - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - sandbox: true, - preload: path$1.join(process.cwd(), "dist-electron/preload/preload.js") - } - }); - this.views.set(id, view); - if (this.enabled && active) this.attach(id); - const target = url && url.length > 0 ? url : "about:blank"; - view.webContents.loadURL(target); - this.bindEvents(id, view); - const info = this.info(id, view); - this.win.webContents.send("tab-created", info); - return info; - } - switch(tabId) { - if (!this.views.has(tabId)) return; - if (this.enabled) this.attach(tabId); - this.win.webContents.send("tab-switched", { tabId }); - } - close(tabId) { - const view = this.views.get(tabId); - if (!view) return; - if (this.activeId === tabId) { - this.win.removeBrowserView(view); - this.activeId = null; - } - view.webContents.destroy(); - this.views.delete(tabId); - this.win.webContents.send("tab-closed", { tabId }); - const next = this.views.keys().next().value; - if (next) this.switch(next); - } - navigate(tabId, url) { - const view = this.views.get(tabId); - if (!view) return; - this.skipNextNavigate.set(tabId, true); - view.webContents.loadURL(url); - } - reload(tabId) { - const view = this.views.get(tabId); - if (!view) return; - view.webContents.reload(); - } - goBack(tabId) { - const view = this.views.get(tabId); - if (!view) return; - if (view.webContents.canGoBack()) view.webContents.goBack(); - } - goForward(tabId) { - const view = this.views.get(tabId); - if (!view) return; - if (view.webContents.canGoForward()) view.webContents.goForward(); - } - attach(tabId) { - if (!this.enabled) return; - const view = this.views.get(tabId); - if (!view) return; - if (this.activeId && this.views.get(this.activeId)) { - const prev = this.views.get(this.activeId); - this.win.removeBrowserView(prev); - } - this.activeId = tabId; - this.win.addBrowserView(view); - this.updateActiveBounds(); - } - updateActiveBounds() { - if (!this.enabled || !this.activeId) return; - const view = this.views.get(this.activeId); - if (!view) return; - const [winWidth, winHeight] = this.win.getContentSize(); - const HEADER_HEIGHT = 88; - const PADDING = 8; - const RIGHT_PANEL_WIDTH = 392 + 80 + 8 + 8; - const x = PADDING; - const y = HEADER_HEIGHT + PADDING; - const width = winWidth - RIGHT_PANEL_WIDTH - PADDING; - const height = winHeight - HEADER_HEIGHT - PADDING * 2; - view.setBounds({ - x, - y, - width: Math.max(0, width), - height: Math.max(0, height) - }); - } - bindEvents(id, view) { - const send = () => this.win.webContents.send("tab-updated", this.info(id, view)); - view.webContents.on("did-start-loading", send); - view.webContents.on("did-stop-loading", send); - view.webContents.on("did-finish-load", send); - view.webContents.on("page-title-updated", send); - view.webContents.on("did-navigate", send); - view.webContents.on("did-navigate-in-page", send); - view.webContents.on("will-navigate", (event, url) => { - if (this.skipNextNavigate.get(id)) { - this.skipNextNavigate.set(id, false); - return; - } - event.preventDefault(); - this.create(url); - }); - view.webContents.setWindowOpenHandler(({ url }) => { - this.create(url); - return { action: "deny" }; - }); - } - info(id, view) { - const wc = view.webContents; - return { - id, - url: wc.getURL(), - title: wc.getTitle(), - isLoading: wc.isLoading(), - canGoBack: wc.canGoBack(), - canGoForward: wc.canGoForward() - }; - } -} -const handleTray = (minimizeToTray) => { - if (minimizeToTray) { - trayManager.create(); - return; - } - trayManager.destroy(); -}; -const registerMenus = (window2) => { - const conversationItemMenuItemClick = (id) => { - logManager.logUserOperation(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.CONVERSATION_ITEM}-${id}`); - window2.webContents.send(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.CONVERSATION_ITEM}`, id); - }; - menuManager.register(MENU_IDS.CONVERSATION_ITEM, [ - { - id: CONVERSATION_ITEM_MENU_IDS.PIN, - label: "menu.conversation.pinConversation", - click: () => conversationItemMenuItemClick(CONVERSATION_ITEM_MENU_IDS.PIN) - }, - { - id: CONVERSATION_ITEM_MENU_IDS.RENAME, - label: "menu.conversation.renameConversation", - click: () => conversationItemMenuItemClick(CONVERSATION_ITEM_MENU_IDS.RENAME) - }, - { - id: CONVERSATION_ITEM_MENU_IDS.DEL, - label: "menu.conversation.delConversation", - click: () => conversationItemMenuItemClick(CONVERSATION_ITEM_MENU_IDS.DEL) - } - ]); - const conversationListMenuItemClick = (id) => { - logManager.logUserOperation(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.CONVERSATION_LIST}-${id}`); - window2.webContents.send(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.CONVERSATION_LIST}`, id); - }; - menuManager.register(MENU_IDS.CONVERSATION_LIST, [ - { - id: CONVERSATION_LIST_MENU_IDS.NEW_CONVERSATION, - label: "menu.conversation.newConversation", - click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.NEW_CONVERSATION) - }, - { type: "separator" }, - { - id: CONVERSATION_LIST_MENU_IDS.SORT_BY, - label: "menu.conversation.sortBy", - submenu: [ - { id: CONVERSATION_LIST_MENU_IDS.SORT_BY_CREATE_TIME, label: "menu.conversation.sortByCreateTime", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_BY_CREATE_TIME) }, - { id: CONVERSATION_LIST_MENU_IDS.SORT_BY_UPDATE_TIME, label: "menu.conversation.sortByUpdateTime", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_BY_UPDATE_TIME) }, - { id: CONVERSATION_LIST_MENU_IDS.SORT_BY_NAME, label: "menu.conversation.sortByName", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_BY_NAME) }, - { id: CONVERSATION_LIST_MENU_IDS.SORT_BY_MODEL, label: "menu.conversation.sortByModel", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_BY_MODEL) }, - { type: "separator" }, - { id: CONVERSATION_LIST_MENU_IDS.SORT_ASCENDING, label: "menu.conversation.sortAscending", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_ASCENDING) }, - { id: CONVERSATION_LIST_MENU_IDS.SORT_DESCENDING, label: "menu.conversation.sortDescending", type: "radio", checked: false, click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.SORT_DESCENDING) } - ] - }, - { - id: CONVERSATION_LIST_MENU_IDS.BATCH_OPERATIONS, - label: "menu.conversation.batchOperations", - click: () => conversationListMenuItemClick(CONVERSATION_LIST_MENU_IDS.BATCH_OPERATIONS) - } - ]); - const messageItemMenuItemClick = (id) => { - logManager.logUserOperation(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.MESSAGE_ITEM}-${id}`); - window2.webContents.send(`${IPC_EVENTS.SHOW_CONTEXT_MENU}:${MENU_IDS.MESSAGE_ITEM}`, id); - }; - menuManager.register(MENU_IDS.MESSAGE_ITEM, [ - { - id: MESSAGE_ITEM_MENU_IDS.COPY, - label: "menu.message.copyMessage", - click: () => messageItemMenuItemClick(MESSAGE_ITEM_MENU_IDS.COPY) - }, - { - id: MESSAGE_ITEM_MENU_IDS.SELECT, - label: "menu.message.selectMessage", - click: () => messageItemMenuItemClick(MESSAGE_ITEM_MENU_IDS.SELECT) - }, - { type: "separator" }, - { - id: MESSAGE_ITEM_MENU_IDS.DELETE, - label: "menu.message.deleteMessage", - click: () => messageItemMenuItemClick(MESSAGE_ITEM_MENU_IDS.DELETE) - } - ]); -}; -function setupMainWindow() { - windowManager.onWindowCreate(WINDOW_NAMES.MAIN, (mainWindow) => { - let minimizeToTray = configManager.get(CONFIG_KEYS.MINIMIZE_TO_TRAY); - configManager.onConfigChange((config) => { - if (minimizeToTray === config[CONFIG_KEYS.MINIMIZE_TO_TRAY]) return; - minimizeToTray = config[CONFIG_KEYS.MINIMIZE_TO_TRAY]; - handleTray(minimizeToTray); - }); - handleTray(minimizeToTray); - registerMenus(mainWindow); - const tabManager = new TabManager(mainWindow); - tabManager.enable(); - mainWindow.on("closed", () => { - tabManager.destroy(); - }); - }); - windowManager.create(WINDOW_NAMES.MAIN, MAIN_WIN_SIZE); - electron.ipcMain.on(IPC_EVENTS.START_A_DIALOGUE, async (_event, props) => { - const { providerName, messages: messages2, messageId, selectedModel } = props; - const mainWindow = windowManager.get(WINDOW_NAMES.MAIN); - if (!mainWindow) { - throw new Error("mainWindow not found"); - } - try { - const provider = createProvider(providerName); - const chunks = await provider?.chat(messages2, selectedModel); - if (!chunks) { - throw new Error("chunks or stream not found"); - } - for await (const chunk of chunks) { - const chunkContent = { - messageId, - data: chunk - }; - mainWindow.webContents.send(IPC_EVENTS.START_A_DIALOGUE + "back" + messageId, chunkContent); - } - } catch (error) { - const errorContent = { - messageId, - data: { - isEnd: true, - isError: true, - result: error instanceof Error ? error.message : String(error) - } - }; - mainWindow.webContents.send(IPC_EVENTS.START_A_DIALOGUE + "back" + messageId, errorContent); - } - }); -} -function getChromePath() { - if (process.platform === "win32") { - return "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"; - } - if (process.platform === "darwin") { - return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; - } - if (process.platform === "linux") { - return "google-chrome"; - } -} -function getProfileDir(accountId) { - return path$1.join(electron.app.getPath("userData"), `profiles`, accountId); -} -function isPortInUse(port) { - return new Promise((resolve) => { - const server = net.createServer(); - server.once("error", (err) => resolve(true)); - server.once("listening", () => { - server.close(); - resolve(false); - }); - server.listen(port); - }); -} -async function isChromeRunning() { - try { - return new Promise((resolve) => { - const req = http.get("http://127.0.0.1:9222/json/version", (res) => { - resolve(res.statusCode === 200); - }); - req.on("error", () => resolve(false)); - req.setTimeout(1e3, () => { - req.destroy(); - resolve(false); - }); - }); - } catch (error) { - return false; - } -} -async function launchLocalChrome() { - const chromePath = getChromePath(); - const profileDir = getProfileDir("default"); - log.info(`Launching Chrome with user data dir: ${profileDir}`); - const portInUse = await isPortInUse(9222); - if (portInUse) { - log.info("Chrome already running on port 9222, skip launching."); - return; - } - if (await isChromeRunning()) { - log.info("Chrome already running, skip launching."); - return; - } - return new Promise((resolve, reject) => { - const chromeProcess = child_process.spawn(chromePath, [ - "--remote-debugging-port=9222", - "--window-size=1920,1080", - "--window-position=0,0", - "--no-first-run", - `--user-data-dir=${profileDir}`, - "--no-default-browser-check", - "about:blank" - // '--window-maximized', - ], { - detached: true, - stdio: "ignore" - }); - chromeProcess.on("error", reject); - setTimeout(() => { - resolve(0); - }, 1e3); - }); -} -class executeScriptService extends events.EventEmitter { - // 执行脚本 - async executeScript(scriptPath, options) { - const MAX_TAIL = 32 * 1024; - const appendTail = (current, chunk) => { - const next = current + chunk; - return next.length > MAX_TAIL ? next.slice(next.length - MAX_TAIL) : next; - }; - return await new Promise((resolve) => { - try { - const roomType = options?.roomType ?? ""; - const startTime = options?.startTime ?? ""; - const endTime = options?.endTime ?? ""; - const operation = options?.operation ?? ""; - const tabIndex = options?.tabIndex ?? ""; - const channels = options?.channels ?? ""; - const startTabIndex = options?.startTabIndex ?? ""; - const child = electron.utilityProcess.fork(scriptPath, [], { - env: { - ...process.env, - ROOM_TYPE: String(roomType), - START_DATE: String(startTime), - END_DATE: String(endTime), - OPERATION: String(operation), - TAB_INDEX: String(tabIndex), - CHANNELS: typeof channels === "string" ? channels : JSON.stringify(channels), - START_TAB_INDEX: String(startTabIndex) - }, - stdio: "pipe" - }); - let stdoutTail = ""; - let stderrTail = ""; - if (child.stdout) { - child.stdout.on("data", (data) => { - const text = data.toString(); - stdoutTail = appendTail(stdoutTail, text); - log.info(`stdout: ${text}`); - }); - } - if (child.stderr) { - child.stderr.on("data", (data) => { - const text = data.toString(); - stderrTail = appendTail(stderrTail, text); - log.info(`stderr: ${text}`); - }); - } - child.on("exit", (code) => { - log.info(`子进程退出,退出码 ${code}`); - resolve({ - success: code === 0, - exitCode: code, - stdoutTail, - stderrTail, - ...code === 0 ? {} : { error: `Script exited with code ${code}` } - }); - }); - } catch (error) { - resolve({ - success: false, - exitCode: null, - stdoutTail: "", - stderrTail: "", - error: error?.message || "运行 Node 脚本时出错" - }); - } - }); - } -} -const openedTabIndexByChannelName = /* @__PURE__ */ new Map(); -function getScriptsDir() { - return electron.app.isPackaged ? path.join(__dirname, "scripts") : path.join(process.cwd(), "electron/scripts"); -} -function runTaskOperationService() { - const executeScriptServiceInstance = new executeScriptService(); - electron.ipcMain.handle(IPC_EVENTS.OPEN_CHANNEL, async (_event, channels) => { - try { - await launchLocalChrome(); - const scriptsDir = getScriptsDir(); - const scriptPath = path.join(scriptsDir, "open_all_channel.js"); - openedTabIndexByChannelName.clear(); - if (Array.isArray(channels)) { - for (let i = 0; i < channels.length; i++) { - const name = channels[i]?.channelName; - if (name) openedTabIndexByChannelName.set(String(name), i); - } - } - const result = await executeScriptServiceInstance.executeScript(scriptPath, { channels }); - return { success: true, result }; - } catch (error) { - return { success: false, error: error?.message || "open channel failed" }; - } - }); - electron.ipcMain.handle(IPC_EVENTS.EXECUTE_SCRIPT, async (_event, options) => { - try { - const roomType = options.roomList.find((item) => item.id === options.roomType); - const pairs = [ - ["fzName", "fg_trace.js"], - ["mtName", "mt_trace.js"], - ["dyHotelName", "dy_hotel_trace.js"], - ["dyHotSpringName", "dy_hot_spring_trace.js"] - ]; - const scriptEntries = pairs.filter(([prop]) => roomType?.[prop]); - const scriptsDir = getScriptsDir(); - const scriptPaths = scriptEntries.map(([channel, fileName]) => { - const p = path.join(scriptsDir, fileName); - if (!fs.existsSync(p)) { - throw new Error(`Script not found for channel ${channel}: ${p}`); - } - return { channel, scriptPath: p }; - }); - const results = []; - for (let i = 0; i < scriptPaths.length; i++) { - const item = scriptPaths[i]; - const channelNameMap = { - fzName: "fliggy", - mtName: "meituan", - dyHotelName: "douyin", - dyHotSpringName: "douyin" - }; - const defaultTabIndexMap = { - fliggy: 0, - meituan: 1, - douyin: 2 - }; - const mappedName = channelNameMap[item.channel]; - const tabIndex = mappedName ? openedTabIndexByChannelName.get(mappedName) ?? defaultTabIndexMap[mappedName] ?? i : i; - log.info(`Launching script for channel ${item.channel}: ${item.scriptPath} (tabIndex: ${tabIndex})`); - const result = await executeScriptServiceInstance.executeScript(item.scriptPath, { - roomType: roomType[item.channel], - startTime: options.startTime, - endTime: options.endTime, - operation: options.operation, - tabIndex - }); - results.push({ - channel: item.channel, - scriptPath: item.scriptPath, - ...result - }); - } - return { success: true, result: results }; - } catch (error) { - return { success: false, error: error.message }; - } - }); -} -class AppUpdater { - mainWindow = null; - static _instance; - _initialized = false; - constructor() { - electronUpdater.autoUpdater.autoDownload = false; - } - init() { - if (this._initialized) return; - this._initialized = true; - this.setupListeners(); - this.registerHandlers(); - } - static getInstance() { - if (!this._instance) { - this._instance = new AppUpdater(); - } - return this._instance; - } - setMainWindow(window2) { - this.mainWindow = window2; - } - setupListeners() { - electronUpdater.autoUpdater.on("checking-for-update", () => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "checking" })); - electronUpdater.autoUpdater.on("update-available", (info) => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "available", info })); - electronUpdater.autoUpdater.on("update-not-available", () => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "not-available" })); - electronUpdater.autoUpdater.on("download-progress", (progress) => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "downloading", progress })); - electronUpdater.autoUpdater.on("update-downloaded", (info) => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "downloaded", info })); - electronUpdater.autoUpdater.on("error", (error) => this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "error", error: error.message })); - } - sendToRenderer(channel, data) { - electron.BrowserWindow.getAllWindows().forEach((win) => { - if (!win.isDestroyed()) { - win.webContents.send(channel, data); - } - }); - } - registerHandlers() { - electron.ipcMain.handle(IPC_EVENTS.UPDATE_CHECK, () => { - if (electron.app.isPackaged) { - return electronUpdater.autoUpdater.checkForUpdates(); - } else { - this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "checking" }); - setTimeout(() => { - this.sendToRenderer(IPC_EVENTS.UPDATE_STATUS_CHANGED, { status: "not-available" }); - }, 1500); - return null; - } - }); - electron.ipcMain.handle(IPC_EVENTS.UPDATE_DOWNLOAD, () => { - if (electron.app.isPackaged) { - return electronUpdater.autoUpdater.downloadUpdate(); - } - return null; - }); - electron.ipcMain.handle(IPC_EVENTS.UPDATE_INSTALL, () => { - if (electron.app.isPackaged) { - return electronUpdater.autoUpdater.quitAndInstall(); - } - return null; - }); - electron.ipcMain.handle(IPC_EVENTS.UPDATE_VERSION, () => { - return electron.app.getVersion(); - }); - } -} -const appUpdater = AppUpdater.getInstance(); -appUpdater.init(); -if (started) { - electron.app.quit(); -} -electron.app.whenReady().then(() => { - setupMainWindow(); - runTaskOperationService(); -}); -electron.app.on("window-all-closed", () => { - if (process.platform !== "darwin" && !configManager.get(CONFIG_KEYS.MINIMIZE_TO_TRAY)) { - log.info("app closing due to all windows being closed"); - electron.app.quit(); - } -}); -electron.app.on("activate", () => { - if (electron.BrowserWindow.getAllWindows().length === 0) { - setupMainWindow(); - } -}); +require('bytenode') +require('./main.jsc') \ No newline at end of file diff --git a/dist-electron/main/main.js.bak b/dist-electron/main/main.js.bak index dde931f..6995c38 100644 --- a/dist-electron/main/main.js.bak +++ b/dist-electron/main/main.js.bak @@ -1 +1 @@ -"use strict";const o=require("electron"),oe=require("openai"),G=require("util"),h=require("electron-log"),W=require("path"),Q=require("fs"),V=require("js-base64"),O=require("node:path"),re=require("crypto"),ae=require("electron-squirrel-startup"),ce=require("net"),le=require("http"),de=require("child_process"),ue=require("events");require("bytenode");function ee(n){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const t in n)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>n[t]})}}return e.default=n,Object.freeze(e)}const S=ee(W),v=ee(Q);var a=(n=>(n.EXTERNAL_OPEN="external-open",n.WINDOW_MINIMIZE="window-minimize",n.WINDOW_MAXIMIZE="window-maximize",n.WINDOW_CLOSE="window-close",n.IS_WINDOW_MAXIMIZED="is-window-maximized",n.APP_SET_FRAMELESS="app:set-frameless",n.APP_LOAD_PAGE="app:load-page",n.TAB_CREATE="tab:create",n.TAB_LIST="tab:list",n.TAB_NAVIGATE="tab:navigate",n.TAB_RELOAD="tab:reload",n.TAB_BACK="tab:back",n.TAB_FORWARD="tab:forward",n.TAB_SWITCH="tab:switch",n.TAB_CLOSE="tab:close",n.LOG_TO_MAIN="log-to-main",n.READ_FILE="read-file",n.INVOKE="ipc:invoke",n.INVOKE_ASYNC="ipc:invokeAsync",n.APP_MINIMIZE="app:minimize",n.APP_MAXIMIZE="app:maximize",n.APP_QUIT="app:quit",n.FILE_READ="file:read",n.FILE_WRITE="file:write",n.GET_WINDOW_ID="get-window-id",n.CUSTOM_EVENT="custom:event",n.TIME_UPDATE="time:update",n.RENDERER_IS_READY="renderer-ready",n.SHOW_CONTEXT_MENU="show-context-menu",n.START_A_DIALOGUE="start-a-dialogue",n.OPEN_WINDOW="open-window",n.LOG_DEBUG="log-debug",n.LOG_INFO="log-info",n.LOG_WARN="log-warn",n.LOG_ERROR="log-error",n.CONFIG_UPDATED="config-updated",n.SET_CONFIG="set-config",n.GET_CONFIG="get-config",n.UPDATE_CONFIG="update-config",n.SET_THEME_MODE="set-theme-mode",n.GET_THEME_MODE="get-theme-mode",n.IS_DARK_THEME="is-dark-theme",n.THEME_MODE_UPDATED="theme-mode-updated",n.EXECUTE_SCRIPT="execute-script",n.OPEN_CHANNEL="open-channel",n))(a||{});const te={width:1440,height:900,minWidth:1440,minHeight:900};var w=(n=>(n.MAIN="main",n.SETTING="setting",n.DIALOG="dialog",n.LOADING="loading",n))(w||{}),g=(n=>(n.THEME_MODE="themeMode",n.PRIMARY_COLOR="primaryColor",n.LANGUAGE="language",n.FONT_SIZE="fontSize",n.MINIMIZE_TO_TRAY="minimizeToTray",n.PROVIDER="provider",n.DEFAULT_MODEL="defaultModel",n))(g||{}),y=(n=>(n.CONVERSATION_ITEM="conversation-item",n.CONVERSATION_LIST="conversation-list",n.MESSAGE_ITEM="message-item",n))(y||{}),E=(n=>(n.PIN="pin",n.RENAME="rename",n.DEL="del",n))(E||{}),m=(n=>(n.NEW_CONVERSATION="newConversation",n.SORT_BY="sortBy",n.SORT_BY_CREATE_TIME="sortByCreateTime",n.SORT_BY_UPDATE_TIME="sortByUpdateTime",n.SORT_BY_NAME="sortByName",n.SORT_BY_MODEL="sortByModel",n.SORT_ASCENDING="sortAscending",n.SORT_DESCENDING="sortDescending",n.BATCH_OPERATIONS="batchOperations",n))(m||{}),I=(n=>(n.COPY="copy",n.DELETE="delete",n.SELECT="select",n))(I||{});class he{}const pe=G.promisify(v.readdir),ge=G.promisify(v.stat),fe=G.promisify(v.unlink);class U{static _instance;LOG_RETENTION_DAYS=7;CLEANUP_INTERVAL_MS=1440*60*1e3;constructor(){const e=S.join(o.app.getPath("userData"),"logs");try{v.existsSync(e)||v.mkdirSync(e,{recursive:!0})}catch(t){this.error("Failed to create log directory:",t)}h.transports.file.resolvePathFn=()=>{const t=new Date,i=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`;return S.join(e,`${i}.log`)},h.transports.file.format="[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}",h.transports.file.maxSize=10*1024*1024,h.transports.console.level=process.env.NODE_ENV==="development"?"debug":"info",h.transports.file.level="debug",this._setupIpcEvents(),this._rewriteConsole(),this.info("LogService initialized successfully."),this._cleanupOldLogs(),setInterval(()=>this._cleanupOldLogs(),this.CLEANUP_INTERVAL_MS)}_setupIpcEvents(){o.ipcMain.on(a.LOG_DEBUG,(e,t,...i)=>this.debug(t,...i)),o.ipcMain.on(a.LOG_INFO,(e,t,...i)=>this.info(t,...i)),o.ipcMain.on(a.LOG_WARN,(e,t,...i)=>this.warn(t,...i)),o.ipcMain.on(a.LOG_ERROR,(e,t,...i)=>this.error(t,...i))}_rewriteConsole(){console.debug=h.debug,console.log=h.info,console.info=h.info,console.warn=h.warn,console.error=h.error}async _cleanupOldLogs(){try{const e=S.join(o.app.getPath("userData"),"logs");if(!v.existsSync(e))return;const t=new Date,i=new Date(t.getTime()-this.LOG_RETENTION_DAYS*24*60*60*1e3),s=await pe(e);let r=0;for(const c of s){if(!c.endsWith(".log"))continue;const d=S.join(e,c);try{const f=await ge(d);f.isFile()&&f.birthtime0&&this.info(`Successfully cleaned up ${r} old log files.`)}catch(e){this.error("Failed to cleanup old logs:",e)}}static getInstance(){return this._instance||(this._instance=new U),this._instance}debug(e,...t){h.debug(e,...t)}info(e,...t){h.info(e,...t)}warn(e,...t){h.warn(e,...t)}error(e,...t){h.error(e,...t)}logApiRequest(e,t={},i="POST"){this.info(`API Request: ${e}, Method: ${i}, Request: ${JSON.stringify(t)}`)}logApiResponse(e,t={},i=200,s=0){i>=400?this.error(`API Error Response: ${e}, Status: ${i}, Response Time: ${s}ms, Response: ${JSON.stringify(t)}`):this.debug(`API Response: ${e}, Status: ${i}, Response Time: ${s}ms, Response: ${JSON.stringify(t)}`)}logUserOperation(e,t="unknown",i={}){this.info(`User Operation: ${e} by ${t}, Details: ${JSON.stringify(i)}`)}}const u=U.getInstance();function me(n){const e=n.choices[0];return{isEnd:e?.finish_reason==="stop",result:e?.delta?.content??""}}class _e extends he{client;constructor(e,t){super(),this.client=new oe({apiKey:e,baseURL:t})}async chat(e,t){const i=Date.now(),s=e[e.length-1];u.logApiRequest("chat.completions.create",{model:t,lastMessage:s?.content?.substring(0,100)+(s?.content?.length>100?"...":""),messageCount:e.length},"POST");try{const r=await this.client.chat.completions.create({model:t,messages:e,stream:!0}),c=Date.now()-i;return u.logApiResponse("chat.completions.create",{success:!0},200,c),{async*[Symbol.asyncIterator](){for await(const d of r)yield me(d)}}}catch(r){const c=Date.now()-i;throw u.logApiResponse("chat.completions.create",{error:r instanceof Error?r.message:String(r)},500,c),r}}}function ne(n,e){let t=null;return function(...i){t&&clearTimeout(t),t=setTimeout(()=>{n.apply(this,i)},e)}}function H(n){if(n===null||typeof n!="object")return n;if(Array.isArray(n))return n.map(t=>H(t));const e=Object.assign({},n);for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(e[t]=H(e[t]));return e}function we(n){try{return JSON.parse(JSON.stringify(n))}catch(e){return console.error("simpleCloneDeep failed:",e),n}}function Ae(n){try{return JSON.parse(V.decode(n))}catch(e){return console.error("parseOpenAISetting failed:",e),{}}}const Te={[g.THEME_MODE]:"system",[g.PRIMARY_COLOR]:"#BB5BE7",[g.LANGUAGE]:"zh",[g.FONT_SIZE]:14,[g.MINIMIZE_TO_TRAY]:!1,[g.PROVIDER]:"",[g.DEFAULT_MODEL]:null};class z{static _instance;_config;_configPath;_defaultConfig=Te;_listeners=[];constructor(){this._configPath=S.join(o.app.getPath("userData"),"config.json"),this._config=this._loadConfig(),this._setupIpcEvents(),u.info("ConfigService initialized successfully.")}_setupIpcEvents(){const t=ne(i=>this.update(i),200);o.ipcMain.handle(a.GET_CONFIG,(i,s)=>this.get(s)),o.ipcMain.on(a.SET_CONFIG,(i,s,r)=>this.set(s,r)),o.ipcMain.on(a.UPDATE_CONFIG,(i,s)=>t(s))}static getInstance(){return this._instance||(this._instance=new z),this._instance}_loadConfig(){try{if(v.existsSync(this._configPath)){const e=v.readFileSync(this._configPath,"utf-8"),t={...this._defaultConfig,...JSON.parse(e)};return u.info("Config loaded successfully from:",this._configPath),t}}catch(e){u.error("Failed to load config:",e)}return{...this._defaultConfig}}_saveConfig(){try{v.mkdirSync(S.dirname(this._configPath),{recursive:!0}),v.writeFileSync(this._configPath,JSON.stringify(this._config,null,2),"utf-8"),this._notifyListeners(),u.info("Config saved successfully to:",this._configPath)}catch(e){u.error("Failed to save config:",e)}}_notifyListeners(){o.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(a.CONFIG_UPDATED,this._config)),this._listeners.forEach(e=>e({...this._config}))}getConfig(){return we(this._config)}get(e){return this._config[e]}set(e,t,i=!0){!(e in this._config)||this._config[e]===t||(this._config[e]=t,u.debug(`Config set: ${e} = ${t}`),i&&this._saveConfig())}update(e,t=!0){this._config={...this._config,...e},t&&this._saveConfig()}resetToDefault(){this._config={...this._defaultConfig},u.info("Config reset to default."),this._saveConfig()}onConfigChange(e){return this._listeners.push(e),()=>this._listeners=this._listeners.filter(t=>t!==e)}}const T=z.getInstance();process.env.BIGMODEL_API_KEY,new Date().getTime(),new Date().getTime(),process.env.DEEPSEEK_API_KEY,new Date().getTime(),new Date().getTime(),process.env.SILICONFLOW_API_KEY,new Date().getTime(),new Date().getTime(),process.env.QIANFAN_API_KEY,new Date().getTime(),new Date().getTime();const ye=()=>{let n=[],e=!1;const t=T.get(g.PROVIDER),i=s=>({...s,openAISetting:typeof s.openAISetting=="string"?Ae(s.openAISetting??""):s.openAISetting});try{n=JSON.parse(V.decode(t)),e=!0}catch(s){u.error(`parse base64 provider failed: ${s}`)}if(!e)try{n=JSON.parse(t)}catch(s){u.error(`parse provider failed: ${s}`)}if(n.length)return n.map(i)},ve=()=>{try{return ye()}catch(n){return u.error(`get provider config failed: ${n}`),null}};function Me(n){const e=ve();if(!e)throw new Error("provider config not found");for(const t of e)if(t.name===n){if(!t.openAISetting?.apiKey||!t.openAISetting?.baseURL)throw new Error("apiKey or baseURL not found");return new _e(t.openAISetting.apiKey,t.openAISetting.baseURL)}}const Ee={minimize:"Minimize",maximize:"Maximize",restore:"Restore",close:"Close"},Ie={welcome:{helloMessage:"Hello, I'm Diona"},conversation:{placeholder:"Type a message...",newConversation:"New Conversation",selectModel:"Please select model",createConversation:"Create Conversation",searchPlaceholder:"Search conversations...",goSettings:"Go to",settings:"Settings Window",addModel:"to add a model",dialog:{title:"Confirm Deletion",content:"Are you sure you want to delete this conversation?",content_1:"Are you sure you want to delete the selected conversations? This action cannot be undone."},operations:{pin:"Pin Selected",del:"Delete Selected",selectAll:"Select All",cancel:"Cancel"}},sidebar:{conversations:"Conversations",settings:"Settings",help:"Help"},message:{dialog:{title:"Confirm Deletion",messageDelete:"Are you sure you want to delete this message?",batchDelete:"Are you sure you want to delete the selected messages?",copySuccess:"Copied successfully"},batchActions:{deleteSelected:"Delete Selected"},rendering:"Thinking...",stoppedGeneration:"(Stopped generating)",sending:"Sending",stopGeneration:"Stop generating",send:"Send"}},Oe={cancel:"Cancel",confirm:"Confirm"},Ce={title:"Settings",base:"Basic Settings",provider:{modelConfig:"Model Configuration"},theme:{label:"Theme Settings",dark:"Dark Theme",light:"Light Theme",system:"System Theme",primaryColor:"Primary Color"},appearance:{fontSize:"Font Size",fontSizeOptions:{10:"Tiny (10px)",12:"Small (12px)",14:"Normal (14px)",16:"Medium (16px)",18:"Large (18px)",20:"Larger (20px)",24:"Extra Large (24px)"}},behavior:{minimizeToTray:"Minimize to tray when closed"},language:{label:"Language"},providers:{defaultModel:"Default Model",apiKey:"API Key",apiUrl:"API URL"}},Se={conversation:{newConversation:"New Conversation",sortBy:"Sort By",sortByCreateTime:"Sort by Creation Time",sortByUpdateTime:"Sort by Update Time",sortByName:"Sort by Name",sortByModel:"Sort by Model",sortAscending:"Ascending",sortDescending:"Descending",pinConversation:"Pin Conversation",unpinConversation:"Unpin Conversation",renameConversation:"Rename Conversation",delConversation:"Delete Conversation",batchOperations:"Batch Operations"},message:{copyMessage:"Copy Message",deleteMessage:"Delete Message",selectMessage:"Select Message"}},be={tooltip:"Diona Application",showWindow:"Show Window",exit:"Exit"},De={justNow:"Just now",minutes:"{count} minutes ago",hours:"{count} hours ago",days:"{count} days ago",months:"{count} months ago",years:"{count} years ago",weekday:{sun:"Sunday",mon:"Monday",tue:"Tuesday",wed:"Wednesday",thu:"Thursday",fri:"Friday",sat:"Saturday"}},Re={title:"Diona Application"},Ne={window:Ee,main:Ie,dialog:Oe,settings:Ce,menu:Se,tray:be,timeAgo:De,app:Re},Le={minimize:"最小化",maximize:"最大化",restore:"还原",close:"关闭"},We={welcome:{helloMessage:"你好,我是迪奥娜"},conversation:{placeholder:"输入消息...",newConversation:"新对话",selectModel:"请选择模型",createConversation:"创建对话",searchPlaceholder:"搜索对话...",goSettings:"快去",settings:"设置窗口",addModel:"添加模型",dialog:{title:"确认删除",content:"确定要删除这个对话吗?",content_1:"确定要删除选中的对话吗?此操作不可撤销。"},operations:{pin:"置顶所选",del:"删除所选",selectAll:"全选",cancel:"取消"}},sidebar:{conversations:"对话",settings:"设置",help:"帮助"},message:{dialog:{title:"确认删除",messageDelete:"确认删除该条消息?",batchDelete:"确认删除选中的消息?",copySuccess:"复制成功"},batchActions:{deleteSelected:"删除选中项"},rendering:"思考中...",stoppedGeneration:"(已停止生成)",sending:"发送中",stopGeneration:"停止生成",send:"发送"}},Be={cancel:"取消",confirm:"确认"},ke={title:"设置",base:"基础设置",provider:{modelConfig:"模型配置"},providers:{defaultModel:"默认模型",apiKey:"API密钥",apiUrl:"API地址"},theme:{label:"主题设置",dark:"深色主题",light:"浅色主题",system:"跟随系统",primaryColor:"主题颜色"},appearance:{fontSize:"字体大小",fontSizeOptions:{10:"极小 (10px)",12:"小 (12px)",14:"正常 (14px)",16:"中 (16px)",18:"大 (18px)",20:"较大 (20px)",24:"超大 (24px)"}},behavior:{minimizeToTray:"关闭时最小化到托盘"},language:{label:"语言设置"}},xe={conversation:{newConversation:"新建对话",sortBy:"排序方式",sortByCreateTime:"按创建时间排序",sortByUpdateTime:"按更新时间排序",sortByName:"按名称排序",sortByModel:"按模型排序",sortAscending:"递增",sortDescending:"递减",pinConversation:"置顶对话",unpinConversation:"取消置顶",renameConversation:"重命名对话",delConversation:"删除对话",batchOperations:"批量操作"},message:{copyMessage:"复制消息",deleteMessage:"删除消息",selectMessage:"选择消息"}},Pe={tooltip:"迪奥娜",showWindow:"显示窗口",exit:"退出"},$e={justNow:"刚刚",minutes:"{count}分钟前",hours:"{count}小时前",days:"{count}天前",months:"{count}个月前",years:"{count}年前",weekday:{sun:"星期日",mon:"星期一",tue:"星期二",wed:"星期三",thu:"星期四",fri:"星期五",sat:"星期六"}},He={title:"迪奥娜"},Ge={window:Le,main:We,dialog:Be,settings:ke,menu:xe,tray:Pe,timeAgo:$e,app:He},Ue={en:Ne,zh:Ge};function k(){return n=>{if(n)try{const e=n?.split(".");let t=Ue[T.get(g.LANGUAGE)];for(const i of e)t=t[i];return t}catch(e){return u.error("failed to translate key:",n,e),n}}}let B;function ie(){if(B!=null)return B;const n=o.app.getAppPath();return B=O.join(n,"resources","icons","icon.ico"),B}class F{static _instance;_isDark=o.nativeTheme.shouldUseDarkColors;constructor(){const e=T.get(g.THEME_MODE);e&&(o.nativeTheme.themeSource=e,this._isDark=o.nativeTheme.shouldUseDarkColors),this._setupIpcEvent(),u.info("ThemeService initialized successfully.")}_setupIpcEvent(){o.ipcMain.handle(a.SET_THEME_MODE,(e,t)=>(o.nativeTheme.themeSource=t,T.set(g.THEME_MODE,t),o.nativeTheme.shouldUseDarkColors)),o.ipcMain.handle(a.GET_THEME_MODE,()=>o.nativeTheme.themeSource),o.ipcMain.handle(a.IS_DARK_THEME,()=>o.nativeTheme.shouldUseDarkColors),o.nativeTheme.on("updated",()=>{this._isDark=o.nativeTheme.shouldUseDarkColors,o.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(a.THEME_MODE_UPDATED,this._isDark))})}static getInstance(){return this._instance||(this._instance=new F),this._instance}get isDark(){return this._isDark}get themeMode(){return o.nativeTheme.themeSource}}const X=F.getInstance(),ze={frame:!1,titleBarStyle:"hidden",trafficLightPosition:{x:-100,y:-100},show:!1,title:"NIANXX",darkTheme:X.isDark,backgroundColor:X.isDark?"#2C2C2C":"#FFFFFF",webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,backgroundThrottling:!1,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?O.join(process.cwd(),"dist-electron/preload/preload.js"):O.join(__dirname,"preload.js")}};class j{static _instance;_logo=ie();isDev=!!MAIN_WINDOW_VITE_DEV_SERVER_URL;_winStates={main:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},setting:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},dialog:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},login:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},loading:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]}};constructor(){this._setupIpcEvents(),u.info("WindowService initialized successfully.")}_isReallyClose(e){return e===w.MAIN?T.get(g.MINIMIZE_TO_TRAY)===!1:e!==w.SETTING}_setupIpcEvents(){const e=r=>{const c=o.BrowserWindow.fromWebContents(r.sender),d=this.getName(c);this.close(c,this._isReallyClose(d))},t=r=>{o.BrowserWindow.fromWebContents(r.sender)?.minimize()},i=r=>{this.toggleMax(o.BrowserWindow.fromWebContents(r.sender))},s=r=>o.BrowserWindow.fromWebContents(r.sender)?.isMaximized()??!1;o.ipcMain.on(a.WINDOW_CLOSE,e),o.ipcMain.on(a.WINDOW_MINIMIZE,t),o.ipcMain.on(a.WINDOW_MAXIMIZE,i),o.ipcMain.handle(a.IS_WINDOW_MAXIMIZED,s),o.ipcMain.handle(a.APP_LOAD_PAGE,(r,c)=>{const d=o.BrowserWindow.fromWebContents(r.sender);d&&this._loadPage(d,c)})}static getInstance(){return this._instance||(this._instance=new j),this._instance}create(e,t,i){if(this.get(e))return;const s=this._isHiddenWin(e);let r=this._createWinInstance(e,{...t,...i});return this.isDev&&r.webContents.openDevTools(),!s&&this._setupWinLifecycle(r,e)._loadWindowTemplate(r,e),this._listenWinReady({win:r,isHiddenWin:s,size:t}),s||(this._winStates[e].instance=r,this._winStates[e].onCreate.forEach(c=>c(r))),s&&(this._winStates[e].isHidden=!1,u.info(`Hidden window show: ${e}`)),r}_setupWinLifecycle(e,t){const i=ne(()=>!e?.isDestroyed()&&e?.webContents?.send(a.WINDOW_MAXIMIZE+"back",e?.isMaximized()),80);return e.once("closed",()=>{this._winStates[t].onClosed.forEach(s=>s(e)),e?.destroy(),e?.removeListener("resize",i),this._winStates[t].instance=void 0,this._winStates[t].isHidden=!1,u.info(`Window closed: ${t}`)}),e.on("resize",i),this}_listenWinReady(e){const t=()=>{e.win?.once("show",()=>setTimeout(()=>this._applySizeConstraints(e.win,e.size),2)),e.win?.show()};e.isHiddenWin?t():this._addLoadingView(e.win,e.size)?.(t)}_addLoadingView(e,t){let i=!1;const s=r=>{r.sender!==e?.webContents||i||(i=!0,o.ipcMain.removeListener(a.RENDERER_IS_READY,s))};return o.ipcMain.on(a.RENDERER_IS_READY,s),r=>{r()}}_applySizeConstraints(e,t){t.maxHeight&&t.maxWidth&&e.setMaximumSize(t.maxWidth,t.maxHeight),t.minHeight&&t.minWidth&&e.setMinimumSize(t.minWidth,t.minHeight)}_loadPage(e,t){if(MAIN_WINDOW_VITE_DEV_SERVER_URL)return e.loadURL(`${MAIN_WINDOW_VITE_DEV_SERVER_URL}/${t}.html`);e.loadFile(O.join(app.getAppPath(),"dist",`${t}.html`))}_loadWindowTemplate(e,t){this._loadPage(e,"index")}_handleCloseWindowState(e,t){const i=this.getName(e);i&&(t?this._winStates[i].instance=void 0:this._winStates[i].isHidden=!0),setTimeout(()=>{e[t?"close":"hide"]?.(),this._checkAndCloseAllWinodws()},210)}_checkAndCloseAllWinodws(){if(!this._winStates[w.MAIN].instance||this._winStates[w.MAIN].instance?.isDestroyed())return Object.values(this._winStates).forEach(t=>t?.instance?.close());if(!T.get(g.MINIMIZE_TO_TRAY)&&!this.get(w.MAIN)?.isVisible())return Object.values(this._winStates).forEach(t=>!t?.instance?.isVisible()&&t?.instance?.close())}_isHiddenWin(e){return this._winStates[e]&&this._winStates[e].isHidden}_createWinInstance(e,t){return this._isHiddenWin(e)?this._winStates[e].instance:new o.BrowserWindow({...ze,icon:this._logo,...t})}focus(e){if(!e)return;const t=this.getName(e);e?.isMaximized()?(e?.restore(),u.debug(`Window ${t} restored and focused`)):u.debug(`Window ${t} focused`),e?.focus()}close(e,t=!0){if(!e)return;const i=this.getName(e);u.info(`Close window: ${i}, really: ${t}`),this._handleCloseWindowState(e,t)}toggleMax(e){e&&(e.isMaximized()?e.unmaximize():e.maximize())}getName(e){if(e){for(const[t,i]of Object.entries(this._winStates))if(i?.instance===e)return t}}get(e){if(!this._winStates[e].isHidden)return this._winStates[e].instance}onWindowCreate(e,t){this._winStates[e].onCreate.push(t)}onWindowClosed(e,t){this._winStates[e].onClosed.push(t)}}const L=j.getInstance();let x=k();class Y{static _instance;_menuTemplates=new Map;_currentMenu=void 0;constructor(){this._setupIpcListener(),this._setupLanguageChangeListener(),u.info("MenuService initialized successfully.")}_setupIpcListener(){o.ipcMain.handle(a.SHOW_CONTEXT_MENU,(e,t,i)=>new Promise(s=>this.showMenu(t,()=>s(!0),i)))}_setupLanguageChangeListener(){T.onConfigChange(e=>{e[g.LANGUAGE]&&(x=k())})}static getInstance(){return this._instance||(this._instance=new Y),this._instance}register(e,t){return this._menuTemplates.set(e,t),e}showMenu(e,t,i){if(this._currentMenu)return;const s=H(this._menuTemplates.get(e));if(!s){u.warn(`Menu ${e} not found.`),t?.();return}let r=[];try{r=Array.isArray(i)?i:JSON.parse(i??"[]")}catch(l){u.error(`Failed to parse dynamicOptions for menu ${e}: ${l}`)}const c=l=>l.submenu?{...l,label:x(l?.label)??void 0,submenu:l.submenu?.map(p=>c(p))}:{...l,label:x(l?.label)??void 0},d=s.map(l=>{if(!Array.isArray(r)||!r.length)return c(l);const p=r.find(_=>_.id===l.id);if(p){const _={...l,...p};return c(_)}return l.submenu?c({...l,submenu:l.submenu?.map(_=>{const b=r.find(A=>A.id===_.id);return{..._,...b}})}):c(l)}),f=o.Menu.buildFromTemplate(d);this._currentMenu=f,f.popup({callback:()=>{this._currentMenu=void 0,t?.()}})}destroyMenu(e){this._menuTemplates.delete(e)}destroyed(){this._menuTemplates.clear(),this._currentMenu=void 0}}const P=Y.getInstance();let N=k();class q{static _instance;_tray=null;_removeLanguageListener;_setupLanguageChangeListener(){this._removeLanguageListener=T.onConfigChange(e=>{e[g.LANGUAGE]&&(N=k(),this._tray&&this._updateTray())})}_updateTray(){this._tray||(this._tray=new o.Tray(ie()));const e=()=>{const t=L.get(w.MAIN);if(t&&!t?.isDestroyed()&&t?.isVisible()&&!t?.isFocused())return t.focus();if(t?.isMinimized())return t?.restore();t?.isVisible()&&t?.isFocused()||L.create(w.MAIN,te)};this._tray.setToolTip(N("tray.tooltip")??"Diona Application"),this._tray.setContextMenu(o.Menu.buildFromTemplate([{label:N("tray.showWindow"),accelerator:"CmdOrCtrl+N",click:e},{type:"separator"},{label:N("settings.title"),click:()=>o.ipcMain.emit(`${a.OPEN_WINDOW}:${w.SETTING}`)},{role:"quit",label:N("tray.exit")}])),this._tray.removeAllListeners("click"),this._tray.on("click",e)}constructor(){this._setupLanguageChangeListener(),u.info("TrayService initialized successfully.")}static getInstance(){return this._instance||(this._instance=new q),this._instance}create(){this._tray||(this._updateTray(),o.app.on("quit",()=>{this.destroy()}))}destroy(){this._tray?.destroy(),this._tray=null,this._removeLanguageListener&&(this._removeLanguageListener(),this._removeLanguageListener=void 0)}}const Z=q.getInstance();class Fe{win;views=new Map;activeId=null;skipNextNavigate=new Map;enabled=!1;constructor(e){this.win=e,this.win.on("resize",()=>this.updateActiveBounds()),this._setupIpcEvents()}_setupIpcEvents(){o.ipcMain.handle(a.TAB_CREATE,(e,t)=>this.create(t)),o.ipcMain.handle(a.TAB_LIST,()=>this.list()),o.ipcMain.handle(a.TAB_NAVIGATE,(e,{tabId:t,url:i})=>{this.navigate(t,i)}),o.ipcMain.handle(a.TAB_RELOAD,(e,t)=>{this.reload(t)}),o.ipcMain.handle(a.TAB_BACK,(e,t)=>{this.goBack(t)}),o.ipcMain.handle(a.TAB_FORWARD,(e,t)=>{this.goForward(t)}),o.ipcMain.handle(a.TAB_SWITCH,(e,t)=>{this.switch(t)}),o.ipcMain.handle(a.TAB_CLOSE,(e,t)=>{this.close(t)})}enable(){this.enabled=!0,this.updateActiveBounds(),this.activeId&&this.attach(this.activeId)}disable(){this.enabled=!1;const e=this.activeId?this.views.get(this.activeId):null;e&&this.win.removeBrowserView(e)}destroy(){this.disable(),this.views.forEach(e=>{e.webContents.destroy()}),this.views.clear(),o.ipcMain.removeHandler(a.TAB_CREATE),o.ipcMain.removeHandler(a.TAB_LIST),o.ipcMain.removeHandler(a.TAB_NAVIGATE),o.ipcMain.removeHandler(a.TAB_RELOAD),o.ipcMain.removeHandler(a.TAB_BACK),o.ipcMain.removeHandler(a.TAB_FORWARD),o.ipcMain.removeHandler(a.TAB_SWITCH),o.ipcMain.removeHandler(a.TAB_CLOSE)}list(){return Array.from(this.views.entries()).map(([e,t])=>this.info(e,t))}create(e,t=!0){const i=re.randomUUID(),s=new o.BrowserView({webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?O.join(process.cwd(),"dist-electron/preload/preload.js"):O.join(__dirname,"preload.js")}});this.views.set(i,s),this.enabled&&t&&this.attach(i);const r=e&&e.length>0?e:"about:blank";s.webContents.loadURL(r),this.bindEvents(i,s);const c=this.info(i,s);return this.win.webContents.send("tab-created",c),c}switch(e){this.views.has(e)&&(this.enabled&&this.attach(e),this.win.webContents.send("tab-switched",{tabId:e}))}close(e){const t=this.views.get(e);if(!t)return;this.activeId===e&&(this.win.removeBrowserView(t),this.activeId=null),t.webContents.destroy(),this.views.delete(e),this.win.webContents.send("tab-closed",{tabId:e});const i=this.views.keys().next().value;i&&this.switch(i)}navigate(e,t){const i=this.views.get(e);i&&(this.skipNextNavigate.set(e,!0),i.webContents.loadURL(t))}reload(e){const t=this.views.get(e);t&&t.webContents.reload()}goBack(e){const t=this.views.get(e);t&&t.webContents.canGoBack()&&t.webContents.goBack()}goForward(e){const t=this.views.get(e);t&&t.webContents.canGoForward()&&t.webContents.goForward()}attach(e){if(!this.enabled)return;const t=this.views.get(e);if(t){if(this.activeId&&this.views.get(this.activeId)){const i=this.views.get(this.activeId);this.win.removeBrowserView(i)}this.activeId=e,this.win.addBrowserView(t),this.updateActiveBounds()}}updateActiveBounds(){if(!this.enabled||!this.activeId)return;const e=this.views.get(this.activeId);if(!e)return;const[t,i]=this.win.getContentSize(),s=88,r=8,c=488,d=r,f=s+r,l=t-c-r,p=i-s-r*2;e.setBounds({x:d,y:f,width:Math.max(0,l),height:Math.max(0,p)})}bindEvents(e,t){const i=()=>this.win.webContents.send("tab-updated",this.info(e,t));t.webContents.on("did-start-loading",i),t.webContents.on("did-stop-loading",i),t.webContents.on("did-finish-load",i),t.webContents.on("page-title-updated",i),t.webContents.on("did-navigate",i),t.webContents.on("did-navigate-in-page",i),t.webContents.on("will-navigate",(s,r)=>{if(this.skipNextNavigate.get(e)){this.skipNextNavigate.set(e,!1);return}s.preventDefault(),this.create(r)}),t.webContents.setWindowOpenHandler(({url:s})=>(this.create(s),{action:"deny"}))}info(e,t){const i=t.webContents;return{id:e,url:i.getURL(),title:i.getTitle(),isLoading:i.isLoading(),canGoBack:i.canGoBack(),canGoForward:i.canGoForward()}}}const K=n=>{if(n){Z.create();return}Z.destroy()},je=n=>{const e=s=>{u.logUserOperation(`${a.SHOW_CONTEXT_MENU}:${y.CONVERSATION_ITEM}-${s}`),n.webContents.send(`${a.SHOW_CONTEXT_MENU}:${y.CONVERSATION_ITEM}`,s)};P.register(y.CONVERSATION_ITEM,[{id:E.PIN,label:"menu.conversation.pinConversation",click:()=>e(E.PIN)},{id:E.RENAME,label:"menu.conversation.renameConversation",click:()=>e(E.RENAME)},{id:E.DEL,label:"menu.conversation.delConversation",click:()=>e(E.DEL)}]);const t=s=>{u.logUserOperation(`${a.SHOW_CONTEXT_MENU}:${y.CONVERSATION_LIST}-${s}`),n.webContents.send(`${a.SHOW_CONTEXT_MENU}:${y.CONVERSATION_LIST}`,s)};P.register(y.CONVERSATION_LIST,[{id:m.NEW_CONVERSATION,label:"menu.conversation.newConversation",click:()=>t(m.NEW_CONVERSATION)},{type:"separator"},{id:m.SORT_BY,label:"menu.conversation.sortBy",submenu:[{id:m.SORT_BY_CREATE_TIME,label:"menu.conversation.sortByCreateTime",type:"radio",checked:!1,click:()=>t(m.SORT_BY_CREATE_TIME)},{id:m.SORT_BY_UPDATE_TIME,label:"menu.conversation.sortByUpdateTime",type:"radio",checked:!1,click:()=>t(m.SORT_BY_UPDATE_TIME)},{id:m.SORT_BY_NAME,label:"menu.conversation.sortByName",type:"radio",checked:!1,click:()=>t(m.SORT_BY_NAME)},{id:m.SORT_BY_MODEL,label:"menu.conversation.sortByModel",type:"radio",checked:!1,click:()=>t(m.SORT_BY_MODEL)},{type:"separator"},{id:m.SORT_ASCENDING,label:"menu.conversation.sortAscending",type:"radio",checked:!1,click:()=>t(m.SORT_ASCENDING)},{id:m.SORT_DESCENDING,label:"menu.conversation.sortDescending",type:"radio",checked:!1,click:()=>t(m.SORT_DESCENDING)}]},{id:m.BATCH_OPERATIONS,label:"menu.conversation.batchOperations",click:()=>t(m.BATCH_OPERATIONS)}]);const i=s=>{u.logUserOperation(`${a.SHOW_CONTEXT_MENU}:${y.MESSAGE_ITEM}-${s}`),n.webContents.send(`${a.SHOW_CONTEXT_MENU}:${y.MESSAGE_ITEM}`,s)};P.register(y.MESSAGE_ITEM,[{id:I.COPY,label:"menu.message.copyMessage",click:()=>i(I.COPY)},{id:I.SELECT,label:"menu.message.selectMessage",click:()=>i(I.SELECT)},{type:"separator"},{id:I.DELETE,label:"menu.message.deleteMessage",click:()=>i(I.DELETE)}])};function se(){L.onWindowCreate(w.MAIN,n=>{let e=T.get(g.MINIMIZE_TO_TRAY);T.onConfigChange(i=>{e!==i[g.MINIMIZE_TO_TRAY]&&(e=i[g.MINIMIZE_TO_TRAY],K(e))}),K(e),je(n);const t=new Fe(n);t.enable(),n.on("closed",()=>{t.destroy()})}),L.create(w.MAIN,te),o.ipcMain.on(a.START_A_DIALOGUE,async(n,e)=>{const{providerName:t,messages:i,messageId:s,selectedModel:r}=e,c=L.get(w.MAIN);if(!c)throw new Error("mainWindow not found");try{const f=await Me(t)?.chat(i,r);if(!f)throw new Error("chunks or stream not found");for await(const l of f){const p={messageId:s,data:l};c.webContents.send(a.START_A_DIALOGUE+"back"+s,p)}}catch(d){const f={messageId:s,data:{isEnd:!0,isError:!0,result:d instanceof Error?d.message:String(d)}};c.webContents.send(a.START_A_DIALOGUE+"back"+s,f)}})}function Ye(){if(process.platform==="win32")return"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";if(process.platform==="darwin")return"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";if(process.platform==="linux")return"google-chrome"}function qe(n){return O.join(o.app.getPath("userData"),"profiles",n)}function Xe(n){return new Promise(e=>{const t=ce.createServer();t.once("error",i=>e(!0)),t.once("listening",()=>{t.close(),e(!1)}),t.listen(n)})}async function Ze(){try{return new Promise(n=>{const e=le.get("http://127.0.0.1:9222/json/version",t=>{n(t.statusCode===200)});e.on("error",()=>n(!1)),e.setTimeout(1e3,()=>{e.destroy(),n(!1)})})}catch{return!1}}async function Ke(){const n=Ye(),e=qe("default");if(h.info(`Launching Chrome with user data dir: ${e}`),await Xe(9222)){h.info("Chrome already running on port 9222, skip launching.");return}if(await Ze()){h.info("Chrome already running, skip launching.");return}return new Promise((i,s)=>{de.spawn(n,["--remote-debugging-port=9222","--window-size=1920,1080","--window-position=0,0","--no-first-run",`--user-data-dir=${e}`,"--no-default-browser-check","about:blank"],{detached:!0,stdio:"ignore"}).on("error",s),setTimeout(()=>{i(0)},1e3)})}class Je extends ue.EventEmitter{async executeScript(e,t){const s=(r,c)=>{const d=r+c;return d.length>32768?d.slice(d.length-32768):d};return await new Promise(r=>{try{const c=t?.roomType??"",d=t?.startTime??"",f=t?.endTime??"",l=t?.operation??"",p=t?.tabIndex??"",_=t?.channels??"",b=t?.startTabIndex??"",A=o.utilityProcess.fork(e,[],{env:{...process.env,ROOM_TYPE:String(c),START_DATE:String(d),END_DATE:String(f),OPERATION:String(l),TAB_INDEX:String(p),CHANNELS:typeof _=="string"?_:JSON.stringify(_),START_TAB_INDEX:String(b)},stdio:"pipe"});let C="",D="";A.stdout&&A.stdout.on("data",M=>{const R=M.toString();C=s(C,R),h.info(`stdout: ${R}`)}),A.stderr&&A.stderr.on("data",M=>{const R=M.toString();D=s(D,R),h.info(`stderr: ${R}`)}),A.on("exit",M=>{h.info(`子进程退出,退出码 ${M}`),r({success:M===0,exitCode:M,stdoutTail:C,stderrTail:D,...M===0?{}:{error:`Script exited with code ${M}`}})})}catch(c){r({success:!1,exitCode:null,stdoutTail:"",stderrTail:"",error:c?.message||"运行 Node 脚本时出错"})}})}}const $=new Map;function J(){return o.app.isPackaged?W.join(__dirname,"scripts"):W.join(process.cwd(),"electron/scripts")}function Qe(){const n=new Je;o.ipcMain.handle(a.OPEN_CHANNEL,async(e,t)=>{try{await Ke();const i=J(),s=W.join(i,"open_all_channel.js");if($.clear(),Array.isArray(t))for(let c=0;c{try{const i=t.roomList.find(l=>l.id===t.roomType),r=[["fzName","fg_trace.js"],["mtName","mt_trace.js"],["dyHotelName","dy_hotel_trace.js"],["dyHotSpringName","dy_hot_spring_trace.js"]].filter(([l])=>i?.[l]),c=J(),d=r.map(([l,p])=>{const _=W.join(c,p);if(!Q.existsSync(_))throw new Error(`Script not found for channel ${l}: ${_}`);return{channel:l,scriptPath:_}}),f=[];for(let l=0;l{se(),Qe()});o.app.on("window-all-closed",()=>{process.platform!=="darwin"&&!T.get(g.MINIMIZE_TO_TRAY)&&(h.info("app closing due to all windows being closed"),o.app.quit())});o.app.on("activate",()=>{o.BrowserWindow.getAllWindows().length===0&&se()}); +"use strict";const s=require("electron"),ae=require("openai"),$=require("util"),h=require("electron-log"),U=require("path"),ee=require("fs"),te=require("js-base64"),C=require("node:path"),ce=require("crypto"),le=require("electron-squirrel-startup"),de=require("net"),ue=require("http"),he=require("child_process"),pe=require("events");require("bytenode");const y=require("electron-updater");function ne(n){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const t in n)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>n[t]})}}return e.default=n,Object.freeze(e)}const S=ne(U),v=ne(ee);var r=(n=>(n.EXTERNAL_OPEN="external-open",n.WINDOW_MINIMIZE="window-minimize",n.WINDOW_MAXIMIZE="window-maximize",n.WINDOW_CLOSE="window-close",n.IS_WINDOW_MAXIMIZED="is-window-maximized",n.APP_SET_FRAMELESS="app:set-frameless",n.APP_LOAD_PAGE="app:load-page",n.TAB_CREATE="tab:create",n.TAB_LIST="tab:list",n.TAB_NAVIGATE="tab:navigate",n.TAB_RELOAD="tab:reload",n.TAB_BACK="tab:back",n.TAB_FORWARD="tab:forward",n.TAB_SWITCH="tab:switch",n.TAB_CLOSE="tab:close",n.LOG_TO_MAIN="log-to-main",n.READ_FILE="read-file",n.INVOKE="ipc:invoke",n.INVOKE_ASYNC="ipc:invokeAsync",n.APP_MINIMIZE="app:minimize",n.APP_MAXIMIZE="app:maximize",n.APP_QUIT="app:quit",n.FILE_READ="file:read",n.FILE_WRITE="file:write",n.GET_WINDOW_ID="get-window-id",n.CUSTOM_EVENT="custom:event",n.TIME_UPDATE="time:update",n.RENDERER_IS_READY="renderer-ready",n.SHOW_CONTEXT_MENU="show-context-menu",n.START_A_DIALOGUE="start-a-dialogue",n.OPEN_WINDOW="open-window",n.LOG_DEBUG="log-debug",n.LOG_INFO="log-info",n.LOG_WARN="log-warn",n.LOG_ERROR="log-error",n.CONFIG_UPDATED="config-updated",n.SET_CONFIG="set-config",n.GET_CONFIG="get-config",n.UPDATE_CONFIG="update-config",n.SET_THEME_MODE="set-theme-mode",n.GET_THEME_MODE="get-theme-mode",n.IS_DARK_THEME="is-dark-theme",n.THEME_MODE_UPDATED="theme-mode-updated",n.EXECUTE_SCRIPT="execute-script",n.OPEN_CHANNEL="open-channel",n.UPDATE_CHECK="update:check",n.UPDATE_DOWNLOAD="update:download",n.UPDATE_INSTALL="update:install",n.UPDATE_VERSION="update:version",n.UPDATE_STATUS_CHANGED="update:status-changed",n))(r||{});const ie={width:1440,height:900,minWidth:1440,minHeight:900};var w=(n=>(n.MAIN="main",n.SETTING="setting",n.DIALOG="dialog",n.LOADING="loading",n))(w||{}),g=(n=>(n.THEME_MODE="themeMode",n.PRIMARY_COLOR="primaryColor",n.LANGUAGE="language",n.FONT_SIZE="fontSize",n.MINIMIZE_TO_TRAY="minimizeToTray",n.PROVIDER="provider",n.DEFAULT_MODEL="defaultModel",n.AUTO_CHECK_UPDATE="autoCheckUpdate",n.AUTO_DOWNLOAD_UPDATE="autoDownloadUpdate",n))(g||{}),E=(n=>(n.CONVERSATION_ITEM="conversation-item",n.CONVERSATION_LIST="conversation-list",n.MESSAGE_ITEM="message-item",n))(E||{}),D=(n=>(n.PIN="pin",n.RENAME="rename",n.DEL="del",n))(D||{}),_=(n=>(n.NEW_CONVERSATION="newConversation",n.SORT_BY="sortBy",n.SORT_BY_CREATE_TIME="sortByCreateTime",n.SORT_BY_UPDATE_TIME="sortByUpdateTime",n.SORT_BY_NAME="sortByName",n.SORT_BY_MODEL="sortByModel",n.SORT_ASCENDING="sortAscending",n.SORT_DESCENDING="sortDescending",n.BATCH_OPERATIONS="batchOperations",n))(_||{}),O=(n=>(n.COPY="copy",n.DELETE="delete",n.SELECT="select",n))(O||{});class ge{}const fe=$.promisify(v.readdir),_e=$.promisify(v.stat),me=$.promisify(v.unlink);class z{static _instance;LOG_RETENTION_DAYS=7;CLEANUP_INTERVAL_MS=1440*60*1e3;constructor(){const e=S.join(s.app.getPath("userData"),"logs");try{v.existsSync(e)||v.mkdirSync(e,{recursive:!0})}catch(t){this.error("Failed to create log directory:",t)}h.transports.file.resolvePathFn=()=>{const t=new Date,i=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`;return S.join(e,`${i}.log`)},h.transports.file.format="[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}",h.transports.file.maxSize=10*1024*1024,h.transports.console.level=process.env.NODE_ENV==="development"?"debug":"info",h.transports.file.level="debug",this._setupIpcEvents(),this._rewriteConsole(),this.info("LogService initialized successfully."),this._cleanupOldLogs(),setInterval(()=>this._cleanupOldLogs(),this.CLEANUP_INTERVAL_MS)}_setupIpcEvents(){s.ipcMain.on(r.LOG_DEBUG,(e,t,...i)=>this.debug(t,...i)),s.ipcMain.on(r.LOG_INFO,(e,t,...i)=>this.info(t,...i)),s.ipcMain.on(r.LOG_WARN,(e,t,...i)=>this.warn(t,...i)),s.ipcMain.on(r.LOG_ERROR,(e,t,...i)=>this.error(t,...i))}_rewriteConsole(){console.debug=h.debug,console.log=h.info,console.info=h.info,console.warn=h.warn,console.error=h.error}async _cleanupOldLogs(){try{const e=S.join(s.app.getPath("userData"),"logs");if(!v.existsSync(e))return;const t=new Date,i=new Date(t.getTime()-this.LOG_RETENTION_DAYS*24*60*60*1e3),o=await fe(e);let a=0;for(const c of o){if(!c.endsWith(".log"))continue;const d=S.join(e,c);try{const f=await _e(d);f.isFile()&&f.birthtime0&&this.info(`Successfully cleaned up ${a} old log files.`)}catch(e){this.error("Failed to cleanup old logs:",e)}}static getInstance(){return this._instance||(this._instance=new z),this._instance}debug(e,...t){h.debug(e,...t)}info(e,...t){h.info(e,...t)}warn(e,...t){h.warn(e,...t)}error(e,...t){h.error(e,...t)}logApiRequest(e,t={},i="POST"){this.info(`API Request: ${e}, Method: ${i}, Request: ${JSON.stringify(t)}`)}logApiResponse(e,t={},i=200,o=0){i>=400?this.error(`API Error Response: ${e}, Status: ${i}, Response Time: ${o}ms, Response: ${JSON.stringify(t)}`):this.debug(`API Response: ${e}, Status: ${i}, Response Time: ${o}ms, Response: ${JSON.stringify(t)}`)}logUserOperation(e,t="unknown",i={}){this.info(`User Operation: ${e} by ${t}, Details: ${JSON.stringify(i)}`)}}const u=z.getInstance();function we(n){const e=n.choices[0];return{isEnd:e?.finish_reason==="stop",result:e?.delta?.content??""}}class Ae extends ge{client;constructor(e,t){super(),this.client=new ae({apiKey:e,baseURL:t})}async chat(e,t){const i=Date.now(),o=e[e.length-1];u.logApiRequest("chat.completions.create",{model:t,lastMessage:o?.content?.substring(0,100)+(o?.content?.length>100?"...":""),messageCount:e.length},"POST");try{const a=await this.client.chat.completions.create({model:t,messages:e,stream:!0}),c=Date.now()-i;return u.logApiResponse("chat.completions.create",{success:!0},200,c),{async*[Symbol.asyncIterator](){for await(const d of a)yield we(d)}}}catch(a){const c=Date.now()-i;throw u.logApiResponse("chat.completions.create",{error:a instanceof Error?a.message:String(a)},500,c),a}}}function se(n,e){let t=null;return function(...i){t&&clearTimeout(t),t=setTimeout(()=>{n.apply(this,i)},e)}}function G(n){if(n===null||typeof n!="object")return n;if(Array.isArray(n))return n.map(t=>G(t));const e=Object.assign({},n);for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(e[t]=G(e[t]));return e}function Te(n){try{return JSON.parse(JSON.stringify(n))}catch(e){return console.error("simpleCloneDeep failed:",e),n}}function ye(n){try{return JSON.parse(te.decode(n))}catch(e){return console.error("parseOpenAISetting failed:",e),{}}}const Ee={[g.THEME_MODE]:"system",[g.PRIMARY_COLOR]:"#BB5BE7",[g.LANGUAGE]:"zh",[g.FONT_SIZE]:14,[g.MINIMIZE_TO_TRAY]:!1,[g.PROVIDER]:"",[g.DEFAULT_MODEL]:null};class F{static _instance;_config;_configPath;_defaultConfig=Ee;_listeners=[];constructor(){this._configPath=S.join(s.app.getPath("userData"),"config.json"),this._config=this._loadConfig(),this._setupIpcEvents(),u.info("ConfigService initialized successfully.")}_setupIpcEvents(){const t=se(i=>this.update(i),200);s.ipcMain.handle(r.GET_CONFIG,(i,o)=>this.get(o)),s.ipcMain.on(r.SET_CONFIG,(i,o,a)=>this.set(o,a)),s.ipcMain.on(r.UPDATE_CONFIG,(i,o)=>t(o))}static getInstance(){return this._instance||(this._instance=new F),this._instance}_loadConfig(){try{if(v.existsSync(this._configPath)){const e=v.readFileSync(this._configPath,"utf-8"),t={...this._defaultConfig,...JSON.parse(e)};return u.info("Config loaded successfully from:",this._configPath),t}}catch(e){u.error("Failed to load config:",e)}return{...this._defaultConfig}}_saveConfig(){try{v.mkdirSync(S.dirname(this._configPath),{recursive:!0}),v.writeFileSync(this._configPath,JSON.stringify(this._config,null,2),"utf-8"),this._notifyListeners(),u.info("Config saved successfully to:",this._configPath)}catch(e){u.error("Failed to save config:",e)}}_notifyListeners(){s.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(r.CONFIG_UPDATED,this._config)),this._listeners.forEach(e=>e({...this._config}))}getConfig(){return Te(this._config)}get(e){return this._config[e]}set(e,t,i=!0){!(e in this._config)||this._config[e]===t||(this._config[e]=t,u.debug(`Config set: ${e} = ${t}`),i&&this._saveConfig())}update(e,t=!0){this._config={...this._config,...e},t&&this._saveConfig()}resetToDefault(){this._config={...this._defaultConfig},u.info("Config reset to default."),this._saveConfig()}onConfigChange(e){return this._listeners.push(e),()=>this._listeners=this._listeners.filter(t=>t!==e)}}const T=F.getInstance();process.env.BIGMODEL_API_KEY,new Date().getTime(),new Date().getTime(),process.env.DEEPSEEK_API_KEY,new Date().getTime(),new Date().getTime(),process.env.SILICONFLOW_API_KEY,new Date().getTime(),new Date().getTime(),process.env.QIANFAN_API_KEY,new Date().getTime(),new Date().getTime();const ve=()=>{let n=[],e=!1;const t=T.get(g.PROVIDER),i=o=>({...o,openAISetting:typeof o.openAISetting=="string"?ye(o.openAISetting??""):o.openAISetting});try{n=JSON.parse(te.decode(t)),e=!0}catch(o){u.error(`parse base64 provider failed: ${o}`)}if(!e)try{n=JSON.parse(t)}catch(o){u.error(`parse provider failed: ${o}`)}if(n.length)return n.map(i)},Me=()=>{try{return ve()}catch(n){return u.error(`get provider config failed: ${n}`),null}};function De(n){const e=Me();if(!e)throw new Error("provider config not found");for(const t of e)if(t.name===n){if(!t.openAISetting?.apiKey||!t.openAISetting?.baseURL)throw new Error("apiKey or baseURL not found");return new Ae(t.openAISetting.apiKey,t.openAISetting.baseURL)}}const Oe={minimize:"Minimize",maximize:"Maximize",restore:"Restore",close:"Close"},Ce={welcome:{helloMessage:"Hello, I'm Diona"},conversation:{placeholder:"Type a message...",newConversation:"New Conversation",selectModel:"Please select model",createConversation:"Create Conversation",searchPlaceholder:"Search conversations...",goSettings:"Go to",settings:"Settings Window",addModel:"to add a model",dialog:{title:"Confirm Deletion",content:"Are you sure you want to delete this conversation?",content_1:"Are you sure you want to delete the selected conversations? This action cannot be undone."},operations:{pin:"Pin Selected",del:"Delete Selected",selectAll:"Select All",cancel:"Cancel"}},sidebar:{conversations:"Conversations",settings:"Settings",help:"Help"},message:{dialog:{title:"Confirm Deletion",messageDelete:"Are you sure you want to delete this message?",batchDelete:"Are you sure you want to delete the selected messages?",copySuccess:"Copied successfully"},batchActions:{deleteSelected:"Delete Selected"},rendering:"Thinking...",stoppedGeneration:"(Stopped generating)",sending:"Sending",stopGeneration:"Stop generating",send:"Send"}},Ie={cancel:"Cancel",confirm:"Confirm"},Se={title:"Settings",base:"Basic Settings",provider:{modelConfig:"Model Configuration"},theme:{label:"Theme Settings",dark:"Dark Theme",light:"Light Theme",system:"System Theme",primaryColor:"Primary Color"},appearance:{fontSize:"Font Size",fontSizeOptions:{10:"Tiny (10px)",12:"Small (12px)",14:"Normal (14px)",16:"Medium (16px)",18:"Large (18px)",20:"Larger (20px)",24:"Extra Large (24px)"}},behavior:{minimizeToTray:"Minimize to tray when closed"},language:{label:"Language"},providers:{defaultModel:"Default Model",apiKey:"API Key",apiUrl:"API URL"}},be={conversation:{newConversation:"New Conversation",sortBy:"Sort By",sortByCreateTime:"Sort by Creation Time",sortByUpdateTime:"Sort by Update Time",sortByName:"Sort by Name",sortByModel:"Sort by Model",sortAscending:"Ascending",sortDescending:"Descending",pinConversation:"Pin Conversation",unpinConversation:"Unpin Conversation",renameConversation:"Rename Conversation",delConversation:"Delete Conversation",batchOperations:"Batch Operations"},message:{copyMessage:"Copy Message",deleteMessage:"Delete Message",selectMessage:"Select Message"}},Re={tooltip:"Diona Application",showWindow:"Show Window",exit:"Exit"},Ne={justNow:"Just now",minutes:"{count} minutes ago",hours:"{count} hours ago",days:"{count} days ago",months:"{count} months ago",years:"{count} years ago",weekday:{sun:"Sunday",mon:"Monday",tue:"Tuesday",wed:"Wednesday",thu:"Thursday",fri:"Friday",sat:"Saturday"}},Le={title:"Diona Application"},We={window:Oe,main:Ce,dialog:Ie,settings:Se,menu:be,tray:Re,timeAgo:Ne,app:Le},Ue={minimize:"最小化",maximize:"最大化",restore:"还原",close:"关闭"},ke={welcome:{helloMessage:"你好,我是迪奥娜"},conversation:{placeholder:"输入消息...",newConversation:"新对话",selectModel:"请选择模型",createConversation:"创建对话",searchPlaceholder:"搜索对话...",goSettings:"快去",settings:"设置窗口",addModel:"添加模型",dialog:{title:"确认删除",content:"确定要删除这个对话吗?",content_1:"确定要删除选中的对话吗?此操作不可撤销。"},operations:{pin:"置顶所选",del:"删除所选",selectAll:"全选",cancel:"取消"}},sidebar:{conversations:"对话",settings:"设置",help:"帮助"},message:{dialog:{title:"确认删除",messageDelete:"确认删除该条消息?",batchDelete:"确认删除选中的消息?",copySuccess:"复制成功"},batchActions:{deleteSelected:"删除选中项"},rendering:"思考中...",stoppedGeneration:"(已停止生成)",sending:"发送中",stopGeneration:"停止生成",send:"发送"}},Be={cancel:"取消",confirm:"确认"},Pe={title:"设置",base:"基础设置",provider:{modelConfig:"模型配置"},providers:{defaultModel:"默认模型",apiKey:"API密钥",apiUrl:"API地址"},theme:{label:"主题设置",dark:"深色主题",light:"浅色主题",system:"跟随系统",primaryColor:"主题颜色"},appearance:{fontSize:"字体大小",fontSizeOptions:{10:"极小 (10px)",12:"小 (12px)",14:"正常 (14px)",16:"中 (16px)",18:"大 (18px)",20:"较大 (20px)",24:"超大 (24px)"}},behavior:{minimizeToTray:"关闭时最小化到托盘"},language:{label:"语言设置"}},xe={conversation:{newConversation:"新建对话",sortBy:"排序方式",sortByCreateTime:"按创建时间排序",sortByUpdateTime:"按更新时间排序",sortByName:"按名称排序",sortByModel:"按模型排序",sortAscending:"递增",sortDescending:"递减",pinConversation:"置顶对话",unpinConversation:"取消置顶",renameConversation:"重命名对话",delConversation:"删除对话",batchOperations:"批量操作"},message:{copyMessage:"复制消息",deleteMessage:"删除消息",selectMessage:"选择消息"}},He={tooltip:"迪奥娜",showWindow:"显示窗口",exit:"退出"},Ge={justNow:"刚刚",minutes:"{count}分钟前",hours:"{count}小时前",days:"{count}天前",months:"{count}个月前",years:"{count}年前",weekday:{sun:"星期日",mon:"星期一",tue:"星期二",wed:"星期三",thu:"星期四",fri:"星期五",sat:"星期六"}},$e={title:"迪奥娜"},ze={window:Ue,main:ke,dialog:Be,settings:Pe,menu:xe,tray:He,timeAgo:Ge,app:$e},Fe={en:We,zh:ze};function B(){return n=>{if(n)try{const e=n?.split(".");let t=Fe[T.get(g.LANGUAGE)];for(const i of e)t=t[i];return t}catch(e){return u.error("failed to translate key:",n,e),n}}}let k;function oe(){if(k!=null)return k;const n=s.app.getAppPath();return k=C.join(n,"resources","icons","icon.ico"),k}class j{static _instance;_isDark=s.nativeTheme.shouldUseDarkColors;constructor(){const e=T.get(g.THEME_MODE);e&&(s.nativeTheme.themeSource=e,this._isDark=s.nativeTheme.shouldUseDarkColors),this._setupIpcEvent(),u.info("ThemeService initialized successfully.")}_setupIpcEvent(){s.ipcMain.handle(r.SET_THEME_MODE,(e,t)=>(s.nativeTheme.themeSource=t,T.set(g.THEME_MODE,t),s.nativeTheme.shouldUseDarkColors)),s.ipcMain.handle(r.GET_THEME_MODE,()=>s.nativeTheme.themeSource),s.ipcMain.handle(r.IS_DARK_THEME,()=>s.nativeTheme.shouldUseDarkColors),s.nativeTheme.on("updated",()=>{this._isDark=s.nativeTheme.shouldUseDarkColors,s.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(r.THEME_MODE_UPDATED,this._isDark))})}static getInstance(){return this._instance||(this._instance=new j),this._instance}get isDark(){return this._isDark}get themeMode(){return s.nativeTheme.themeSource}}const K=j.getInstance(),je={frame:!1,titleBarStyle:"hidden",trafficLightPosition:{x:-100,y:-100},show:!1,title:"NIANXX",darkTheme:K.isDark,backgroundColor:K.isDark?"#2C2C2C":"#FFFFFF",webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,backgroundThrottling:!1,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?C.join(process.cwd(),"dist-electron/preload/preload.js"):C.join(__dirname,"preload.js")}};class Y{static _instance;_logo=oe();isDev=!!MAIN_WINDOW_VITE_DEV_SERVER_URL;_winStates={main:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},setting:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},dialog:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},login:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]},loading:{instance:void 0,isHidden:!1,onCreate:[],onClosed:[]}};constructor(){this._setupIpcEvents(),u.info("WindowService initialized successfully.")}_isReallyClose(e){return e===w.MAIN?T.get(g.MINIMIZE_TO_TRAY)===!1:e!==w.SETTING}_setupIpcEvents(){const e=a=>{const c=s.BrowserWindow.fromWebContents(a.sender),d=this.getName(c);this.close(c,this._isReallyClose(d))},t=a=>{s.BrowserWindow.fromWebContents(a.sender)?.minimize()},i=a=>{this.toggleMax(s.BrowserWindow.fromWebContents(a.sender))},o=a=>s.BrowserWindow.fromWebContents(a.sender)?.isMaximized()??!1;s.ipcMain.on(r.WINDOW_CLOSE,e),s.ipcMain.on(r.WINDOW_MINIMIZE,t),s.ipcMain.on(r.WINDOW_MAXIMIZE,i),s.ipcMain.handle(r.IS_WINDOW_MAXIMIZED,o),s.ipcMain.handle(r.APP_LOAD_PAGE,(a,c)=>{const d=s.BrowserWindow.fromWebContents(a.sender);d&&this._loadPage(d,c)})}static getInstance(){return this._instance||(this._instance=new Y),this._instance}create(e,t,i){if(this.get(e))return;const o=this._isHiddenWin(e);let a=this._createWinInstance(e,{...t,...i});return this.isDev&&a.webContents.openDevTools(),!o&&this._setupWinLifecycle(a,e)._loadWindowTemplate(a,e),this._listenWinReady({win:a,isHiddenWin:o,size:t}),o||(this._winStates[e].instance=a,this._winStates[e].onCreate.forEach(c=>c(a))),o&&(this._winStates[e].isHidden=!1,u.info(`Hidden window show: ${e}`)),a}_setupWinLifecycle(e,t){const i=se(()=>!e?.isDestroyed()&&e?.webContents?.send(r.WINDOW_MAXIMIZE+"back",e?.isMaximized()),80);return e.once("closed",()=>{this._winStates[t].onClosed.forEach(o=>o(e)),e?.destroy(),e?.removeListener("resize",i),this._winStates[t].instance=void 0,this._winStates[t].isHidden=!1,u.info(`Window closed: ${t}`)}),e.on("resize",i),this}_listenWinReady(e){const t=()=>{e.win?.once("show",()=>setTimeout(()=>this._applySizeConstraints(e.win,e.size),2)),e.win?.show()};e.isHiddenWin?t():this._addLoadingView(e.win,e.size)?.(t)}_addLoadingView(e,t){let i=!1;const o=a=>{a.sender!==e?.webContents||i||(i=!0,s.ipcMain.removeListener(r.RENDERER_IS_READY,o))};return s.ipcMain.on(r.RENDERER_IS_READY,o),a=>{a()}}_applySizeConstraints(e,t){t.maxHeight&&t.maxWidth&&e.setMaximumSize(t.maxWidth,t.maxHeight),t.minHeight&&t.minWidth&&e.setMinimumSize(t.minWidth,t.minHeight)}_loadPage(e,t){if(MAIN_WINDOW_VITE_DEV_SERVER_URL)return e.loadURL(`${MAIN_WINDOW_VITE_DEV_SERVER_URL}/${t}.html`);e.loadFile(C.join(app.getAppPath(),"dist",`${t}.html`))}_loadWindowTemplate(e,t){this._loadPage(e,"index")}_handleCloseWindowState(e,t){const i=this.getName(e);i&&(t?this._winStates[i].instance=void 0:this._winStates[i].isHidden=!0),setTimeout(()=>{e[t?"close":"hide"]?.(),this._checkAndCloseAllWinodws()},210)}_checkAndCloseAllWinodws(){if(!this._winStates[w.MAIN].instance||this._winStates[w.MAIN].instance?.isDestroyed())return Object.values(this._winStates).forEach(t=>t?.instance?.close());if(!T.get(g.MINIMIZE_TO_TRAY)&&!this.get(w.MAIN)?.isVisible())return Object.values(this._winStates).forEach(t=>!t?.instance?.isVisible()&&t?.instance?.close())}_isHiddenWin(e){return this._winStates[e]&&this._winStates[e].isHidden}_createWinInstance(e,t){return this._isHiddenWin(e)?this._winStates[e].instance:new s.BrowserWindow({...je,icon:this._logo,...t})}focus(e){if(!e)return;const t=this.getName(e);e?.isMaximized()?(e?.restore(),u.debug(`Window ${t} restored and focused`)):u.debug(`Window ${t} focused`),e?.focus()}close(e,t=!0){if(!e)return;const i=this.getName(e);u.info(`Close window: ${i}, really: ${t}`),this._handleCloseWindowState(e,t)}toggleMax(e){e&&(e.isMaximized()?e.unmaximize():e.maximize())}getName(e){if(e){for(const[t,i]of Object.entries(this._winStates))if(i?.instance===e)return t}}get(e){if(!this._winStates[e].isHidden)return this._winStates[e].instance}onWindowCreate(e,t){this._winStates[e].onCreate.push(t)}onWindowClosed(e,t){this._winStates[e].onClosed.push(t)}}const W=Y.getInstance();let P=B();class q{static _instance;_menuTemplates=new Map;_currentMenu=void 0;constructor(){this._setupIpcListener(),this._setupLanguageChangeListener(),u.info("MenuService initialized successfully.")}_setupIpcListener(){s.ipcMain.handle(r.SHOW_CONTEXT_MENU,(e,t,i)=>new Promise(o=>this.showMenu(t,()=>o(!0),i)))}_setupLanguageChangeListener(){T.onConfigChange(e=>{e[g.LANGUAGE]&&(P=B())})}static getInstance(){return this._instance||(this._instance=new q),this._instance}register(e,t){return this._menuTemplates.set(e,t),e}showMenu(e,t,i){if(this._currentMenu)return;const o=G(this._menuTemplates.get(e));if(!o){u.warn(`Menu ${e} not found.`),t?.();return}let a=[];try{a=Array.isArray(i)?i:JSON.parse(i??"[]")}catch(l){u.error(`Failed to parse dynamicOptions for menu ${e}: ${l}`)}const c=l=>l.submenu?{...l,label:P(l?.label)??void 0,submenu:l.submenu?.map(p=>c(p))}:{...l,label:P(l?.label)??void 0},d=o.map(l=>{if(!Array.isArray(a)||!a.length)return c(l);const p=a.find(m=>m.id===l.id);if(p){const m={...l,...p};return c(m)}return l.submenu?c({...l,submenu:l.submenu?.map(m=>{const b=a.find(A=>A.id===m.id);return{...m,...b}})}):c(l)}),f=s.Menu.buildFromTemplate(d);this._currentMenu=f,f.popup({callback:()=>{this._currentMenu=void 0,t?.()}})}destroyMenu(e){this._menuTemplates.delete(e)}destroyed(){this._menuTemplates.clear(),this._currentMenu=void 0}}const x=q.getInstance();let L=B();class X{static _instance;_tray=null;_removeLanguageListener;_setupLanguageChangeListener(){this._removeLanguageListener=T.onConfigChange(e=>{e[g.LANGUAGE]&&(L=B(),this._tray&&this._updateTray())})}_updateTray(){this._tray||(this._tray=new s.Tray(oe()));const e=()=>{const t=W.get(w.MAIN);if(t&&!t?.isDestroyed()&&t?.isVisible()&&!t?.isFocused())return t.focus();if(t?.isMinimized())return t?.restore();t?.isVisible()&&t?.isFocused()||W.create(w.MAIN,ie)};this._tray.setToolTip(L("tray.tooltip")??"Diona Application"),this._tray.setContextMenu(s.Menu.buildFromTemplate([{label:L("tray.showWindow"),accelerator:"CmdOrCtrl+N",click:e},{type:"separator"},{label:L("settings.title"),click:()=>s.ipcMain.emit(`${r.OPEN_WINDOW}:${w.SETTING}`)},{role:"quit",label:L("tray.exit")}])),this._tray.removeAllListeners("click"),this._tray.on("click",e)}constructor(){this._setupLanguageChangeListener(),u.info("TrayService initialized successfully.")}static getInstance(){return this._instance||(this._instance=new X),this._instance}create(){this._tray||(this._updateTray(),s.app.on("quit",()=>{this.destroy()}))}destroy(){this._tray?.destroy(),this._tray=null,this._removeLanguageListener&&(this._removeLanguageListener(),this._removeLanguageListener=void 0)}}const J=X.getInstance();class Ye{win;views=new Map;activeId=null;skipNextNavigate=new Map;enabled=!1;constructor(e){this.win=e,this.win.on("resize",()=>this.updateActiveBounds()),this._setupIpcEvents()}_setupIpcEvents(){s.ipcMain.handle(r.TAB_CREATE,(e,t)=>this.create(t)),s.ipcMain.handle(r.TAB_LIST,()=>this.list()),s.ipcMain.handle(r.TAB_NAVIGATE,(e,{tabId:t,url:i})=>{this.navigate(t,i)}),s.ipcMain.handle(r.TAB_RELOAD,(e,t)=>{this.reload(t)}),s.ipcMain.handle(r.TAB_BACK,(e,t)=>{this.goBack(t)}),s.ipcMain.handle(r.TAB_FORWARD,(e,t)=>{this.goForward(t)}),s.ipcMain.handle(r.TAB_SWITCH,(e,t)=>{this.switch(t)}),s.ipcMain.handle(r.TAB_CLOSE,(e,t)=>{this.close(t)})}enable(){this.enabled=!0,this.updateActiveBounds(),this.activeId&&this.attach(this.activeId)}disable(){this.enabled=!1;const e=this.activeId?this.views.get(this.activeId):null;e&&this.win.removeBrowserView(e)}destroy(){this.disable(),this.views.forEach(e=>{e.webContents.destroy()}),this.views.clear(),s.ipcMain.removeHandler(r.TAB_CREATE),s.ipcMain.removeHandler(r.TAB_LIST),s.ipcMain.removeHandler(r.TAB_NAVIGATE),s.ipcMain.removeHandler(r.TAB_RELOAD),s.ipcMain.removeHandler(r.TAB_BACK),s.ipcMain.removeHandler(r.TAB_FORWARD),s.ipcMain.removeHandler(r.TAB_SWITCH),s.ipcMain.removeHandler(r.TAB_CLOSE)}list(){return Array.from(this.views.entries()).map(([e,t])=>this.info(e,t))}create(e,t=!0){const i=ce.randomUUID(),o=new s.BrowserView({webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?C.join(process.cwd(),"dist-electron/preload/preload.js"):C.join(__dirname,"preload.js")}});this.views.set(i,o),this.enabled&&t&&this.attach(i);const a=e&&e.length>0?e:"about:blank";o.webContents.loadURL(a),this.bindEvents(i,o);const c=this.info(i,o);return this.win.webContents.send("tab-created",c),c}switch(e){this.views.has(e)&&(this.enabled&&this.attach(e),this.win.webContents.send("tab-switched",{tabId:e}))}close(e){const t=this.views.get(e);if(!t)return;this.activeId===e&&(this.win.removeBrowserView(t),this.activeId=null),t.webContents.destroy(),this.views.delete(e),this.win.webContents.send("tab-closed",{tabId:e});const i=this.views.keys().next().value;i&&this.switch(i)}navigate(e,t){const i=this.views.get(e);i&&(this.skipNextNavigate.set(e,!0),i.webContents.loadURL(t))}reload(e){const t=this.views.get(e);t&&t.webContents.reload()}goBack(e){const t=this.views.get(e);t&&t.webContents.canGoBack()&&t.webContents.goBack()}goForward(e){const t=this.views.get(e);t&&t.webContents.canGoForward()&&t.webContents.goForward()}attach(e){if(!this.enabled)return;const t=this.views.get(e);if(t){if(this.activeId&&this.views.get(this.activeId)){const i=this.views.get(this.activeId);this.win.removeBrowserView(i)}this.activeId=e,this.win.addBrowserView(t),this.updateActiveBounds()}}updateActiveBounds(){if(!this.enabled||!this.activeId)return;const e=this.views.get(this.activeId);if(!e)return;const[t,i]=this.win.getContentSize(),o=88,a=8,c=488,d=a,f=o+a,l=t-c-a,p=i-o-a*2;e.setBounds({x:d,y:f,width:Math.max(0,l),height:Math.max(0,p)})}bindEvents(e,t){const i=()=>this.win.webContents.send("tab-updated",this.info(e,t));t.webContents.on("did-start-loading",i),t.webContents.on("did-stop-loading",i),t.webContents.on("did-finish-load",i),t.webContents.on("page-title-updated",i),t.webContents.on("did-navigate",i),t.webContents.on("did-navigate-in-page",i),t.webContents.on("will-navigate",(o,a)=>{if(this.skipNextNavigate.get(e)){this.skipNextNavigate.set(e,!1);return}o.preventDefault(),this.create(a)}),t.webContents.setWindowOpenHandler(({url:o})=>(this.create(o),{action:"deny"}))}info(e,t){const i=t.webContents;return{id:e,url:i.getURL(),title:i.getTitle(),isLoading:i.isLoading(),canGoBack:i.canGoBack(),canGoForward:i.canGoForward()}}}const Q=n=>{if(n){J.create();return}J.destroy()},qe=n=>{const e=o=>{u.logUserOperation(`${r.SHOW_CONTEXT_MENU}:${E.CONVERSATION_ITEM}-${o}`),n.webContents.send(`${r.SHOW_CONTEXT_MENU}:${E.CONVERSATION_ITEM}`,o)};x.register(E.CONVERSATION_ITEM,[{id:D.PIN,label:"menu.conversation.pinConversation",click:()=>e(D.PIN)},{id:D.RENAME,label:"menu.conversation.renameConversation",click:()=>e(D.RENAME)},{id:D.DEL,label:"menu.conversation.delConversation",click:()=>e(D.DEL)}]);const t=o=>{u.logUserOperation(`${r.SHOW_CONTEXT_MENU}:${E.CONVERSATION_LIST}-${o}`),n.webContents.send(`${r.SHOW_CONTEXT_MENU}:${E.CONVERSATION_LIST}`,o)};x.register(E.CONVERSATION_LIST,[{id:_.NEW_CONVERSATION,label:"menu.conversation.newConversation",click:()=>t(_.NEW_CONVERSATION)},{type:"separator"},{id:_.SORT_BY,label:"menu.conversation.sortBy",submenu:[{id:_.SORT_BY_CREATE_TIME,label:"menu.conversation.sortByCreateTime",type:"radio",checked:!1,click:()=>t(_.SORT_BY_CREATE_TIME)},{id:_.SORT_BY_UPDATE_TIME,label:"menu.conversation.sortByUpdateTime",type:"radio",checked:!1,click:()=>t(_.SORT_BY_UPDATE_TIME)},{id:_.SORT_BY_NAME,label:"menu.conversation.sortByName",type:"radio",checked:!1,click:()=>t(_.SORT_BY_NAME)},{id:_.SORT_BY_MODEL,label:"menu.conversation.sortByModel",type:"radio",checked:!1,click:()=>t(_.SORT_BY_MODEL)},{type:"separator"},{id:_.SORT_ASCENDING,label:"menu.conversation.sortAscending",type:"radio",checked:!1,click:()=>t(_.SORT_ASCENDING)},{id:_.SORT_DESCENDING,label:"menu.conversation.sortDescending",type:"radio",checked:!1,click:()=>t(_.SORT_DESCENDING)}]},{id:_.BATCH_OPERATIONS,label:"menu.conversation.batchOperations",click:()=>t(_.BATCH_OPERATIONS)}]);const i=o=>{u.logUserOperation(`${r.SHOW_CONTEXT_MENU}:${E.MESSAGE_ITEM}-${o}`),n.webContents.send(`${r.SHOW_CONTEXT_MENU}:${E.MESSAGE_ITEM}`,o)};x.register(E.MESSAGE_ITEM,[{id:O.COPY,label:"menu.message.copyMessage",click:()=>i(O.COPY)},{id:O.SELECT,label:"menu.message.selectMessage",click:()=>i(O.SELECT)},{type:"separator"},{id:O.DELETE,label:"menu.message.deleteMessage",click:()=>i(O.DELETE)}])};function re(){W.onWindowCreate(w.MAIN,n=>{let e=T.get(g.MINIMIZE_TO_TRAY);T.onConfigChange(i=>{e!==i[g.MINIMIZE_TO_TRAY]&&(e=i[g.MINIMIZE_TO_TRAY],Q(e))}),Q(e),qe(n);const t=new Ye(n);t.enable(),n.on("closed",()=>{t.destroy()})}),W.create(w.MAIN,ie),s.ipcMain.on(r.START_A_DIALOGUE,async(n,e)=>{const{providerName:t,messages:i,messageId:o,selectedModel:a}=e,c=W.get(w.MAIN);if(!c)throw new Error("mainWindow not found");try{const f=await De(t)?.chat(i,a);if(!f)throw new Error("chunks or stream not found");for await(const l of f){const p={messageId:o,data:l};c.webContents.send(r.START_A_DIALOGUE+"back"+o,p)}}catch(d){const f={messageId:o,data:{isEnd:!0,isError:!0,result:d instanceof Error?d.message:String(d)}};c.webContents.send(r.START_A_DIALOGUE+"back"+o,f)}})}function Xe(){if(process.platform==="win32")return"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";if(process.platform==="darwin")return"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";if(process.platform==="linux")return"google-chrome"}function Ze(n){return C.join(s.app.getPath("userData"),"profiles",n)}function Ke(n){return new Promise(e=>{const t=de.createServer();t.once("error",i=>e(!0)),t.once("listening",()=>{t.close(),e(!1)}),t.listen(n)})}async function Je(){try{return new Promise(n=>{const e=ue.get("http://127.0.0.1:9222/json/version",t=>{n(t.statusCode===200)});e.on("error",()=>n(!1)),e.setTimeout(1e3,()=>{e.destroy(),n(!1)})})}catch{return!1}}async function Qe(){const n=Xe(),e=Ze("default");if(h.info(`Launching Chrome with user data dir: ${e}`),await Ke(9222)){h.info("Chrome already running on port 9222, skip launching.");return}if(await Je()){h.info("Chrome already running, skip launching.");return}return new Promise((i,o)=>{he.spawn(n,["--remote-debugging-port=9222","--window-size=1920,1080","--window-position=0,0","--no-first-run",`--user-data-dir=${e}`,"--no-default-browser-check","about:blank"],{detached:!0,stdio:"ignore"}).on("error",o),setTimeout(()=>{i(0)},1e3)})}class Ve extends pe.EventEmitter{async executeScript(e,t){const o=(a,c)=>{const d=a+c;return d.length>32768?d.slice(d.length-32768):d};return await new Promise(a=>{try{const c=t?.roomType??"",d=t?.startTime??"",f=t?.endTime??"",l=t?.operation??"",p=t?.tabIndex??"",m=t?.channels??"",b=t?.startTabIndex??"",A=s.utilityProcess.fork(e,[],{env:{...process.env,ROOM_TYPE:String(c),START_DATE:String(d),END_DATE:String(f),OPERATION:String(l),TAB_INDEX:String(p),CHANNELS:typeof m=="string"?m:JSON.stringify(m),START_TAB_INDEX:String(b)},stdio:"pipe"});let I="",R="";A.stdout&&A.stdout.on("data",M=>{const N=M.toString();I=o(I,N),h.info(`stdout: ${N}`)}),A.stderr&&A.stderr.on("data",M=>{const N=M.toString();R=o(R,N),h.info(`stderr: ${N}`)}),A.on("exit",M=>{h.info(`子进程退出,退出码 ${M}`),a({success:M===0,exitCode:M,stdoutTail:I,stderrTail:R,...M===0?{}:{error:`Script exited with code ${M}`}})})}catch(c){a({success:!1,exitCode:null,stdoutTail:"",stderrTail:"",error:c?.message||"运行 Node 脚本时出错"})}})}}const H=new Map;function V(){return s.app.isPackaged?U.join(__dirname,"scripts"):U.join(process.cwd(),"electron/scripts")}function et(){const n=new Ve;s.ipcMain.handle(r.OPEN_CHANNEL,async(e,t)=>{try{await Qe();const i=V(),o=U.join(i,"open_all_channel.js");if(H.clear(),Array.isArray(t))for(let c=0;c{try{const i=t.roomList.find(l=>l.id===t.roomType),a=[["fzName","fg_trace.js"],["mtName","mt_trace.js"],["dyHotelName","dy_hotel_trace.js"],["dyHotSpringName","dy_hot_spring_trace.js"]].filter(([l])=>i?.[l]),c=V(),d=a.map(([l,p])=>{const m=U.join(c,p);if(!ee.existsSync(m))throw new Error(`Script not found for channel ${l}: ${m}`);return{channel:l,scriptPath:m}}),f=[];for(let l=0;lthis.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"checking"})),y.autoUpdater.on("update-available",e=>this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"available",info:e})),y.autoUpdater.on("update-not-available",()=>this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"not-available"})),y.autoUpdater.on("download-progress",e=>this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"downloading",progress:e})),y.autoUpdater.on("update-downloaded",e=>this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"downloaded",info:e})),y.autoUpdater.on("error",e=>this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"error",error:e.message}))}sendToRenderer(e,t){s.BrowserWindow.getAllWindows().forEach(i=>{i.isDestroyed()||i.webContents.send(e,t)})}registerHandlers(){s.ipcMain.handle(r.UPDATE_CHECK,()=>s.app.isPackaged?y.autoUpdater.checkForUpdates():(this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"checking"}),setTimeout(()=>{this.sendToRenderer(r.UPDATE_STATUS_CHANGED,{status:"not-available"})},1500),null)),s.ipcMain.handle(r.UPDATE_DOWNLOAD,()=>s.app.isPackaged?y.autoUpdater.downloadUpdate():null),s.ipcMain.handle(r.UPDATE_INSTALL,()=>s.app.isPackaged?y.autoUpdater.quitAndInstall():null),s.ipcMain.handle(r.UPDATE_VERSION,()=>s.app.getVersion())}}const tt=Z.getInstance();tt.init();le&&s.app.quit();s.app.whenReady().then(()=>{re(),et()});s.app.on("window-all-closed",()=>{process.platform!=="darwin"&&!T.get(g.MINIMIZE_TO_TRAY)&&(h.info("app closing due to all windows being closed"),s.app.quit())});s.app.on("activate",()=>{s.BrowserWindow.getAllWindows().length===0&&re()}); diff --git a/dist-electron/main/main.jsc b/dist-electron/main/main.jsc index a5dff2de635ea69420cc3a8ae6af7373ae91e0e8..32107a2a53a79873a94416d9c320d2be9a5e9c46 100644 GIT binary patch delta 53342 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 Pulz!9Yw>Y*lAr$vSj;y| delta 49554 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 K{~R66|Nb8`Aa&{h diff --git a/dist-electron/preload/preload.js b/dist-electron/preload/preload.js index 0164736..59832c9 100644 --- a/dist-electron/preload/preload.js +++ b/dist-electron/preload/preload.js @@ -1,99 +1 @@ -"use strict"; -const electron = require("electron"); -var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => { - IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open"; - IPC_EVENTS2["WINDOW_MINIMIZE"] = "window-minimize"; - IPC_EVENTS2["WINDOW_MAXIMIZE"] = "window-maximize"; - IPC_EVENTS2["WINDOW_CLOSE"] = "window-close"; - IPC_EVENTS2["IS_WINDOW_MAXIMIZED"] = "is-window-maximized"; - IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless"; - IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page"; - IPC_EVENTS2["TAB_CREATE"] = "tab:create"; - IPC_EVENTS2["TAB_LIST"] = "tab:list"; - IPC_EVENTS2["TAB_NAVIGATE"] = "tab:navigate"; - IPC_EVENTS2["TAB_RELOAD"] = "tab:reload"; - IPC_EVENTS2["TAB_BACK"] = "tab:back"; - IPC_EVENTS2["TAB_FORWARD"] = "tab:forward"; - IPC_EVENTS2["TAB_SWITCH"] = "tab:switch"; - IPC_EVENTS2["TAB_CLOSE"] = "tab:close"; - IPC_EVENTS2["LOG_TO_MAIN"] = "log-to-main"; - IPC_EVENTS2["READ_FILE"] = "read-file"; - IPC_EVENTS2["INVOKE"] = "ipc:invoke"; - IPC_EVENTS2["INVOKE_ASYNC"] = "ipc:invokeAsync"; - IPC_EVENTS2["APP_MINIMIZE"] = "app:minimize"; - IPC_EVENTS2["APP_MAXIMIZE"] = "app:maximize"; - IPC_EVENTS2["APP_QUIT"] = "app:quit"; - IPC_EVENTS2["FILE_READ"] = "file:read"; - IPC_EVENTS2["FILE_WRITE"] = "file:write"; - IPC_EVENTS2["GET_WINDOW_ID"] = "get-window-id"; - IPC_EVENTS2["CUSTOM_EVENT"] = "custom:event"; - IPC_EVENTS2["TIME_UPDATE"] = "time:update"; - IPC_EVENTS2["RENDERER_IS_READY"] = "renderer-ready"; - IPC_EVENTS2["SHOW_CONTEXT_MENU"] = "show-context-menu"; - IPC_EVENTS2["START_A_DIALOGUE"] = "start-a-dialogue"; - IPC_EVENTS2["OPEN_WINDOW"] = "open-window"; - IPC_EVENTS2["LOG_DEBUG"] = "log-debug"; - IPC_EVENTS2["LOG_INFO"] = "log-info"; - IPC_EVENTS2["LOG_WARN"] = "log-warn"; - IPC_EVENTS2["LOG_ERROR"] = "log-error"; - IPC_EVENTS2["CONFIG_UPDATED"] = "config-updated"; - IPC_EVENTS2["SET_CONFIG"] = "set-config"; - IPC_EVENTS2["GET_CONFIG"] = "get-config"; - IPC_EVENTS2["UPDATE_CONFIG"] = "update-config"; - IPC_EVENTS2["SET_THEME_MODE"] = "set-theme-mode"; - IPC_EVENTS2["GET_THEME_MODE"] = "get-theme-mode"; - IPC_EVENTS2["IS_DARK_THEME"] = "is-dark-theme"; - IPC_EVENTS2["THEME_MODE_UPDATED"] = "theme-mode-updated"; - IPC_EVENTS2["EXECUTE_SCRIPT"] = "execute-script"; - IPC_EVENTS2["OPEN_CHANNEL"] = "open-channel"; - IPC_EVENTS2["UPDATE_CHECK"] = "update:check"; - IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download"; - IPC_EVENTS2["UPDATE_INSTALL"] = "update:install"; - IPC_EVENTS2["UPDATE_VERSION"] = "update:version"; - IPC_EVENTS2["UPDATE_STATUS_CHANGED"] = "update:status-changed"; - return IPC_EVENTS2; -})(IPC_EVENTS || {}); -const api = { - versions: process.versions, - external: { - open: (url) => electron.ipcRenderer.invoke("external-open", url) - }, - closeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_CLOSE), - minimizeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_MINIMIZE), - maximizeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_MAXIMIZE), - onWindowMaximized: (callback) => electron.ipcRenderer.on(IPC_EVENTS.WINDOW_MAXIMIZE + "back", (_, isMaximized) => callback(isMaximized)), - isWindowMaximized: () => electron.ipcRenderer.invoke(IPC_EVENTS.IS_WINDOW_MAXIMIZED), - viewIsReady: () => electron.ipcRenderer.send(IPC_EVENTS.RENDERER_IS_READY), - app: { - setFrameless: (route) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_SET_FRAMELESS, route), - loadPage: (page) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_LOAD_PAGE, page) - }, - // 通过 IPC 调用主进程 - readFile: (filePath) => electron.ipcRenderer.invoke(IPC_EVENTS.READ_FILE, filePath), - // 异步调用(映射为 electron 的 invoke) - invoke: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args), - // 异步调用(为了兼容老代码) - invokeAsync: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args), - // 监听主进程消息 - on: (event, callback) => { - const subscription = (_event, ...args) => callback(...args); - electron.ipcRenderer.on(event, subscription); - return () => electron.ipcRenderer.removeListener(event, subscription); - }, - // 发送消息到主进程 - send: (channel, ...args) => electron.ipcRenderer.send(channel, ...args), - // 获取窗口ID - getCurrentWindowId: () => electron.ipcRenderer.sendSync(IPC_EVENTS.GET_WINDOW_ID), - // 发送日志 - logger: { - debug: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_DEBUG, message, ...meta), - info: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_INFO, message, ...meta), - warn: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_WARN, message, ...meta), - error: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta) - }, - // 执行脚本 - executeScript: (params) => electron.ipcRenderer.invoke(IPC_EVENTS.EXECUTE_SCRIPT, params), - // 打开渠道 - openChannel: (channels) => electron.ipcRenderer.invoke(IPC_EVENTS.OPEN_CHANNEL, channels) -}; -electron.contextBridge.exposeInMainWorld("api", api); +"use strict";const n=require("electron");var i=(e=>(e.EXTERNAL_OPEN="external-open",e.WINDOW_MINIMIZE="window-minimize",e.WINDOW_MAXIMIZE="window-maximize",e.WINDOW_CLOSE="window-close",e.IS_WINDOW_MAXIMIZED="is-window-maximized",e.APP_SET_FRAMELESS="app:set-frameless",e.APP_LOAD_PAGE="app:load-page",e.TAB_CREATE="tab:create",e.TAB_LIST="tab:list",e.TAB_NAVIGATE="tab:navigate",e.TAB_RELOAD="tab:reload",e.TAB_BACK="tab:back",e.TAB_FORWARD="tab:forward",e.TAB_SWITCH="tab:switch",e.TAB_CLOSE="tab:close",e.LOG_TO_MAIN="log-to-main",e.READ_FILE="read-file",e.INVOKE="ipc:invoke",e.INVOKE_ASYNC="ipc:invokeAsync",e.APP_MINIMIZE="app:minimize",e.APP_MAXIMIZE="app:maximize",e.APP_QUIT="app:quit",e.FILE_READ="file:read",e.FILE_WRITE="file:write",e.GET_WINDOW_ID="get-window-id",e.CUSTOM_EVENT="custom:event",e.TIME_UPDATE="time:update",e.RENDERER_IS_READY="renderer-ready",e.SHOW_CONTEXT_MENU="show-context-menu",e.START_A_DIALOGUE="start-a-dialogue",e.OPEN_WINDOW="open-window",e.LOG_DEBUG="log-debug",e.LOG_INFO="log-info",e.LOG_WARN="log-warn",e.LOG_ERROR="log-error",e.CONFIG_UPDATED="config-updated",e.SET_CONFIG="set-config",e.GET_CONFIG="get-config",e.UPDATE_CONFIG="update-config",e.SET_THEME_MODE="set-theme-mode",e.GET_THEME_MODE="get-theme-mode",e.IS_DARK_THEME="is-dark-theme",e.THEME_MODE_UPDATED="theme-mode-updated",e.EXECUTE_SCRIPT="execute-script",e.OPEN_CHANNEL="open-channel",e.UPDATE_CHECK="update:check",e.UPDATE_DOWNLOAD="update:download",e.UPDATE_INSTALL="update:install",e.UPDATE_VERSION="update:version",e.UPDATE_STATUS_CHANGED="update:status-changed",e))(i||{});const a={versions:process.versions,external:{open:e=>n.ipcRenderer.invoke("external-open",e)},closeWindow:()=>n.ipcRenderer.send(i.WINDOW_CLOSE),minimizeWindow:()=>n.ipcRenderer.send(i.WINDOW_MINIMIZE),maximizeWindow:()=>n.ipcRenderer.send(i.WINDOW_MAXIMIZE),onWindowMaximized:e=>n.ipcRenderer.on(i.WINDOW_MAXIMIZE+"back",(r,d)=>e(d)),isWindowMaximized:()=>n.ipcRenderer.invoke(i.IS_WINDOW_MAXIMIZED),viewIsReady:()=>n.ipcRenderer.send(i.RENDERER_IS_READY),app:{setFrameless:e=>n.ipcRenderer.invoke(i.APP_SET_FRAMELESS,e),loadPage:e=>n.ipcRenderer.invoke(i.APP_LOAD_PAGE,e)},readFile:e=>n.ipcRenderer.invoke(i.READ_FILE,e),invoke:(e,...r)=>n.ipcRenderer.invoke(e,...r),invokeAsync:(e,...r)=>n.ipcRenderer.invoke(e,...r),on:(e,r)=>{const d=(t,...o)=>r(...o);return n.ipcRenderer.on(e,d),()=>n.ipcRenderer.removeListener(e,d)},send:(e,...r)=>n.ipcRenderer.send(e,...r),getCurrentWindowId:()=>n.ipcRenderer.sendSync(i.GET_WINDOW_ID),logger:{debug:(e,...r)=>n.ipcRenderer.send(i.LOG_DEBUG,e,...r),info:(e,...r)=>n.ipcRenderer.send(i.LOG_INFO,e,...r),warn:(e,...r)=>n.ipcRenderer.send(i.LOG_WARN,e,...r),error:(e,...r)=>n.ipcRenderer.send(i.LOG_ERROR,e,...r)},executeScript:e=>n.ipcRenderer.invoke(i.EXECUTE_SCRIPT,e),openChannel:e=>n.ipcRenderer.invoke(i.OPEN_CHANNEL,e)};n.contextBridge.exposeInMainWorld("api",a); diff --git a/dist/assets/index-CvK9ZwFP.css b/dist/assets/index-CvK9ZwFP.css deleted file mode 100644 index 5c4f0c7..0000000 --- a/dist/assets/index-CvK9ZwFP.css +++ /dev/null @@ -1 +0,0 @@ -[data-v-eceb1c86] .el-steps--simple{background:0 0}[data-v-eceb1c86] .el-step.is-simple .el-step__arrow:before{background:#525866;width:2px}[data-v-eceb1c86] .el-step.is-simple .el-step__arrow:after{background:#525866;width:2px}[data-v-eceb1c86] .el-step__head.is-process .el-step__icon.is-text{border-color:#2b7fff}[data-v-eceb1c86] .el-step__head.is-success{color:#1fc16b}[data-v-eceb1c86] .el-step__head.is-success .el-step__icon.is-text{background:#1fc16b}[data-v-eceb1c86] .el-step__head.is-success .el-step__icon.is-text{color:#fff;border-color:#1fc16b}[data-v-eceb1c86] .el-step__title.is-success{color:#525866;font-size:14px;font-weight:500}[data-v-eceb1c86] .el-textarea .el-input__count.is-outside{top:auto;bottom:10px;right:15px}[data-v-6ab79709] .el-button.button{background:linear-gradient(#4a8ff9,#0000),#2b7fff;border:1px solid #1447e6;border-radius:8px;padding-top:18px;padding-bottom:18px;box-shadow:0 1px 1px #0000000d,inset 0 0 0 1px #ffffff3d}[data-v-84bf9ea3] .el-table tr td:nth-of-type(1){background:#eff6ff!important}[data-v-84bf9ea3] .el-tag{color:#525866;background:#fff!important;border:1px solid #e5e8ee!important;border-radius:6px!important}[data-v-4c31200f] .el-tabs__item{color:#99a0ae}[data-v-4c31200f] .el-tabs__item.is-active{color:#2b7fff}[data-v-4c31200f] .el-tabs__active-bar{background-color:#2b7fff} diff --git a/dist/assets/index-tccZ5UIk.css b/dist/assets/index-tccZ5UIk.css deleted file mode 100644 index 46fb464..0000000 --- a/dist/assets/index-tccZ5UIk.css +++ /dev/null @@ -1 +0,0 @@ -.task[data-v-74ff89ed]{z-index:1;transition:all .2s linear;position:relative}.task .success[data-v-74ff89ed]{color:#1fc16b;background-color:#e0faec}.task .error[data-v-74ff89ed]{color:#fb3748;background-color:#ffebec}.task .warning[data-v-74ff89ed]{color:#fa7319;background-color:#fff3eb}.task[data-v-74ff89ed]:hover{z-index:2;transform:translateY(-2px);box-shadow:0 10px 20px #0000001a}.task-tab .text[data-v-be5e193a]{color:#525866;cursor:pointer;font-size:14px}.task-tab .active[data-v-be5e193a]{color:#2b7fff;background:#fff;border-radius:8px;position:relative}.task-tab .active[data-v-be5e193a]:after{content:"";border:1px solid #2b7fff;border-radius:8px;width:100%;height:100%;position:absolute;top:0;left:0}.task-tab .text[data-v-33324fcc]{color:#525866;cursor:pointer;font-size:14px}.task-tab .active[data-v-33324fcc]{color:#2b7fff;background:#fff;border-radius:8px;position:relative}.task-tab .active[data-v-33324fcc]:after{content:"";border:1px solid #2b7fff;border-radius:8px;width:100%;height:100%;position:absolute;top:0;left:0}pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}.wave[data-v-5b734189]{text-align:center;width:30px;position:relative}.dot[data-v-5b734189]{background:#333;border-radius:50%;width:3px;height:3px;margin-right:3px;animation:1.3s linear infinite wave-5b734189;display:inline-block}.dot[data-v-5b734189]:nth-child(2){animation-delay:-1.1s}.dot[data-v-5b734189]:nth-child(3){animation-delay:-.9s}@keyframes wave-5b734189{0%,60%,to{transform:initial}30%{transform:translateY(-5px)}} diff --git a/dist/index.html b/dist/index.html index d64847e..54eda75 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,17 +1,17 @@ - - - - - NIANXX - - - - - - -
- - + + + + + NIANXX + + + + + + +
+ + diff --git a/package.json b/package.json index cc3a98e..6d8b195 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "start": "vite", "build": "vite build && electron-builder", "build:vite": "vite build", - "package": "electron-builder", + "package": "vite build", "icons": "zx scripts/generate-icons.mjs", "uv:download": "zx scripts/download-bundled-uv.mjs", "uv:download:mac": "zx scripts/download-bundled-uv.mjs --platform=mac", @@ -18,10 +18,14 @@ "uv:download:all": "zx scripts/download-bundled-uv.mjs --all", "node:download:win": "zx scripts/download-bundled-node.mjs --platform=win", "prep:win-binaries": "pnpm run uv:download:win && pnpm run node:download:win", - "package:win": "pnpm run prep:win-binaries && vite build && electron-builder --win --publish never", - "package:mac": "vite build && electron-builder --mac --publish never", - "package:linux": "vite build && electron-builder --linux --publish never", - "release": "vite build && electron-builder --publish always", + "package:win": "pnpm run prep:win-binaries && pnpm run package && electron-builder --win --publish never", + "package:mac": "pnpm run package && electron-builder --mac --publish never", + "package:mac:local": "SKIP_AFTERPACK_CLEANUP=1 pnpm run package && electron-builder --mac --publish never", + "package:mac:x64": "pnpm run package && electron-builder --mac --x64 --publish never", + "package:mac:arm64": "pnpm run package && electron-builder --mac --arm64 --publish never", + "package:mac:fast": "pnpm run package && electron-builder --mac --publish never --config.compression=normal", + "package:linux": "pnpm run package && electron-builder --linux --publish never", + "release": "pnpm run package && electron-builder --publish always", "lint": "eslint --ext .ts,.tsx .", "typecheck": "tsc --noEmit", "openapi": "dotenv -e .env -- openapi-ts", diff --git a/package_mac_diagnosis_report.md b/package_mac_diagnosis_report.md new file mode 100644 index 0000000..83eb773 --- /dev/null +++ b/package_mac_diagnosis_report.md @@ -0,0 +1,145 @@ +# package:mac 打包诊断报告 + +**诊断时间**: 2026-04-11 +**项目路径**: `/Users/duanshuwen/Documents/workspace/electron/zn-ai` +**执行命令**: `pnpm run package:mac` + +--- + +## 1. 结论摘要 + +**本次打包失败不是因为项目源码缺少文件或 `electron-builder.yml` 配置项缺失,而是因为** + +1. **网络下载中断**:`electron-builder` 在构建 DMG 时需要下载 `dmgbuild-bundle-x86_64`,该请求被服务器中断(`ReadError: The server aborted pending request`)。 +2. **并发锁竞争**:`mac.target` 同时配置了 `x64` 与 `arm64` 两种架构,`electron-builder` 并行打包时两个进程争抢 `proper-lockfile` 的缓存锁,导致下载失败后的清理阶段抛出 `Lock file is already being held` 错误。 +3. **(非致命)代码签名证书已过期**:本地唯一的 `Apple Development` 证书状态为 `CSSMERR_TP_CERT_EXPIRED`,因此 `electron-builder` 跳过了正式签名,仅做了 ad-hoc 签名。这不会导致打包中断,但会影响最终 app 在 macOS Gatekeeper 下的可运行性。 + +--- + +## 2. 关键错误日志 + +```text + • downloading release=dmg-builder@1.2.0 file=dmgbuild-bundle-x86_64-75c8a6c.tar.gz +... +ReadError: The server aborted pending request +... +Error: Lock file is already being held + at /Users/duanshuwen/Documents/workspace/electron/zn-ai/node_modules/proper-lockfile/lib/lockfile.js:68:47 +... + ELIFECYCLE  Command failed with exit code 1. +``` + +--- + +## 3. 配置与文件检查结果 + +| 检查项 | 状态 | 说明 | +|--------|------|------| +| `package.json` | 正常 | 存在且 `package:mac` 脚本定义正确 | +| `electron-builder.yml` | 正常 | 配置完整,`mac` / `dmg` / `win` / `linux` 分平台配置齐全 | +| `resources/icons/icon.icns` | 正常 | `mac.icon` 指向的文件存在 | +| `entitlements.mac.plist` | 正常 | 文件存在并已配置 | +| `dist` / `dist-electron` | 正常 | `vite build` 阶段成功通过,产物已生成 | +| 发布产物 | 部分生成 | `zip`(x64 / arm64)已成功生成,但 DMG(x64 / arm64)因下载失败未完成 | + +--- + +## 4. 详细原因分析 + +### 4.1 网络问题导致 dmg-builder 下载中断 +`electron-builder` 在首次构建 DMG 时需要拉取预编译的 `dmg-builder` bundle(`dmgbuild-bundle-x86_64-75c8a6c.tar.gz`)。由于该资源托管在 GitHub / AWS CDN 上,在国内网络环境下极易出现连接被重置或请求被服务器中断的情况。 + +### 4.2 并发构建加剧锁竞争 +`electron-builder.yml` 中配置了同时打包两种架构: + +```yaml +mac: + target: + - target: dmg + arch: + - x64 + - arm64 + - target: zip + arch: + - x64 + - arm64 +``` + +这导致 `electron-builder` 会并行启动多个打包任务。当它们同时尝试下载/解压同一个 `dmg-builder` 缓存时,`proper-lockfile` 产生竞争;一旦其中一个下载失败,另一个在清理阶段也会因无法获取锁而报错,最终整体构建失败。 + +### 4.3 代码签名证书过期(仅提示,不中断构建) +日志中出现的: + +```text +skipped macOS application code signing reason=cannot find valid "Developer ID Application" identity ... +"Apple Development: 562304744@qq.com (Z27TQS657B)" (CSSMERR_TP_CERT_EXPIRED) +``` + +这说明本地证书已过期,不会影响打包流程本身,但生成的 `.app` 没有有效的开发者签名,分发后用户打开时会遇到 "已损坏,无法打开" 的 Gatekeeper 提示。 + +--- + +## 5. 解决方案与建议 + +### 方案 A:分架构单独打包(推荐,最稳定) +先避免并发锁竞争,同时降低单次构建对网络的敏感度: + +```bash +# 仅打包 arm64(Apple Silicon) +cd zn-ai +npx electron-builder --mac --arm64 --publish never + +# 仅打包 x64(Intel) +npx electron-builder --mac --x64 --publish never +``` + +若网络仍不稳定,可配置代理或手动下载缓存(见方案 B)。 + +### 方案 B:配置 electron-builder 缓存 +如果网络受限,可预先设置缓存目录并手动下载所需 bundle: + +```bash +export ELECTRON_BUILDER_CACHE="$HOME/.electron-builder-cache" +``` + +然后手动将 `dmgbuild-bundle-x86_64-75c8a6c.tar.gz` 放置到缓存目录的 `cache/dmg-builder` 子目录下,再执行打包。 + +### 方案 C:修改 `electron-builder.yml` 降低并发 +在 `mac.target` 里先只保留当前常用架构(如 `arm64`),需要时再切换: + +```yaml +mac: + target: + - target: dmg + arch: + - arm64 + - target: zip + arch: + - arm64 +``` + +### 方案 D:修复代码签名(分发前必须) +若计划将应用分发给其他用户,需要: +1. 在 Apple Developer 后台续期或重新申请 **Developer ID Application** 证书; +2. 将 `notarize` 改为 `true` 并配置正确的 `teamId`; +3. 在构建机器上安装新证书后重新打包。 + +--- + +## 6. 附录:构建产物现状 + +截至诊断时,`release/` 目录下已生成: + +- `NIANXX-1.0.0-mac-x64.zip` (133 MB) +- `NIANXX-1.0.0-mac-arm64.zip` (129 MB) +- 对应的 `.blockmap` 文件 + +**未生成**: +- `NIANXX-1.0.0-mac-x64.dmg` +- `NIANXX-1.0.0-mac-arm64.dmg` + +原因即上述网络下载中断 + 并发锁竞争。 + +--- + +*报告结束* diff --git a/scripts/after-pack.cjs b/scripts/after-pack.cjs index 202ed20..0b2bf9d 100644 --- a/scripts/after-pack.cjs +++ b/scripts/after-pack.cjs @@ -142,19 +142,23 @@ module.exports = async function afterPack(context) { await ensureDependency(dep); } - // 3. Clean up unnecessary development files from node_modules - const nodeModulesDest = path.join(appOutDir, 'node_modules'); - if (await fs.pathExists(nodeModulesDest)) { - console.log('Cleaning up development files in node_modules...'); - const removed = cleanupUnnecessaryFiles(nodeModulesDest); - console.log(`Removed ${removed} unnecessary files/directories from node_modules.`); - } + // 3. Clean up unnecessary development files from node_modules (skip if SKIP_AFTERPACK_CLEANUP is set) + if (!process.env.SKIP_AFTERPACK_CLEANUP) { + const nodeModulesDest = path.join(appOutDir, 'node_modules'); + if (await fs.pathExists(nodeModulesDest)) { + console.log('Cleaning up development files in node_modules...'); + const removed = cleanupUnnecessaryFiles(nodeModulesDest); + console.log(`Removed ${removed} unnecessary files/directories from node_modules.`); + } - // 4. Clean up unnecessary files in scripts directory - if (await fs.pathExists(scriptsDest)) { - console.log('Cleaning up development files in scripts directory...'); - const removedScripts = cleanupUnnecessaryFiles(scriptsDest); - console.log(`Removed ${removedScripts} unnecessary files/directories from scripts.`); + // 4. Clean up unnecessary files in scripts directory + if (await fs.pathExists(scriptsDest)) { + console.log('Cleaning up development files in scripts directory...'); + const removedScripts = cleanupUnnecessaryFiles(scriptsDest); + console.log(`Removed ${removedScripts} unnecessary files/directories from scripts.`); + } + } else { + console.log('Skipping afterPack cleanup (SKIP_AFTERPACK_CLEANUP is set)'); } // 5. Optional: platform-specific native package cleanup