diff --git a/dist-electron/main/main.js b/dist-electron/main/main.js index 5e08ac0..9900f36 100644 --- a/dist-electron/main/main.js +++ b/dist-electron/main/main.js @@ -1,4 +1,26 @@ "use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); const electron = require("electron"); const OpenAI = require("openai"); const util = require("util"); @@ -13,7 +35,6 @@ const net = require("net"); const http = require("http"); const child_process = require("child_process"); const events = require("events"); -const playwright = require("playwright"); require("bytenode"); const electronUpdater = require("electron-updater"); function _interopNamespaceDefault(e) { @@ -88,6 +109,7 @@ var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => { IPC_EVENTS2["SCRIPT_RUN"] = "script:run"; IPC_EVENTS2["SCRIPT_RECORD_START"] = "script:record-start"; IPC_EVENTS2["SCRIPT_RECORD_STOP"] = "script:record-stop"; + IPC_EVENTS2["SCRIPT_CODEGEN"] = "script:codegen"; IPC_EVENTS2["UPDATE_CHECK"] = "update:check"; IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download"; IPC_EVENTS2["UPDATE_INSTALL"] = "update:install"; @@ -793,7 +815,7 @@ class WindowService { } _loadPage(window2, pageName) { { - return window2.loadURL(`${"http://localhost:5173"}/${pageName}.html`); + return window2.loadURL(`${"http://localhost:5173/"}/${pageName}.html`); } } _loadWindowTemplate(window2, name) { @@ -1702,59 +1724,15 @@ async function runScriptById(id, channel) { }); return result; } -let recorderBrowser = null; -let recorderContext = null; -async function startRecording(url) { - try { - await launchLocalChrome(); - if (recorderBrowser) { - await stopRecording(); - } - recorderBrowser = await playwright.chromium.connectOverCDP("http://127.0.0.1:9222"); - recorderContext = recorderBrowser.contexts()[0] || await recorderBrowser.newContext(); - const page = await recorderContext.newPage(); - const targetUrl = url || "about:blank"; - await page.goto(targetUrl, { waitUntil: "domcontentloaded" }); - await page.pause(); - return { - success: true, - code: "" - }; - } catch (error) { - log.error("[script-recorder-service] Failed to start recording:", error); - return { - success: false, - error: error?.message || "Failed to start recording" - }; - } -} -async function stopRecording() { - try { - if (recorderContext) { - await recorderContext.close().catch(() => { - }); - recorderContext = null; - } - if (recorderBrowser) { - await recorderBrowser.close().catch(() => { - }); - recorderBrowser = null; - } - return { success: true, code: "" }; - } catch (error) { - log.error("[script-recorder-service] Failed to stop recording:", error); - return { - success: false, - error: error?.message || "Failed to stop recording" - }; - } -} 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(); + const playwrightCoreDir = path.dirname(require.resolve("playwright-core")); + const cliPath = path.join(playwrightCoreDir, "cli.js"); + let recorderProc = null; electron.ipcMain.handle(IPC_EVENTS.SCRIPT_LIST, async () => { try { return listScripts(); @@ -1806,7 +1784,29 @@ function runTaskOperationService() { }); electron.ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_START, async (_event, url) => { try { - return await startRecording(url); + if (recorderProc) { + recorderProc.kill("SIGINT"); + recorderProc = null; + } + const targetUrl = url || "about:blank"; + recorderProc = child_process.spawn(process.execPath, [cliPath, "codegen", "--target", "javascript", "--channel", "chrome", "--viewport-size", "1920,1080", "--color-scheme", "light", targetUrl], { + env: { ...process.env, ELECTRON_RUN_AS_NODE: "1" }, + stdio: "pipe" + }); + recorderProc.on("error", (err) => { + log.error("[SCRIPT_RECORD_START] Failed to start codegen process:", err); + }); + recorderProc.on("exit", (code, signal) => { + log.info(`[SCRIPT_RECORD_START] Process exited code=${code} signal=${signal}`); + recorderProc = null; + }); + recorderProc.stdout?.on("data", (data) => { + log.info(`[SCRIPT_RECORD_START] stdout: ${data.toString()}`); + }); + recorderProc.stderr?.on("data", (data) => { + log.error(`[SCRIPT_RECORD_START] stderr: ${data.toString()}`); + }); + return { success: true }; } catch (error) { log.error("[SCRIPT_RECORD_START] error:", error); return { success: false, error: error?.message || "Recording start failed" }; @@ -1814,12 +1814,65 @@ function runTaskOperationService() { }); electron.ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_STOP, async () => { try { - return await stopRecording(); + if (recorderProc) { + recorderProc.kill("SIGINT"); + recorderProc = null; + } + return { success: true, code: "" }; } catch (error) { log.error("[SCRIPT_RECORD_STOP] error:", error); return { success: false, error: error?.message || "Recording stop failed" }; } }); + electron.ipcMain.handle(IPC_EVENTS.SCRIPT_CODEGEN, async (_event, id, url) => { + try { + const script = getScript(id); + if (!script) { + return { success: false, error: "Script not found" }; + } + const scriptsDir = getScriptsDir(); + const scriptPath = path.join(scriptsDir, script.filename); + const targetUrl = url || "about:blank"; + log.info(`[SCRIPT_CODEGEN] Starting codegen for script ${id} at ${scriptPath} with url ${targetUrl}`); + return await new Promise((resolve) => { + const proc = child_process.spawn(process.execPath, [cliPath, "codegen", "--target", "javascript", "--channel", "chrome", "-o", scriptPath, targetUrl], { + env: { ...process.env, ELECTRON_RUN_AS_NODE: "1" }, + stdio: "pipe" + }); + proc.on("exit", () => { + try { + let generatedCode = fs.readFileSync(scriptPath, "utf-8"); + if (generatedCode.includes("require('playwright')") && !generatedCode.includes("createRequire")) { + generatedCode = `import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); + +${generatedCode}`; + } + fs.writeFileSync(scriptPath, generatedCode, "utf-8"); + saveScript({ + id, + name: script.name, + description: script.description, + code: generatedCode, + channel: script.channel, + enabled: script.enabled + }); + resolve({ success: true, code: generatedCode }); + } catch (err) { + log.error("[SCRIPT_CODEGEN] Failed to process generated code:", err); + resolve({ success: false, error: err?.message || "Failed to process generated code" }); + } + }); + proc.on("error", (err) => { + log.error("[SCRIPT_CODEGEN] Failed to start codegen:", err); + resolve({ success: false, error: err.message }); + }); + }); + } catch (error) { + log.error("[SCRIPT_CODEGEN] error:", error); + return { success: false, error: error?.message || "Codegen failed" }; + } + }); electron.ipcMain.handle(IPC_EVENTS.OPEN_CHANNEL, async (_event, channels) => { try { await launchLocalChrome(); diff --git a/dist-electron/main/main.js.bak b/dist-electron/main/main.js.bak index 6995c38..9e75660 100644 --- a/dist-electron/main/main.js.bak +++ b/dist-electron/main/main.js.bak @@ -1 +1,4 @@ -"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()}); +"use strict";var we=Object.create;var re=Object.defineProperty;var Ae=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var Se=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var ve=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ye(e))!Ee.call(n,s)&&s!==t&&re(n,s,{get:()=>e[s],enumerable:!(i=Ae(e,s))||i.enumerable});return n};var Ce=(n,e,t)=>(t=n!=null?we(Se(n)):{},ve(e||!n||!n.__esModule?re(t,"default",{value:n,enumerable:!0}):t,n));const o=require("electron"),De=require("openai"),K=require("util"),d=require("electron-log"),y=require("path"),A=require("fs"),de=require("js-base64"),N=require("node:path"),Ie=require("crypto"),Me=require("electron-squirrel-startup"),Re=require("net"),Oe=require("http"),X=require("child_process"),be=require("events");require("bytenode");const C=require("electron-updater");function ue(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 W=ue(y),I=ue(A);var c=(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.SCRIPT_LIST="script:list",n.SCRIPT_GET="script:get",n.SCRIPT_SAVE="script:save",n.SCRIPT_DELETE="script:delete",n.SCRIPT_TOGGLE="script:toggle",n.SCRIPT_RUN="script:run",n.SCRIPT_RECORD_START="script:record-start",n.SCRIPT_RECORD_STOP="script:record-stop",n.SCRIPT_CODEGEN="script:codegen",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))(c||{});const pe={width:1440,height:900,minWidth:1440,minHeight:900};var E=(n=>(n.MAIN="main",n.SETTING="setting",n.DIALOG="dialog",n.LOADING="loading",n))(E||{}),_=(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))(_||{}),D=(n=>(n.CONVERSATION_ITEM="conversation-item",n.CONVERSATION_LIST="conversation-list",n.MESSAGE_ITEM="message-item",n))(D||{}),O=(n=>(n.PIN="pin",n.RENAME="rename",n.DEL="del",n))(O||{}),w=(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))(w||{}),b=(n=>(n.COPY="copy",n.DELETE="delete",n.SELECT="select",n))(b||{});class Ne{}const Le=K.promisify(I.readdir),Pe=K.promisify(I.stat),We=K.promisify(I.unlink);class J{static _instance;LOG_RETENTION_DAYS=7;CLEANUP_INTERVAL_MS=1440*60*1e3;constructor(){const e=W.join(o.app.getPath("userData"),"logs");try{I.existsSync(e)||I.mkdirSync(e,{recursive:!0})}catch(t){this.error("Failed to create log directory:",t)}d.transports.file.resolvePathFn=()=>{const t=new Date,i=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`;return W.join(e,`${i}.log`)},d.transports.file.format="[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}",d.transports.file.maxSize=10*1024*1024,d.transports.console.level=process.env.NODE_ENV==="development"?"debug":"info",d.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(c.LOG_DEBUG,(e,t,...i)=>this.debug(t,...i)),o.ipcMain.on(c.LOG_INFO,(e,t,...i)=>this.info(t,...i)),o.ipcMain.on(c.LOG_WARN,(e,t,...i)=>this.warn(t,...i)),o.ipcMain.on(c.LOG_ERROR,(e,t,...i)=>this.error(t,...i))}_rewriteConsole(){console.debug=d.debug,console.log=d.info,console.info=d.info,console.warn=d.warn,console.error=d.error}async _cleanupOldLogs(){try{const e=W.join(o.app.getPath("userData"),"logs");if(!I.existsSync(e))return;const t=new Date,i=new Date(t.getTime()-this.LOG_RETENTION_DAYS*24*60*60*1e3),s=await Le(e);let r=0;for(const a of s){if(!a.endsWith(".log"))continue;const l=W.join(e,a);try{const g=await Pe(l);g.isFile()&&g.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 J),this._instance}debug(e,...t){d.debug(e,...t)}info(e,...t){d.info(e,...t)}warn(e,...t){d.warn(e,...t)}error(e,...t){d.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 h=J.getInstance();function Ue(n){const e=n.choices[0];return{isEnd:e?.finish_reason==="stop",result:e?.delta?.content??""}}class ke extends Ne{client;constructor(e,t){super(),this.client=new De({apiKey:e,baseURL:t})}async chat(e,t){const i=Date.now(),s=e[e.length-1];h.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}),a=Date.now()-i;return h.logApiResponse("chat.completions.create",{success:!0},200,a),{async*[Symbol.asyncIterator](){for await(const l of r)yield Ue(l)}}}catch(r){const a=Date.now()-i;throw h.logApiResponse("chat.completions.create",{error:r instanceof Error?r.message:String(r)},500,a),r}}}function he(n,e){let t=null;return function(...i){t&&clearTimeout(t),t=setTimeout(()=>{n.apply(this,i)},e)}}function Z(n){if(n===null||typeof n!="object")return n;if(Array.isArray(n))return n.map(t=>Z(t));const e=Object.assign({},n);for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(e[t]=Z(e[t]));return e}function xe(n){try{return JSON.parse(JSON.stringify(n))}catch(e){return console.error("simpleCloneDeep failed:",e),n}}function Be(n){try{return JSON.parse(de.decode(n))}catch(e){return console.error("parseOpenAISetting failed:",e),{}}}const Ge={[_.THEME_MODE]:"system",[_.PRIMARY_COLOR]:"#BB5BE7",[_.LANGUAGE]:"zh",[_.FONT_SIZE]:14,[_.MINIMIZE_TO_TRAY]:!1,[_.PROVIDER]:"",[_.DEFAULT_MODEL]:null};class Q{static _instance;_config;_configPath;_defaultConfig=Ge;_listeners=[];constructor(){this._configPath=W.join(o.app.getPath("userData"),"config.json"),this._config=this._loadConfig(),this._setupIpcEvents(),h.info("ConfigService initialized successfully.")}_setupIpcEvents(){const t=he(i=>this.update(i),200);o.ipcMain.handle(c.GET_CONFIG,(i,s)=>this.get(s)),o.ipcMain.on(c.SET_CONFIG,(i,s,r)=>this.set(s,r)),o.ipcMain.on(c.UPDATE_CONFIG,(i,s)=>t(s))}static getInstance(){return this._instance||(this._instance=new Q),this._instance}_loadConfig(){try{if(I.existsSync(this._configPath)){const e=I.readFileSync(this._configPath,"utf-8"),t={...this._defaultConfig,...JSON.parse(e)};return h.info("Config loaded successfully from:",this._configPath),t}}catch(e){h.error("Failed to load config:",e)}return{...this._defaultConfig}}_saveConfig(){try{I.mkdirSync(W.dirname(this._configPath),{recursive:!0}),I.writeFileSync(this._configPath,JSON.stringify(this._config,null,2),"utf-8"),this._notifyListeners(),h.info("Config saved successfully to:",this._configPath)}catch(e){h.error("Failed to save config:",e)}}_notifyListeners(){o.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(c.CONFIG_UPDATED,this._config)),this._listeners.forEach(e=>e({...this._config}))}getConfig(){return xe(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,h.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},h.info("Config reset to default."),this._saveConfig()}onConfigChange(e){return this._listeners.push(e),()=>this._listeners=this._listeners.filter(t=>t!==e)}}const v=Q.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 $e=()=>{let n=[],e=!1;const t=v.get(_.PROVIDER),i=s=>({...s,openAISetting:typeof s.openAISetting=="string"?Be(s.openAISetting??""):s.openAISetting});try{n=JSON.parse(de.decode(t)),e=!0}catch(s){h.error(`parse base64 provider failed: ${s}`)}if(!e)try{n=JSON.parse(t)}catch(s){h.error(`parse provider failed: ${s}`)}if(n.length)return n.map(i)},He=()=>{try{return $e()}catch(n){return h.error(`get provider config failed: ${n}`),null}};function Fe(n){const e=He();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 ke(t.openAISetting.apiKey,t.openAISetting.baseURL)}}const ze={minimize:"Minimize",maximize:"Maximize",restore:"Restore",close:"Close"},je={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"}},qe={cancel:"Cancel",confirm:"Confirm"},Ye={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"}},Xe={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"}},Ze={tooltip:"Diona Application",showWindow:"Show Window",exit:"Exit"},Ke={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"}},Je={title:"Diona Application"},Qe={window:ze,main:je,dialog:qe,settings:Ye,menu:Xe,tray:Ze,timeAgo:Ke,app:Je},Ve={minimize:"最小化",maximize:"最大化",restore:"还原",close:"关闭"},et={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:"发送"}},tt={cancel:"取消",confirm:"确认"},nt={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:"语言设置"}},it={conversation:{newConversation:"新建对话",sortBy:"排序方式",sortByCreateTime:"按创建时间排序",sortByUpdateTime:"按更新时间排序",sortByName:"按名称排序",sortByModel:"按模型排序",sortAscending:"递增",sortDescending:"递减",pinConversation:"置顶对话",unpinConversation:"取消置顶",renameConversation:"重命名对话",delConversation:"删除对话",batchOperations:"批量操作"},message:{copyMessage:"复制消息",deleteMessage:"删除消息",selectMessage:"选择消息"}},st={tooltip:"迪奥娜",showWindow:"显示窗口",exit:"退出"},rt={justNow:"刚刚",minutes:"{count}分钟前",hours:"{count}小时前",days:"{count}天前",months:"{count}个月前",years:"{count}年前",weekday:{sun:"星期日",mon:"星期一",tue:"星期二",wed:"星期三",thu:"星期四",fri:"星期五",sat:"星期六"}},ot={title:"迪奥娜"},at={window:Ve,main:et,dialog:tt,settings:nt,menu:it,tray:st,timeAgo:rt,app:ot},ct={en:Qe,zh:at};function H(){return n=>{if(n)try{const e=n?.split(".");let t=ct[v.get(_.LANGUAGE)];for(const i of e)t=t[i];return t}catch(e){return h.error("failed to translate key:",n,e),n}}}let G;function ge(){if(G!=null)return G;const n=o.app.getAppPath();return G=N.join(n,"resources","icons","icon.ico"),G}class V{static _instance;_isDark=o.nativeTheme.shouldUseDarkColors;constructor(){const e=v.get(_.THEME_MODE);e&&(o.nativeTheme.themeSource=e,this._isDark=o.nativeTheme.shouldUseDarkColors),this._setupIpcEvent(),h.info("ThemeService initialized successfully.")}_setupIpcEvent(){o.ipcMain.handle(c.SET_THEME_MODE,(e,t)=>(o.nativeTheme.themeSource=t,v.set(_.THEME_MODE,t),o.nativeTheme.shouldUseDarkColors)),o.ipcMain.handle(c.GET_THEME_MODE,()=>o.nativeTheme.themeSource),o.ipcMain.handle(c.IS_DARK_THEME,()=>o.nativeTheme.shouldUseDarkColors),o.nativeTheme.on("updated",()=>{this._isDark=o.nativeTheme.shouldUseDarkColors,o.BrowserWindow.getAllWindows().forEach(e=>e.webContents.send(c.THEME_MODE_UPDATED,this._isDark))})}static getInstance(){return this._instance||(this._instance=new V),this._instance}get isDark(){return this._isDark}get themeMode(){return o.nativeTheme.themeSource}}const oe=V.getInstance(),lt={frame:!1,titleBarStyle:"hidden",trafficLightPosition:{x:-100,y:-100},show:!1,title:"NIANXX",darkTheme:oe.isDark,backgroundColor:oe.isDark?"#2C2C2C":"#FFFFFF",webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,backgroundThrottling:!1,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?N.join(process.cwd(),"dist-electron/preload/preload.js"):N.join(__dirname,"preload.js")}};class ee{static _instance;_logo=ge();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(),h.info("WindowService initialized successfully.")}_isReallyClose(e){return e===E.MAIN?v.get(_.MINIMIZE_TO_TRAY)===!1:e!==E.SETTING}_setupIpcEvents(){const e=r=>{const a=o.BrowserWindow.fromWebContents(r.sender),l=this.getName(a);this.close(a,this._isReallyClose(l))},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(c.WINDOW_CLOSE,e),o.ipcMain.on(c.WINDOW_MINIMIZE,t),o.ipcMain.on(c.WINDOW_MAXIMIZE,i),o.ipcMain.handle(c.IS_WINDOW_MAXIMIZED,s),o.ipcMain.handle(c.APP_LOAD_PAGE,(r,a)=>{const l=o.BrowserWindow.fromWebContents(r.sender);l&&this._loadPage(l,a)})}static getInstance(){return this._instance||(this._instance=new ee),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(a=>a(r))),s&&(this._winStates[e].isHidden=!1,h.info(`Hidden window show: ${e}`)),r}_setupWinLifecycle(e,t){const i=he(()=>!e?.isDestroyed()&&e?.webContents?.send(c.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,h.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(c.RENDERER_IS_READY,s))};return o.ipcMain.on(c.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(N.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[E.MAIN].instance||this._winStates[E.MAIN].instance?.isDestroyed())return Object.values(this._winStates).forEach(t=>t?.instance?.close());if(!v.get(_.MINIMIZE_TO_TRAY)&&!this.get(E.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({...lt,icon:this._logo,...t})}focus(e){if(!e)return;const t=this.getName(e);e?.isMaximized()?(e?.restore(),h.debug(`Window ${t} restored and focused`)):h.debug(`Window ${t} focused`),e?.focus()}close(e,t=!0){if(!e)return;const i=this.getName(e);h.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 B=ee.getInstance();let F=H();class te{static _instance;_menuTemplates=new Map;_currentMenu=void 0;constructor(){this._setupIpcListener(),this._setupLanguageChangeListener(),h.info("MenuService initialized successfully.")}_setupIpcListener(){o.ipcMain.handle(c.SHOW_CONTEXT_MENU,(e,t,i)=>new Promise(s=>this.showMenu(t,()=>s(!0),i)))}_setupLanguageChangeListener(){v.onConfigChange(e=>{e[_.LANGUAGE]&&(F=H())})}static getInstance(){return this._instance||(this._instance=new te),this._instance}register(e,t){return this._menuTemplates.set(e,t),e}showMenu(e,t,i){if(this._currentMenu)return;const s=Z(this._menuTemplates.get(e));if(!s){h.warn(`Menu ${e} not found.`),t?.();return}let r=[];try{r=Array.isArray(i)?i:JSON.parse(i??"[]")}catch(u){h.error(`Failed to parse dynamicOptions for menu ${e}: ${u}`)}const a=u=>u.submenu?{...u,label:F(u?.label)??void 0,submenu:u.submenu?.map(f=>a(f))}:{...u,label:F(u?.label)??void 0},l=s.map(u=>{if(!Array.isArray(r)||!r.length)return a(u);const f=r.find(m=>m.id===u.id);if(f){const m={...u,...f};return a(m)}return u.submenu?a({...u,submenu:u.submenu?.map(m=>{const T=r.find(p=>p.id===m.id);return{...m,...T}})}):a(u)}),g=o.Menu.buildFromTemplate(l);this._currentMenu=g,g.popup({callback:()=>{this._currentMenu=void 0,t?.()}})}destroyMenu(e){this._menuTemplates.delete(e)}destroyed(){this._menuTemplates.clear(),this._currentMenu=void 0}}const z=te.getInstance();let x=H();class ne{static _instance;_tray=null;_removeLanguageListener;_setupLanguageChangeListener(){this._removeLanguageListener=v.onConfigChange(e=>{e[_.LANGUAGE]&&(x=H(),this._tray&&this._updateTray())})}_updateTray(){this._tray||(this._tray=new o.Tray(ge()));const e=()=>{const t=B.get(E.MAIN);if(t&&!t?.isDestroyed()&&t?.isVisible()&&!t?.isFocused())return t.focus();if(t?.isMinimized())return t?.restore();t?.isVisible()&&t?.isFocused()||B.create(E.MAIN,pe)};this._tray.setToolTip(x("tray.tooltip")??"Diona Application"),this._tray.setContextMenu(o.Menu.buildFromTemplate([{label:x("tray.showWindow"),accelerator:"CmdOrCtrl+N",click:e},{type:"separator"},{label:x("settings.title"),click:()=>o.ipcMain.emit(`${c.OPEN_WINDOW}:${E.SETTING}`)},{role:"quit",label:x("tray.exit")}])),this._tray.removeAllListeners("click"),this._tray.on("click",e)}constructor(){this._setupLanguageChangeListener(),h.info("TrayService initialized successfully.")}static getInstance(){return this._instance||(this._instance=new ne),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 ae=ne.getInstance();class dt{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(c.TAB_CREATE,(e,t)=>this.create(t)),o.ipcMain.handle(c.TAB_LIST,()=>this.list()),o.ipcMain.handle(c.TAB_NAVIGATE,(e,{tabId:t,url:i})=>{this.navigate(t,i)}),o.ipcMain.handle(c.TAB_RELOAD,(e,t)=>{this.reload(t)}),o.ipcMain.handle(c.TAB_BACK,(e,t)=>{this.goBack(t)}),o.ipcMain.handle(c.TAB_FORWARD,(e,t)=>{this.goForward(t)}),o.ipcMain.handle(c.TAB_SWITCH,(e,t)=>{this.switch(t)}),o.ipcMain.handle(c.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(c.TAB_CREATE),o.ipcMain.removeHandler(c.TAB_LIST),o.ipcMain.removeHandler(c.TAB_NAVIGATE),o.ipcMain.removeHandler(c.TAB_RELOAD),o.ipcMain.removeHandler(c.TAB_BACK),o.ipcMain.removeHandler(c.TAB_FORWARD),o.ipcMain.removeHandler(c.TAB_SWITCH),o.ipcMain.removeHandler(c.TAB_CLOSE)}list(){return Array.from(this.views.entries()).map(([e,t])=>this.info(e,t))}create(e,t=!0){const i=Ie.randomUUID(),s=new o.BrowserView({webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,preload:MAIN_WINDOW_VITE_DEV_SERVER_URL?N.join(process.cwd(),"dist-electron/preload/preload.js"):N.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 a=this.info(i,s);return this.win.webContents.send("tab-created",a),a}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,a=488,l=r,g=s+r,u=t-a-r,f=i-s-r*2;e.setBounds({x:l,y:g,width:Math.max(0,u),height:Math.max(0,f)})}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 ce=n=>{if(n){ae.create();return}ae.destroy()},ut=n=>{const e=s=>{h.logUserOperation(`${c.SHOW_CONTEXT_MENU}:${D.CONVERSATION_ITEM}-${s}`),n.webContents.send(`${c.SHOW_CONTEXT_MENU}:${D.CONVERSATION_ITEM}`,s)};z.register(D.CONVERSATION_ITEM,[{id:O.PIN,label:"menu.conversation.pinConversation",click:()=>e(O.PIN)},{id:O.RENAME,label:"menu.conversation.renameConversation",click:()=>e(O.RENAME)},{id:O.DEL,label:"menu.conversation.delConversation",click:()=>e(O.DEL)}]);const t=s=>{h.logUserOperation(`${c.SHOW_CONTEXT_MENU}:${D.CONVERSATION_LIST}-${s}`),n.webContents.send(`${c.SHOW_CONTEXT_MENU}:${D.CONVERSATION_LIST}`,s)};z.register(D.CONVERSATION_LIST,[{id:w.NEW_CONVERSATION,label:"menu.conversation.newConversation",click:()=>t(w.NEW_CONVERSATION)},{type:"separator"},{id:w.SORT_BY,label:"menu.conversation.sortBy",submenu:[{id:w.SORT_BY_CREATE_TIME,label:"menu.conversation.sortByCreateTime",type:"radio",checked:!1,click:()=>t(w.SORT_BY_CREATE_TIME)},{id:w.SORT_BY_UPDATE_TIME,label:"menu.conversation.sortByUpdateTime",type:"radio",checked:!1,click:()=>t(w.SORT_BY_UPDATE_TIME)},{id:w.SORT_BY_NAME,label:"menu.conversation.sortByName",type:"radio",checked:!1,click:()=>t(w.SORT_BY_NAME)},{id:w.SORT_BY_MODEL,label:"menu.conversation.sortByModel",type:"radio",checked:!1,click:()=>t(w.SORT_BY_MODEL)},{type:"separator"},{id:w.SORT_ASCENDING,label:"menu.conversation.sortAscending",type:"radio",checked:!1,click:()=>t(w.SORT_ASCENDING)},{id:w.SORT_DESCENDING,label:"menu.conversation.sortDescending",type:"radio",checked:!1,click:()=>t(w.SORT_DESCENDING)}]},{id:w.BATCH_OPERATIONS,label:"menu.conversation.batchOperations",click:()=>t(w.BATCH_OPERATIONS)}]);const i=s=>{h.logUserOperation(`${c.SHOW_CONTEXT_MENU}:${D.MESSAGE_ITEM}-${s}`),n.webContents.send(`${c.SHOW_CONTEXT_MENU}:${D.MESSAGE_ITEM}`,s)};z.register(D.MESSAGE_ITEM,[{id:b.COPY,label:"menu.message.copyMessage",click:()=>i(b.COPY)},{id:b.SELECT,label:"menu.message.selectMessage",click:()=>i(b.SELECT)},{type:"separator"},{id:b.DELETE,label:"menu.message.deleteMessage",click:()=>i(b.DELETE)}])};function fe(){B.onWindowCreate(E.MAIN,n=>{let e=v.get(_.MINIMIZE_TO_TRAY);v.onConfigChange(i=>{e!==i[_.MINIMIZE_TO_TRAY]&&(e=i[_.MINIMIZE_TO_TRAY],ce(e))}),ce(e),ut(n);const t=new dt(n);t.enable(),n.on("closed",()=>{t.destroy()})}),B.create(E.MAIN,pe),o.ipcMain.on(c.START_A_DIALOGUE,async(n,e)=>{const{providerName:t,messages:i,messageId:s,selectedModel:r}=e,a=B.get(E.MAIN);if(!a)throw new Error("mainWindow not found");try{const g=await Fe(t)?.chat(i,r);if(!g)throw new Error("chunks or stream not found");for await(const u of g){const f={messageId:s,data:u};a.webContents.send(c.START_A_DIALOGUE+"back"+s,f)}}catch(l){const g={messageId:s,data:{isEnd:!0,isError:!0,result:l instanceof Error?l.message:String(l)}};a.webContents.send(c.START_A_DIALOGUE+"back"+s,g)}})}function pt(){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 ht(n){return N.join(o.app.getPath("userData"),"profiles",n)}function gt(n){return new Promise(e=>{const t=Re.createServer();t.once("error",i=>e(!0)),t.once("listening",()=>{t.close(),e(!1)}),t.listen(n)})}async function ft(){try{return new Promise(n=>{const e=Oe.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 _t(){const n=pt(),e=ht("default");if(d.info(`Launching Chrome with user data dir: ${e}`),await gt(9222)){d.info("Chrome already running on port 9222, skip launching.");return}if(await ft()){d.info("Chrome already running, skip launching.");return}return new Promise((i,s)=>{X.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 _e extends be.EventEmitter{async executeScript(e,t){const s=(r,a)=>{const l=r+a;return l.length>32768?l.slice(l.length-32768):l};return await new Promise(r=>{try{const a=t?.roomType??"",l=t?.startTime??"",g=t?.endTime??"",u=t?.operation??"",f=t?.tabIndex??"",m=t?.channels??"",T=t?.startTabIndex??"",p=o.utilityProcess.fork(e,[],{env:{...process.env,ROOM_TYPE:String(a),START_DATE:String(l),END_DATE:String(g),OPERATION:String(u),TAB_INDEX:String(f),CHANNELS:typeof m=="string"?m:JSON.stringify(m),START_TAB_INDEX:String(T)},stdio:"pipe"});let M="",k="";p.stdout&&p.stdout.on("data",S=>{const R=S.toString();M=s(M,R),d.info(`stdout: ${R}`)}),p.stderr&&p.stderr.on("data",S=>{const R=S.toString();k=s(k,R),d.info(`stderr: ${R}`)}),p.on("exit",S=>{d.info(`子进程退出,退出码 ${S}`),r({success:S===0,exitCode:S,stdoutTail:M,stderrTail:k,...S===0?{}:{error:`Script exited with code ${S}`}})})}catch(a){r({success:!1,exitCode:null,stdoutTail:"",stderrTail:"",error:a?.message||"运行 Node 脚本时出错"})}})}}const mt="scripts.meta.json";function L(){return o.app.isPackaged?y.join(__dirname,"scripts"):y.join(process.cwd(),"electron/scripts")}function me(){const n=L();A.existsSync(n)||A.mkdirSync(n,{recursive:!0})}function ie(){return y.join(L(),mt)}function P(){const n=ie();if(!A.existsSync(n))return{scripts:[]};try{const e=A.readFileSync(n,"utf-8"),t=JSON.parse(e);if(t&&Array.isArray(t.scripts))return t}catch(e){d.warn("[script-store-service] Failed to read meta:",e)}return{scripts:[]}}function U(n){me();const e=ie();A.writeFileSync(e,JSON.stringify(n,null,2),"utf-8")}function Tt(n){return n.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/g,"-").replace(/^-+|-+$/g,"")||"script"}function wt(n,e){const t=Tt(n);let i=`${t}.mjs`,s=1;for(;e.has(i);)i=`${t}-${s}.mjs`,s++;return i}function At(){const n=L(),e=ie();if(A.existsSync(e))return;if(!A.existsSync(n)){d.info("[script-store-service] Scripts directory does not exist, skipping seed.");return}const t={scripts:[]},i=A.readdirSync(n).filter(s=>s.endsWith(".mjs"));for(const s of i)try{const r=s.replace(/\.mjs$/,""),a=new Date().toISOString();t.scripts.push({id:`seed-${r}`,name:r,description:"",filename:s,enabled:!0,channel:"",createdAt:a,updatedAt:a})}catch(r){d.warn("[script-store-service] Failed to seed script",s,r)}U(t),d.info("[script-store-service] Seeded scripts:",t.scripts.length)}function yt(){me(),At()}function St(){return P().scripts.map(e=>$(e)).sort((e,t)=>new Date(t.updatedAt).getTime()-new Date(e.updatedAt).getTime())}function j(n){const t=P().scripts.find(i=>i.id===n);return t?$(t):null}function Et(n){const t=P().scripts.find(i=>i.id===n);return t?y.join(L(),t.filename):null}function le(n){const e=P(),t=L(),i=new Set(e.scripts.map(u=>u.filename)),s=new Date().toISOString();if(n.id){const u=e.scripts.findIndex(f=>f.id===n.id);if(u>=0){const f=e.scripts[u],m=y.join(t,f.filename);return A.writeFileSync(m,n.code,"utf-8"),e.scripts[u]={...f,name:n.name,description:n.description,channel:n.channel,enabled:n.enabled,updatedAt:s},U(e),$(e.scripts[u])}}const r=wt(n.name,i),a=y.join(t,r);A.writeFileSync(a,n.code,"utf-8");const g={id:`script-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,name:n.name,description:n.description,filename:r,enabled:n.enabled,channel:n.channel,createdAt:s,updatedAt:s};return e.scripts.push(g),U(e),$(g)}function vt(n){const e=P(),t=e.scripts.findIndex(r=>r.id===n);if(t===-1)return!1;const i=e.scripts[t],s=y.join(L(),i.filename);if(A.existsSync(s))try{A.unlinkSync(s)}catch(r){d.warn("[script-store-service] Failed to delete script file:",r)}return e.scripts.splice(t,1),U(e),!0}function Ct(n,e){const t=P(),i=t.scripts.findIndex(s=>s.id===n);return i===-1?!1:(t.scripts[i].enabled=e,t.scripts[i].updatedAt=new Date().toISOString(),U(t),!0)}function Dt(n,e){const t=P(),i=t.scripts.findIndex(s=>s.id===n);return i===-1?!1:(t.scripts[i].lastRun=e,t.scripts[i].updatedAt=new Date().toISOString(),U(t),!0)}function $(n){const e=L(),t=y.join(e,n.filename);let i="";try{A.existsSync(t)&&(i=A.readFileSync(t,"utf-8"))}catch(s){d.warn("[script-store-service] Failed to read script file:",s)}return{...n,code:i}}const It=new _e;async function Mt(n,e){const t=Et(n);if(!t)return{success:!1,exitCode:null,stdoutTail:"",stderrTail:"",error:"Script not found"};const i=await It.executeScript(t,{SCRIPT_ID:n,CHANNEL:e||""});return Dt(n,{time:new Date().toISOString(),success:i.success,error:i.error}),i}const q=new Map;function Y(){return o.app.isPackaged?y.join(__dirname,"scripts"):y.join(process.cwd(),"electron/scripts")}function Rt(){const n=new _e,e=y.dirname(require.resolve("playwright-core")),t=y.join(e,"cli.js");let i=null;o.ipcMain.handle(c.SCRIPT_LIST,async()=>{try{return St()}catch(s){throw d.error("[SCRIPT_LIST] error:",s),s}}),o.ipcMain.handle(c.SCRIPT_GET,async(s,r)=>{try{return j(r)}catch(a){throw d.error("[SCRIPT_GET] error:",a),a}}),o.ipcMain.handle(c.SCRIPT_SAVE,async(s,r)=>{try{return le(r)}catch(a){throw d.error("[SCRIPT_SAVE] error:",a),a}}),o.ipcMain.handle(c.SCRIPT_DELETE,async(s,r)=>{try{return vt(r)}catch(a){throw d.error("[SCRIPT_DELETE] error:",a),a}}),o.ipcMain.handle(c.SCRIPT_TOGGLE,async(s,r,a)=>{try{return Ct(r,a)}catch(l){throw d.error("[SCRIPT_TOGGLE] error:",l),l}}),o.ipcMain.handle(c.SCRIPT_RUN,async(s,r)=>{try{const a=j(r);return await Mt(r,a?.channel)}catch(a){return d.error("[SCRIPT_RUN] error:",a),{success:!1,exitCode:null,stdoutTail:"",stderrTail:"",error:a?.message||"Run failed"}}}),o.ipcMain.handle(c.SCRIPT_RECORD_START,async(s,r)=>{try{i&&(i.kill("SIGINT"),i=null);const a=r||"about:blank";return i=X.spawn(process.execPath,[t,"codegen","--target","javascript","--viewport-size","1920,1080","--color-scheme","light",a],{env:{...process.env,ELECTRON_RUN_AS_NODE:"1"},stdio:"pipe"}),i.on("error",l=>{d.error("[SCRIPT_RECORD_START] Failed to start codegen process:",l)}),i.stdout?.on("data",l=>{d.info(`[SCRIPT_RECORD_START] stdout: ${l.toString()}`)}),i.stderr?.on("data",l=>{d.error(`[SCRIPT_RECORD_START] stderr: ${l.toString()}`)}),{success:!0}}catch(a){return d.error("[SCRIPT_RECORD_START] error:",a),{success:!1,error:a?.message||"Recording start failed"}}}),o.ipcMain.handle(c.SCRIPT_RECORD_STOP,async()=>{try{return i&&(i.kill("SIGINT"),i=null),{success:!0,code:""}}catch(s){return d.error("[SCRIPT_RECORD_STOP] error:",s),{success:!1,error:s?.message||"Recording stop failed"}}}),o.ipcMain.handle(c.SCRIPT_CODEGEN,async(s,r,a)=>{try{const l=j(r);if(!l)return{success:!1,error:"Script not found"};const g=Y(),u=y.join(g,l.filename),f=a||"about:blank";return d.info(`[SCRIPT_CODEGEN] Starting codegen for script ${r} at ${u} with url ${f}`),await new Promise(m=>{const T=X.spawn(process.execPath,[t,"codegen","--target","javascript","-o",u,f],{env:{...process.env,ELECTRON_RUN_AS_NODE:"1"},stdio:"pipe"});T.on("exit",()=>{try{let p=A.readFileSync(u,"utf-8");p.includes("require('playwright')")&&!p.includes("createRequire")&&(p=`import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); + +${p}`),A.writeFileSync(u,p,"utf-8"),le({id:r,name:l.name,description:l.description,code:p,channel:l.channel,enabled:l.enabled}),m({success:!0,code:p})}catch(p){d.error("[SCRIPT_CODEGEN] Failed to process generated code:",p),m({success:!1,error:p?.message||"Failed to process generated code"})}}),T.on("error",p=>{d.error("[SCRIPT_CODEGEN] Failed to start codegen:",p),m({success:!1,error:p.message})})})}catch(l){return d.error("[SCRIPT_CODEGEN] error:",l),{success:!1,error:l?.message||"Codegen failed"}}}),o.ipcMain.handle(c.OPEN_CHANNEL,async(s,r)=>{try{await _t();const a=Y(),l=y.join(a,"open_all_channel.js");if(q.clear(),Array.isArray(r))for(let u=0;u{try{const a=r.roomList.find(T=>T.id===r.roomType),g=[["fzName","fg_trace.js"],["mtName","mt_trace.js"],["dyHotelName","dy_hotel_trace.js"],["dyHotSpringName","dy_hot_spring_trace.js"]].filter(([T])=>a?.[T]),u=Y(),f=g.map(([T,p])=>{const M=y.join(u,p);if(!A.existsSync(M))throw new Error(`Script not found for channel ${T}: ${M}`);return{channel:T,scriptPath:M}}),m=[];for(let T=0;Tthis.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"checking"})),C.autoUpdater.on("update-available",e=>this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"available",info:e})),C.autoUpdater.on("update-not-available",()=>this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"not-available"})),C.autoUpdater.on("download-progress",e=>this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"downloading",progress:e})),C.autoUpdater.on("update-downloaded",e=>this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"downloaded",info:e})),C.autoUpdater.on("error",e=>this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"error",error:e.message}))}sendToRenderer(e,t){o.BrowserWindow.getAllWindows().forEach(i=>{i.isDestroyed()||i.webContents.send(e,t)})}registerHandlers(){o.ipcMain.handle(c.UPDATE_CHECK,()=>o.app.isPackaged?C.autoUpdater.checkForUpdates():(this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"checking"}),setTimeout(()=>{this.sendToRenderer(c.UPDATE_STATUS_CHANGED,{status:"not-available"})},1500),null)),o.ipcMain.handle(c.UPDATE_DOWNLOAD,()=>o.app.isPackaged?C.autoUpdater.downloadUpdate():null),o.ipcMain.handle(c.UPDATE_INSTALL,()=>o.app.isPackaged?C.autoUpdater.quitAndInstall():null),o.ipcMain.handle(c.UPDATE_VERSION,()=>o.app.getVersion())}}const Ot=se.getInstance();Ot.init();Me&&o.app.quit();o.app.whenReady().then(()=>{fe(),yt(),Rt()});o.app.on("window-all-closed",()=>{process.platform!=="darwin"&&!v.get(_.MINIMIZE_TO_TRAY)&&(d.info("app closing due to all windows being closed"),o.app.quit())});o.app.on("activate",()=>{o.BrowserWindow.getAllWindows().length===0&&fe()}); diff --git a/dist-electron/main/main.jsc b/dist-electron/main/main.jsc index b0b98f4..bd795ec 100644 Binary files a/dist-electron/main/main.jsc and b/dist-electron/main/main.jsc differ diff --git a/dist-electron/preload/preload.js b/dist-electron/preload/preload.js index a41b009..ab7c747 100644 --- a/dist-electron/preload/preload.js +++ b/dist-electron/preload/preload.js @@ -54,6 +54,7 @@ var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => { IPC_EVENTS2["SCRIPT_RUN"] = "script:run"; IPC_EVENTS2["SCRIPT_RECORD_START"] = "script:record-start"; IPC_EVENTS2["SCRIPT_RECORD_STOP"] = "script:record-stop"; + IPC_EVENTS2["SCRIPT_CODEGEN"] = "script:codegen"; IPC_EVENTS2["UPDATE_CHECK"] = "update:check"; IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download"; IPC_EVENTS2["UPDATE_INSTALL"] = "update:install"; @@ -112,7 +113,8 @@ const api = { toggle: (id, enabled) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_TOGGLE, id, enabled), run: (id) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RUN, id), startRecording: (url) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_START, url), - stopRecording: () => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_STOP) + stopRecording: () => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_STOP), + codegen: (id, url) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_CODEGEN, id, url) } }; electron.contextBridge.exposeInMainWorld("api", api); diff --git a/dist/index.html b/dist/index.html index 94a9cd0..5cb195e 100644 --- a/dist/index.html +++ b/dist/index.html @@ -8,8 +8,8 @@ http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn" /> - - + +
diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 46f5f61..d03aa57 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -66,6 +66,7 @@ const api: WindowApi = { run: (id: string) => ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RUN, id), startRecording: (url?: string) => ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_START, url), stopRecording: () => ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_STOP), + codegen: (id: string, url?: string) => ipcRenderer.invoke(IPC_EVENTS.SCRIPT_CODEGEN, id, url), }, } diff --git a/electron/process/runTaskOperationService.ts b/electron/process/runTaskOperationService.ts index de493ef..8cd8a36 100644 --- a/electron/process/runTaskOperationService.ts +++ b/electron/process/runTaskOperationService.ts @@ -11,12 +11,9 @@ import { toggleScript, } from '@electron/service/script-store-service'; import { runScriptById } from '@electron/service/script-execution-service'; -import { - startRecording, - stopRecording, -} from '@electron/service/script-recorder-service'; import fs from 'fs' import path from 'path' +import { spawn } from 'child_process' import log from 'electron-log'; const openedTabIndexByChannelName = new Map() @@ -29,6 +26,9 @@ function getScriptsDir() { export function runTaskOperationService() { const executeScriptServiceInstance = new executeScriptService(); + const playwrightCoreDir = path.dirname(require.resolve('playwright-core')); + const cliPath = path.join(playwrightCoreDir, 'cli.js'); + let recorderProc: ReturnType | null = null; // 脚本管理 IPC ipcMain.handle(IPC_EVENTS.SCRIPT_LIST, async () => { @@ -88,7 +88,35 @@ export function runTaskOperationService() { ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_START, async (_event, url?: string) => { try { - return await startRecording(url); + if (recorderProc) { + recorderProc.kill('SIGINT'); + recorderProc = null; + } + + const targetUrl = url || 'about:blank'; + recorderProc = spawn(process.execPath, [cliPath, 'codegen', '--target', 'javascript', '--channel', 'chrome', '--viewport-size', '1920,1080', '--color-scheme', 'light', targetUrl], { + env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' }, + stdio: 'pipe', + }); + + recorderProc.on('error', (err) => { + log.error('[SCRIPT_RECORD_START] Failed to start codegen process:', err); + }); + + recorderProc.on('exit', (code, signal) => { + log.info(`[SCRIPT_RECORD_START] Process exited code=${code} signal=${signal}`); + recorderProc = null; + }); + + recorderProc.stdout?.on('data', (data: Buffer) => { + log.info(`[SCRIPT_RECORD_START] stdout: ${data.toString()}`); + }); + + recorderProc.stderr?.on('data', (data: Buffer) => { + log.error(`[SCRIPT_RECORD_START] stderr: ${data.toString()}`); + }); + + return { success: true }; } catch (error: any) { log.error('[SCRIPT_RECORD_START] error:', error); return { success: false, error: error?.message || 'Recording start failed' }; @@ -97,13 +125,76 @@ export function runTaskOperationService() { ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_STOP, async () => { try { - return await stopRecording(); + if (recorderProc) { + recorderProc.kill('SIGINT'); + recorderProc = null; + } + return { success: true, code: '' }; } catch (error: any) { log.error('[SCRIPT_RECORD_STOP] error:', error); return { success: false, error: error?.message || 'Recording stop failed' }; } }); + ipcMain.handle(IPC_EVENTS.SCRIPT_CODEGEN, async (_event, id: string, url?: string) => { + try { + const script = getScript(id); + if (!script) { + return { success: false, error: 'Script not found' }; + } + + const scriptsDir = getScriptsDir(); + const scriptPath = path.join(scriptsDir, script.filename); + const targetUrl = url || 'about:blank'; + + log.info(`[SCRIPT_CODEGEN] Starting codegen for script ${id} at ${scriptPath} with url ${targetUrl}`); + + return await new Promise<{ success: boolean; code?: string; error?: string }>((resolve) => { + const proc = spawn(process.execPath, [cliPath, 'codegen', '--target', 'javascript', '--channel', 'chrome', '-o', scriptPath, targetUrl], { + env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' }, + stdio: 'pipe', + }); + + proc.on('exit', () => { + try { + let generatedCode = fs.readFileSync(scriptPath, 'utf-8'); + + // Playwright codegen --target javascript generates CommonJS code. + // Since script files use .mjs extension, we inject createRequire for compatibility. + if (generatedCode.includes("require('playwright')") && !generatedCode.includes('createRequire')) { + generatedCode = `import { createRequire } from 'node:module';\nconst require = createRequire(import.meta.url);\n\n${generatedCode}`; + } + + fs.writeFileSync(scriptPath, generatedCode, 'utf-8'); + + // Update script store so the new code is reflected in metadata reads + saveScript({ + id, + name: script.name, + description: script.description, + code: generatedCode, + channel: script.channel, + enabled: script.enabled, + }); + + resolve({ success: true, code: generatedCode }); + } catch (err: any) { + log.error('[SCRIPT_CODEGEN] Failed to process generated code:', err); + resolve({ success: false, error: err?.message || 'Failed to process generated code' }); + } + }); + + proc.on('error', (err) => { + log.error('[SCRIPT_CODEGEN] Failed to start codegen:', err); + resolve({ success: false, error: err.message }); + }); + }); + } catch (error: any) { + log.error('[SCRIPT_CODEGEN] error:', error); + return { success: false, error: error?.message || 'Codegen failed' }; + } + }); + // 打开渠道 ipcMain.handle(IPC_EVENTS.OPEN_CHANNEL, async (_event, channels: any) => { try { diff --git a/electron/scripts/scripts.meta.json b/electron/scripts/scripts.meta.json index d0d5ea2..aac604c 100644 --- a/electron/scripts/scripts.meta.json +++ b/electron/scripts/scripts.meta.json @@ -28,7 +28,12 @@ "enabled": true, "channel": "fliggy", "createdAt": "2026-04-09T19:35:34.000Z", - "updatedAt": "2026-04-09T19:35:34.000Z" + "updatedAt": "2026-04-12T12:59:12.117Z", + "lastRun": { + "time": "2026-04-12T12:59:12.117Z", + "success": false, + "error": "Script exited with code 1" + } }, { "id": "script-mt-trace", diff --git a/electron/service/script-recorder-service/index.ts b/electron/service/script-recorder-service/index.ts deleted file mode 100644 index ecb32d2..0000000 --- a/electron/service/script-recorder-service/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { chromium } from 'playwright'; -import log from 'electron-log'; -import { launchLocalChrome } from '@electron/utils/chrome/launchLocalChrome'; - -let recorderBrowser: any = null; -let recorderContext: any = null; - -export async function startRecording(url?: string): Promise<{ success: boolean; code?: string; error?: string }> { - try { - await launchLocalChrome(); - - if (recorderBrowser) { - await stopRecording(); - } - - recorderBrowser = await chromium.connectOverCDP('http://127.0.0.1:9222'); - recorderContext = recorderBrowser.contexts()[0] || (await recorderBrowser.newContext()); - const page = await recorderContext.newPage(); - const targetUrl = url || 'about:blank'; - await page.goto(targetUrl, { waitUntil: 'domcontentloaded' }); - - // 唤起 Playwright Inspector,让用户手动录制并生成代码 - await page.pause(); - - return { - success: true, - code: '', - }; - } catch (error: any) { - log.error('[script-recorder-service] Failed to start recording:', error); - return { - success: false, - error: error?.message || 'Failed to start recording', - }; - } -} - -export async function stopRecording(): Promise<{ success: boolean; code?: string; error?: string }> { - try { - if (recorderContext) { - await recorderContext.close().catch(() => {}); - recorderContext = null; - } - if (recorderBrowser) { - await recorderBrowser.close().catch(() => {}); - recorderBrowser = null; - } - return { success: true, code: '' }; - } catch (error: any) { - log.error('[script-recorder-service] Failed to stop recording:', error); - return { - success: false, - error: error?.message || 'Failed to stop recording', - }; - } -} diff --git a/global.d.ts b/global.d.ts index 6ee31dd..c7e23d5 100644 --- a/global.d.ts +++ b/global.d.ts @@ -88,6 +88,10 @@ declare global { params: [] return: Promise<{ success: boolean; code?: string; error?: string }> } + [IPC_EVENTS.SCRIPT_CODEGEN]: { + params: [id: string, url?: string] + return: Promise<{ success: boolean; code?: string; error?: string }> + } } type TabId = string @@ -142,6 +146,7 @@ declare global { run: (id: string) => Promise, startRecording: (url?: string) => Promise<{ success: boolean; code?: string; error?: string }>, stopRecording: () => Promise<{ success: boolean; code?: string; error?: string }>, + codegen: (id: string, url?: string) => Promise<{ success: boolean; code?: string; error?: string }>, }, } diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 7ce1c25..55b1355 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -68,6 +68,7 @@ export enum IPC_EVENTS { SCRIPT_RUN = 'script:run', SCRIPT_RECORD_START = 'script:record-start', SCRIPT_RECORD_STOP = 'script:record-stop', + SCRIPT_CODEGEN = 'script:codegen', // 更新 UPDATE_CHECK = 'update:check', diff --git a/src/lib/script-api.ts b/src/lib/script-api.ts index 06a9fdd..f0bb88a 100644 --- a/src/lib/script-api.ts +++ b/src/lib/script-api.ts @@ -15,4 +15,6 @@ export const scriptApi = { window.api.scriptApi.startRecording(url), stopRecording: (): Promise<{ success: boolean; code?: string; error?: string }> => window.api.scriptApi.stopRecording(), + codegen: (id: string, url?: string): Promise<{ success: boolean; code?: string; error?: string }> => + window.api.scriptApi.codegen(id, url), }; diff --git a/src/pages/scripts/components/ScriptCreateDialog.vue b/src/pages/scripts/components/ScriptCreateDialog.vue index 6fd572e..262fd2c 100644 --- a/src/pages/scripts/components/ScriptCreateDialog.vue +++ b/src/pages/scripts/components/ScriptCreateDialog.vue @@ -71,7 +71,7 @@ :loading="saving" class="!rounded-full !px-6 !h-[42px] !text-[13px] !font-semibold" > - {{ saving ? t('common.saving', 'Saving...') : t('script.dialog.createTitle') }} + {{ saving ? t('common.saving', 'Saving...') : t('script.dialog.createAndRecord', '创建并录制') }} @@ -124,7 +124,6 @@ const form = ref({ name: '', description: '', channel: '', - enabled: true, }); function resetForm() { @@ -132,7 +131,6 @@ function resetForm() { name: '', description: '', channel: '', - enabled: true, }; } @@ -149,7 +147,7 @@ function handleSubmit() { description: form.value.description.trim(), code: defaultScriptTemplate, channel: form.value.channel, - enabled: form.value.enabled, + enabled: true, }; emit('save', payload); visible.value = false; diff --git a/src/pages/scripts/index.vue b/src/pages/scripts/index.vue index ab16080..1f99dc3 100644 --- a/src/pages/scripts/index.vue +++ b/src/pages/scripts/index.vue @@ -193,7 +193,7 @@ function openEditDialog(script: AutomationScript) { } function handleCreateDialogClose() { - editingScript.value = undefined; + // editingScript lifecycle is handled by handleSave / handleEditDialogClose } function handleEditDialogClose() { @@ -207,8 +207,17 @@ async function handleSave(input: ScriptSaveInput) { await store.saveScript(input); ElMessage.success(t('script.toast.updated')); } else { - await store.saveScript(input); + const result = await store.saveScript(input); ElMessage.success(t('script.toast.created')); + ElMessage.info(t('script.toast.codegenStarting', '正在启动 Playwright codegen 录制,请在新窗口中操作,完成后关闭窗口即可自动保存代码')); + const codegenResult = await store.codegen(result.id, input.channel || 'about:blank'); + if (codegenResult.success) { + ElMessage.success(t('script.toast.codegenFinished', '录制完成,代码已保存')); + editingScript.value = { ...result, code: codegenResult.code || '' }; + editDialogVisible.value = true; + } else { + ElMessage.error(codegenResult.error || t('script.toast.codegenFailed', '录制失败')); + } } } catch (err) { const msg = err instanceof Error ? err.message : String(err); diff --git a/src/store/script.ts b/src/store/script.ts index c65698b..3e78701 100644 --- a/src/store/script.ts +++ b/src/store/script.ts @@ -140,6 +140,20 @@ export const useScriptStore = defineStore('script', () => { recordingStatus.value = 'idle'; }; + const codegen = async (id: string, url?: string) => { + try { + const result = await scriptApi.codegen(id, url); + if (!result.success) { + error.value = result.error || 'Codegen failed'; + } + return result; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + error.value = msg; + throw err; + } + }; + return { scripts, loading, @@ -157,5 +171,6 @@ export const useScriptStore = defineStore('script', () => { startRecording, stopRecording, resetRecording, + codegen, }; }); diff --git a/vite.config.ts b/vite.config.ts index 68b1631..8fb3e2f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -72,6 +72,9 @@ export default defineConfig(({ mode, command }) => { rollupOptions: { external: isMainProcessExternal, }, + watch: { + exclude: ['**/electron/scripts/**', '**/scripts.meta.json'], + }, }, resolve: { alias: { @@ -100,6 +103,9 @@ export default defineConfig(({ mode, command }) => { entryFileNames: 'preload.js', }, }, + watch: { + exclude: ['**/electron/scripts/**', '**/scripts.meta.json'], + }, }, resolve: { alias: { @@ -139,6 +145,9 @@ export default defineConfig(({ mode, command }) => { server: { port: 5173, + watch: { + ignored: ['**/electron/scripts/**', '**/scripts.meta.json'], + }, proxy: { '/ingress': { target: 'http://8.138.234.141',