// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= import { useHost } from '@/host'; import { queryClient } from '@/lib/queryClient'; import AppRoutes from '@/routers/index'; import { stackClientApp } from '@/stack/client'; import { StackProvider, StackTheme } from '@stackframe/react'; import { QueryClientProvider } from '@tanstack/react-query'; import React, { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { AppCommandProvider } from './components/Layout/AppCommandProvider'; import { WindowCloseProvider } from './components/Layout/WindowCloseProvider'; import { Toaster } from './components/ui/sonner'; import { useBackgroundTaskProcessor } from './hooks/useBackgroundTaskProcessor'; import { useIsBackgroundWorkOwner } from './hooks/useBackgroundWorkOwner'; import { useExecutionSubscription } from './hooks/useExecutionSubscription'; import { useRemoteControlBridge } from './hooks/useRemoteControlBridge'; import { useTriggerTaskExecutor } from './hooks/useTriggerTaskExecutor'; import { hasStackKeys } from './lib'; import { useAuthStore } from './store/authStore'; import { useInstallationStore } from './store/installationStore'; import { useUsageNotices } from '@/hooks/useUsageNotices'; const HAS_STACK_KEYS = hasStackKeys(); /** Work the app starts on its own; only one window runs it. */ function BackgroundWork({ token, isBackendReady, }: { token: string | null; isBackendReady: boolean; }) { // Subscribe to execution events when user is authenticated // Note: Removed triggers.length check to prevent reconnection on every trigger update const shouldSubscribe = !!token; useExecutionSubscription(shouldSubscribe); useBackgroundTaskProcessor(); // Execute triggered tasks automatically when WebSocket events are received useTriggerTaskExecutor(); // The bridge can receive commands immediately after registration. Do not // advertise it until the local Brain can durably persist the command inbox. useRemoteControlBridge(token, isBackendReady); return null; } function App() { useUsageNotices(); const host = useHost(); const navigate = useNavigate(); const { setInitState } = useAuthStore(); const { token } = useAuthStore(); const isBackendReady = useInstallationStore((state) => state.isBackendReady); const isBackgroundWorkOwner = useIsBackgroundWorkOwner(); useEffect(() => { const handleShareCode = (event: any, share_token: string) => { navigate({ pathname: '/', search: `?share_token=${encodeURIComponent(share_token)}`, }); }; // listen version update notification const handleUpdateNotification = (data: { type: string; currentVersion: string; previousVersion: string; reason: string; }) => { console.log('receive version update notification:', data); if (data.type === 'version-update') { // handle version update logic console.log( `version from ${data.previousVersion} to ${data.currentVersion}` ); console.log(`update reason: ${data.reason}`); setInitState('carousel'); } }; host?.ipcRenderer?.on('auth-share-token-received', handleShareCode); host?.electronAPI?.onUpdateNotification(handleUpdateNotification); return () => { host?.ipcRenderer?.off('auth-share-token-received', handleShareCode); host?.electronAPI?.removeAllListeners('update-notification'); }; }, [host, navigate, setInitState]); // render wrapper const renderWrapper = (children: React.ReactNode) => { const content = ( {children} ); if (HAS_STACK_KEYS) { return ( {content} ); } return ( <> {content} ); }; return renderWrapper( {isBackgroundWorkOwner ? ( ) : null} ); } export default App;