@@ -37,48 +37,54 @@ console.log("main: isDev:", isDev);
3737console . log ( "NODE_ENV:" , global . process . env . NODE_ENV ) ;
3838console . log ( "isPackaged:" , app . isPackaged ) ;
3939
40- // Log unhandled errors
41- process . on ( "uncaughtException" , async ( error ) => {
42- console . log ( "Uncaught Exception:" , error ) ;
40+ // Log unhandled errors for debugging
41+ process . on ( "uncaughtException" , ( error ) => {
42+ console . error ( "Uncaught Exception:" , error ) ;
4343} ) ;
4444
45- process . on ( "unhandledRejection" , async ( error ) => {
46- console . log ( "Unhandled Rejection:" , error ) ;
45+ process . on ( "unhandledRejection" , ( error ) => {
46+ console . error ( "Unhandled Rejection:" , error ) ;
4747} ) ;
4848
49+ // Configure custom app paths if APP_PATH_ROOT is specified
4950( ( ) => {
50- const root =
51- global . process . env . APP_PATH_ROOT ?? import . meta. env . VITE_APP_PATH_ROOT ;
51+ const root = global . process . env . APP_PATH_ROOT ?? import . meta. env . VITE_APP_PATH_ROOT ;
5252
53- if ( root === undefined ) {
54- console . log (
55- "no given APP_PATH_ROOT or VITE_APP_PATH_ROOT. default path is used."
56- ) ;
53+ if ( ! root ) {
54+ console . log ( "No APP_PATH_ROOT or VITE_APP_PATH_ROOT specified, using default paths" ) ;
5755 return ;
5856 }
5957
6058 if ( ! path . isAbsolute ( root ) ) {
61- console . log ( "APP_PATH_ROOT must be absolute path. " ) ;
59+ console . error ( "APP_PATH_ROOT must be an absolute path" ) ;
6260 global . process . exit ( 1 ) ;
6361 }
6462
65- console . log ( `APP_PATH_ROOT: ${ root } ` ) ;
63+ console . log ( `Configuring custom APP_PATH_ROOT: ${ root } ` ) ;
6664
6765 const subdirName = pkg . name ;
6866
69- for ( const [ key , val ] of [
67+ // Set app paths
68+ const pathConfigs : Array < [ Parameters < typeof app . setPath > [ 0 ] , string ] > = [
7069 [ "appData" , "" ] ,
7170 [ "userData" , subdirName ] ,
7271 [ "sessionData" , subdirName ] ,
73- ] as const ) {
72+ ] ;
73+
74+ pathConfigs . forEach ( ( [ key , val ] ) => {
7475 app . setPath ( key , path . join ( root , val ) ) ;
75- }
76+ } ) ;
7677
7778 app . setAppLogsPath ( path . join ( root , subdirName , "Logs" ) ) ;
7879} ) ( ) ;
7980
8081console . log ( "appPath:" , app . getAppPath ( ) ) ;
8182
83+ const pathKeys : Array < Parameters < typeof app . getPath > [ 0 ] > = [
84+ "home" , "appData" , "userData" , "sessionData" , "logs" , "temp"
85+ ] ;
86+ pathKeys . forEach ( ( key ) => console . log ( `${ key } :` , app . getPath ( key ) ) ) ;
87+
8288// Register custom protocol scheme before app ready
8389protocol . registerSchemesAsPrivileged ( [
8490 {
@@ -93,16 +99,6 @@ protocol.registerSchemesAsPrivileged([
9399 }
94100] ) ;
95101
96- const keys : Parameters < typeof app . getPath > [ number ] [ ] = [
97- "home" ,
98- "appData" ,
99- "userData" ,
100- "sessionData" ,
101- "logs" ,
102- "temp" ,
103- ] ;
104- keys . forEach ( ( key ) => console . log ( `${ key } :` , app . getPath ( key ) ) ) ;
105-
106102// Initialize server manager
107103const serverManager = new ServerManager ( ) ;
108104
@@ -123,80 +119,17 @@ let ekoService: EkoService;
123119let mainWindowManager : MainWindowManager ;
124120
125121/**
126- * Initialize main window and all related components
127- * Including: detailView, ekoService, windowContext registration
122+ * Setup main window close event handler
123+ * Handles task termination and window hiding/closing based on platform
128124 */
129- async function initializeMainWindow ( ) : Promise < BrowserWindow > {
130- console . log ( '[Main] Starting main window initialization...' ) ;
131-
132- // Create main window (includes transition page and service waiting logic)
133- mainWindow = await mainWindowManager . createMainWindow ( ) ;
134-
135- mainWindow . contentView . setBounds ( {
136- x : 0 ,
137- y : 0 ,
138- width : mainWindow . getBounds ( ) . width ,
139- height : mainWindow . getBounds ( ) . height ,
140- } ) ;
141-
142- // Create detail panel area
143- detailView = createView ( `https://www.google.com` , "view" , '1' ) ;
144- mainWindow . contentView . addChildView ( detailView ) ;
145- detailView . setBounds ( {
146- x : 818 ,
147- y : 264 ,
148- width : 748 ,
149- height : 560 ,
150- } ) ;
151-
152- // Set detail view hidden by default
153- detailView . setVisible ( false ) ;
154-
155- detailView . webContents . setWindowOpenHandler ( ( { url} ) => {
156- detailView . webContents . loadURL ( url ) ;
157- return {
158- action : "deny" ,
159- }
160- } )
161-
162- // Listen for detail view URL changes
163- detailView . webContents . on ( 'did-navigate' , ( _event , url ) => {
164- console . log ( 'detail view did-navigate:' , url ) ;
165- mainWindow ?. webContents . send ( 'url-changed' , url ) ;
166- } ) ;
167-
168- detailView . webContents . on ( 'did-navigate-in-page' , ( _event , url ) => {
169- console . log ( 'detail view did-navigate-in-page:' , url ) ;
170- mainWindow ?. webContents . send ( 'url-changed' , url ) ;
171- } ) ;
172-
173- // Initialize EkoService
174- ekoService = new EkoService ( mainWindow , detailView ) ;
175-
176- // Register main window to windowContextManager
177- const mainWindowContext : WindowContext = {
178- window : mainWindow ,
179- detailView,
180- historyView,
181- ekoService,
182- webContentsId : mainWindow . webContents . id ,
183- windowType : 'main'
184- } ;
185- windowContextManager . registerWindow ( mainWindowContext ) ;
186- console . log ( '[Main] Main window registered to WindowContextManager' ) ;
187-
188- // Listen for window close event (close: triggered before closing, can be prevented)
189- // Unified handling for Mac and Windows: check task status, prompt user
190- mainWindow . on ( 'close' , async ( event ) => {
191- // Check if any task is running
192- const hasRunningTask = ekoService . hasRunningTask ( ) ;
125+ function setupMainWindowCloseHandler ( window : BrowserWindow , service : EkoService ) : void {
126+ window . on ( 'close' , async ( event ) => {
127+ const hasRunningTask = service . hasRunningTask ( ) ;
193128
194129 if ( hasRunningTask ) {
195- // Prevent default close behavior
196130 event . preventDefault ( ) ;
197131
198- // Show confirmation dialog
199- const { response } = await dialog . showMessageBox ( mainWindow , {
132+ const { response } = await dialog . showMessageBox ( window , {
200133 type : 'warning' ,
201134 title : 'Task Running' ,
202135 message : 'A task is currently running. Closing the window will cause the task to fail' ,
@@ -209,108 +142,108 @@ async function initializeMainWindow(): Promise<BrowserWindow> {
209142 } ) ;
210143
211144 if ( response === 1 ) {
212- // Stop task
213- console . log ( '[Main] User chose to stop task' ) ;
214-
215- // Get all task IDs
216- const allTaskIds = ekoService [ 'eko' ] ?. getAllTaskId ( ) || [ ] ;
145+ const allTaskIds = service [ 'eko' ] ?. getAllTaskId ( ) || [ ] ;
146+ await service . abortAllTasks ( ) ;
217147
218- // Abort all tasks
219- await ekoService . abortAllTasks ( ) ;
220-
221- // Send abort event (frontend will listen and update IndexedDB)
222148 allTaskIds . forEach ( taskId => {
223- mainWindow . webContents . send ( 'task-aborted-by-system' , {
149+ window . webContents . send ( 'task-aborted-by-system' , {
224150 taskId,
225151 reason : 'User closed window, task terminated' ,
226152 timestamp : new Date ( ) . toISOString ( )
227153 } ) ;
228154 } ) ;
229155
230- // Delay to ensure message delivery and processing
231156 await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
232157
233- if ( process . platform === 'darwin' ) {
234- // Mac: actually close window
235- mainWindow . destroy ( ) ;
236- } else {
237- // Windows/Linux: hide window
238- mainWindow . hide ( ) ;
239- }
240- }
241- // response === 0: cancel close, do nothing
242- } else {
243- // No task running
244- if ( process . platform !== 'darwin' ) {
245- // Windows/Linux: hide to tray
246- event . preventDefault ( ) ;
247- mainWindow . hide ( ) ;
248- console . log ( '[Main] Main window hidden to tray' ) ;
158+ process . platform === 'darwin' ? window . destroy ( ) : window . hide ( ) ;
249159 }
250- // Mac: use default behavior (close window but keep app running)
160+ } else if ( process . platform !== 'darwin' ) {
161+ event . preventDefault ( ) ;
162+ window . hide ( ) ;
251163 }
252164 } ) ;
165+ }
166+
167+ /**
168+ * Initialize main window and all related components
169+ * Including: detailView, ekoService, windowContext registration
170+ */
171+ async function initializeMainWindow ( ) : Promise < BrowserWindow > {
172+ mainWindow = await mainWindowManager . createMainWindow ( ) ;
173+
174+ const windowBounds = mainWindow . getBounds ( ) ;
175+ mainWindow . contentView . setBounds ( {
176+ x : 0 ,
177+ y : 0 ,
178+ width : windowBounds . width ,
179+ height : windowBounds . height ,
180+ } ) ;
181+
182+ detailView = createView ( `https://www.google.com` , "view" , '1' ) ;
183+ mainWindow . contentView . addChildView ( detailView ) ;
184+ detailView . setBounds ( { x : 818 , y : 264 , width : 748 , height : 560 } ) ;
185+ detailView . setVisible ( false ) ;
186+
187+ detailView . webContents . setWindowOpenHandler ( ( { url } ) => {
188+ detailView . webContents . loadURL ( url ) ;
189+ return { action : "deny" } ;
190+ } ) ;
191+
192+ const handleUrlChange = ( _event : any , url : string ) => {
193+ mainWindow ?. webContents . send ( 'url-changed' , url ) ;
194+ } ;
195+
196+ detailView . webContents . on ( 'did-navigate' , handleUrlChange ) ;
197+ detailView . webContents . on ( 'did-navigate-in-page' , handleUrlChange ) ;
198+
199+ ekoService = new EkoService ( mainWindow , detailView ) ;
200+
201+ windowContextManager . registerWindow ( {
202+ window : mainWindow ,
203+ detailView,
204+ historyView,
205+ ekoService,
206+ webContentsId : mainWindow . webContents . id ,
207+ windowType : 'main'
208+ } ) ;
209+
210+ setupMainWindowCloseHandler ( mainWindow , ekoService ) ;
253211
254- // Listen for window closed event (closed: triggered after window is closed)
255- // Clean up context
256212 mainWindow . on ( 'closed' , ( ) => {
257- console . log ( '[Main] Main window closed, cleaning up context' ) ;
258213 try {
259214 if ( mainWindow && ! mainWindow . isDestroyed ( ) && mainWindow . webContents ) {
260215 windowContextManager . unregisterWindow ( mainWindow . webContents . id ) ;
261216 }
262217 } catch ( error ) {
263- console . error ( '[Main] Failed to clean up main window context:' , error ) ;
218+ console . error ( '[Main] Failed to clean up window context:' , error ) ;
264219 }
265220 } ) ;
266221
267- console . log ( '[Main] Main window initialization completed' ) ;
268222 return mainWindow ;
269223}
270224
271225( async ( ) => {
272226 await app . whenReady ( ) ;
273- console . log ( "App is ready" ) ;
274227
275- // Register global client protocol
276228 registerClientProtocol ( protocol ) ;
277229
278230 if ( isDev ) {
279- const iconPath = path . join ( cwd ( ) , "assets/icons/logo.png" ) ;
280- console . log ( "Setting app icon:" , iconPath ) ;
281- app . dock ?. setIcon ( iconPath ) ;
231+ app . dock ?. setIcon ( path . join ( cwd ( ) , "assets/icons/logo.png" ) ) ;
282232 }
283233
284- // Load any existing cookies from ElectronStore, set as cookie
285234 await initCookies ( ) ;
286235
287- // Initialize main window manager
288236 mainWindowManager = new MainWindowManager ( serverManager ) ;
289-
290- // Initialize main window and all related components
291237 mainWindow = await initializeMainWindow ( ) ;
292238
293- // Create system tray
294239 createTray ( mainWindow ) ;
295- console . log ( '[Main] System tray created' ) ;
296-
297- // Start task scheduler
298240 taskScheduler . start ( ) ;
299- console . log ( '[Main] TaskScheduler started' ) ;
300241
301- // macOS activate event handler
302242 app . on ( "activate" , async ( ) => {
303- // Check if main window exists (regardless of task windows)
304- const hasMainWindow = mainWindow && ! mainWindow . isDestroyed ( ) ;
305-
306- if ( ! hasMainWindow ) {
307- // Create main window if it doesn't exist (even if task windows exist)
308- console . log ( '[Main] App activated, main window does not exist, creating main window' ) ;
243+ if ( ! mainWindow || mainWindow . isDestroyed ( ) ) {
309244 mainWindow = await initializeMainWindow ( ) ;
310245 setupMenu ( mainWindow ) ;
311246 } else {
312- // Main window exists, show and focus
313- console . log ( '[Main] App activated, main window exists, showing and focusing' ) ;
314247 mainWindow . show ( ) ;
315248 mainWindow . focus ( ) ;
316249 }
@@ -319,16 +252,9 @@ async function initializeMainWindow(): Promise<BrowserWindow> {
319252 return mainWindow ;
320253} ) ( ) . then ( ( win ) => setupMenu ( win ) ) ;
321254
322- // Don't quit app when all windows are closed, keep running in background (for scheduled tasks)
323- // User needs to use "Quit" option in tray menu to actually quit the app
324255app . on ( "window-all-closed" , ( ) => {
325- console . log ( '[Main] All windows closed, app continues running in background' ) ;
326- // Don't call app.quit(), let app continue running
327- // Scheduled tasks will continue executing in background
256+ // Keep app running in background for scheduled tasks
328257} ) ;
329258
330- // Register all IPC handlers
331259registerAllIpcHandlers ( ) ;
332-
333260reloadOnChange ( ) ;
334- // setupAutoUpdater();
0 commit comments