diff --git a/backend/app/controller/electron_browser.cjs b/backend/app/controller/electron_browser.cjs
new file mode 100644
index 00000000..5b4fc698
--- /dev/null
+++ b/backend/app/controller/electron_browser.cjs
@@ -0,0 +1,393 @@
+const { app, BrowserWindow, ipcMain } = require('electron');
+const path = require('path');
+
+// Parse command line arguments
+const args = process.argv.slice(2);
+const userDataDir = args[0];
+const cdpPort = args[1];
+const startUrl = args[2] || 'https://www.google.com';
+
+// This must be called before app.ready
+app.commandLine.appendSwitch('remote-debugging-port', cdpPort);
+
+console.log('[ELECTRON BROWSER] Starting with:');
+console.log(' Chrome version:', process.versions.chrome);
+console.log(' User data dir (requested):', userDataDir);
+console.log(' CDP port:', cdpPort);
+console.log(' Start URL:', startUrl);
+
+// Set app paths - must be done before app.ready
+// Do NOT use commandLine.appendSwitch('user-data-dir') as it conflicts with setPath
+app.setPath('userData', userDataDir);
+app.setPath('sessionData', userDataDir);
+
+app.whenReady().then(async () => {
+ const { session } = require('electron');
+ const fs = require('fs');
+ const path = require('path');
+
+ // Log actual paths being used
+ console.log('[ELECTRON BROWSER] Actual paths:');
+ console.log(' app.getPath("userData"):', app.getPath('userData'));
+ console.log(' app.getPath("sessionData"):', app.getPath('sessionData'));
+ console.log(' app.getPath("cache"):', app.getPath('cache'));
+ console.log(' app.getPath("temp"):', app.getPath('temp'));
+ console.log(' process.argv:', process.argv);
+
+ // Check command line switches
+ console.log('[ELECTRON BROWSER] Command line switches:');
+ console.log(' user-data-dir:', app.commandLine.getSwitchValue('user-data-dir'));
+ console.log(' remote-debugging-port:', app.commandLine.getSwitchValue('remote-debugging-port'));
+
+ // Log partition session info
+ const userLoginSession = session.fromPartition('persist:user_login');
+ console.log('[ELECTRON BROWSER] Session info:');
+ console.log(' Partition: persist:user_login');
+ console.log(' Session storage path:', userLoginSession.getStoragePath());
+
+ // Check if Cookies file exists
+ const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies');
+ console.log('[ELECTRON BROWSER] Cookies path:', cookiesPath);
+ console.log('[ELECTRON BROWSER] Cookies exists:', fs.existsSync(cookiesPath));
+ if (fs.existsSync(cookiesPath)) {
+ const stats = fs.statSync(cookiesPath);
+ console.log('[ELECTRON BROWSER] Cookies file size:', stats.size, 'bytes');
+ }
+ const win = new BrowserWindow({
+ width: 1400,
+ height: 900,
+ title: 'Eigent Browser - Login',
+ webPreferences: {
+ nodeIntegration: true,
+ contextIsolation: false,
+ webviewTag: true
+ }
+ });
+
+ // Create navigation bar and webview HTML
+ const html = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Browser Info
+
+
+
+
+
+
+`;
+
+ win.loadURL('data:text/html;charset=UTF-8,' + encodeURIComponent(html));
+
+ // Show window when ready
+ win.once('ready-to-show', () => {
+ win.show();
+
+ // Log cookies periodically to track changes
+ setInterval(async () => {
+ try {
+ const cookies = await userLoginSession.cookies.get({});
+ console.log('[ELECTRON BROWSER] Current cookies count:', cookies.length);
+ if (cookies.length > 0) {
+ console.log('[ELECTRON BROWSER] Cookie domains:', [...new Set(cookies.map(c => c.domain))]);
+ }
+ } catch (error) {
+ console.error('[ELECTRON BROWSER] Failed to get cookies:', error);
+ }
+ }, 5000); // Check every 5 seconds
+ });
+
+ win.on('closed', async () => {
+ console.log('[ELECTRON BROWSER] Window closed, preparing to quit...');
+
+ // Flush storage data before quitting to ensure cookies are saved
+ try {
+ const { session } = require('electron');
+ const fs = require('fs');
+ const path = require('path');
+ const userLoginSession = session.fromPartition('persist:user_login');
+
+ // Log cookies before flush
+ const cookiesBeforeFlush = await userLoginSession.cookies.get({});
+ console.log('[ELECTRON BROWSER] Cookies count before flush:', cookiesBeforeFlush.length);
+
+ // Flush storage
+ console.log('[ELECTRON BROWSER] Flushing storage data...');
+ await userLoginSession.flushStorageData();
+ console.log('[ELECTRON BROWSER] Storage data flushed successfully');
+
+ // Check cookies file after flush
+ const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies');
+ if (fs.existsSync(cookiesPath)) {
+ const stats = fs.statSync(cookiesPath);
+ console.log('[ELECTRON BROWSER] Cookies file size after flush:', stats.size, 'bytes');
+ } else {
+ console.log('[ELECTRON BROWSER] WARNING: Cookies file does not exist after flush!');
+ }
+ } catch (error) {
+ console.error('[ELECTRON BROWSER] Failed to flush storage data:', error);
+ }
+ app.quit();
+ });
+});
+
+let isQuitting = false;
+
+app.on('before-quit', async (event) => {
+ if (isQuitting) return;
+
+ // Prevent immediate quit to allow storage flush and cookie sync
+ event.preventDefault();
+ isQuitting = true;
+
+ console.log('[ELECTRON BROWSER] before-quit event triggered');
+
+ try {
+ const { session } = require('electron');
+ const fs = require('fs');
+ const path = require('path');
+ const userLoginSession = session.fromPartition('persist:user_login');
+
+ // Log cookies before flush
+ const cookiesBeforeQuit = await userLoginSession.cookies.get({});
+ console.log('[ELECTRON BROWSER] Cookies count before quit:', cookiesBeforeQuit.length);
+ if (cookiesBeforeQuit.length > 0) {
+ console.log('[ELECTRON BROWSER] Cookie domains before quit:', [...new Set(cookiesBeforeQuit.map(c => c.domain))]);
+ }
+
+ // Flush storage
+ console.log('[ELECTRON BROWSER] Flushing storage on quit...');
+ await userLoginSession.flushStorageData();
+ console.log('[ELECTRON BROWSER] Storage data flushed on quit');
+ } catch (error) {
+ console.error('[ELECTRON BROWSER] Failed to sync cookies:', error);
+ } finally {
+ console.log('[ELECTRON BROWSER] Exiting now...');
+ // Force quit after sync
+ app.exit(0);
+ }
+});
+
+app.on('window-all-closed', () => {
+ if (!isQuitting) {
+ app.quit();
+ }
+});
diff --git a/backend/app/controller/tool_controller.py b/backend/app/controller/tool_controller.py
index 29320da5..b9cb7ffd 100644
--- a/backend/app/controller/tool_controller.py
+++ b/backend/app/controller/tool_controller.py
@@ -347,410 +347,13 @@ async def open_browser_login():
"note": "Your login data will be saved in the profile."
}
- # Create Electron browser script with .cjs extension for CommonJS
+ # Use static Electron browser script
electron_script_path = os.path.join(os.path.dirname(__file__), "electron_browser.cjs")
- electron_script_content = '''
-const { app, BrowserWindow, ipcMain } = require('electron');
-const path = require('path');
-// Parse command line arguments
-const args = process.argv.slice(2);
-const userDataDir = args[0];
-const cdpPort = args[1];
-const startUrl = args[2] || 'https://www.google.com';
+ # Verify script exists
+ if not os.path.exists(electron_script_path):
+ raise FileNotFoundError(f"Electron browser script not found: {electron_script_path}")
-// This must be called before app.ready
-app.commandLine.appendSwitch('remote-debugging-port', cdpPort);
-
-console.log('[ELECTRON BROWSER] Starting with:');
-console.log(' Chrome version:', process.versions.chrome);
-console.log(' User data dir (requested):', userDataDir);
-console.log(' CDP port:', cdpPort);
-console.log(' Start URL:', startUrl);
-
-// Set app paths - must be done before app.ready
-// Do NOT use commandLine.appendSwitch('user-data-dir') as it conflicts with setPath
-app.setPath('userData', userDataDir);
-app.setPath('sessionData', userDataDir);
-
-app.whenReady().then(async () => {
- const { session } = require('electron');
- const fs = require('fs');
- const path = require('path');
-
- // Log actual paths being used
- console.log('[ELECTRON BROWSER] Actual paths:');
- console.log(' app.getPath("userData"):', app.getPath('userData'));
- console.log(' app.getPath("sessionData"):', app.getPath('sessionData'));
- console.log(' app.getPath("cache"):', app.getPath('cache'));
- console.log(' app.getPath("temp"):', app.getPath('temp'));
- console.log(' process.argv:', process.argv);
-
- // Check command line switches
- console.log('[ELECTRON BROWSER] Command line switches:');
- console.log(' user-data-dir:', app.commandLine.getSwitchValue('user-data-dir'));
- console.log(' remote-debugging-port:', app.commandLine.getSwitchValue('remote-debugging-port'));
-
- // Log partition session info
- const userLoginSession = session.fromPartition('persist:user_login');
- console.log('[ELECTRON BROWSER] Session info:');
- console.log(' Partition: persist:user_login');
- console.log(' Session storage path:', userLoginSession.getStoragePath());
-
- // Check if Cookies file exists
- const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies');
- console.log('[ELECTRON BROWSER] Cookies path:', cookiesPath);
- console.log('[ELECTRON BROWSER] Cookies exists:', fs.existsSync(cookiesPath));
- if (fs.existsSync(cookiesPath)) {
- const stats = fs.statSync(cookiesPath);
- console.log('[ELECTRON BROWSER] Cookies file size:', stats.size, 'bytes');
- }
- const win = new BrowserWindow({
- width: 1400,
- height: 900,
- title: 'Eigent Browser - Login',
- webPreferences: {
- nodeIntegration: true,
- contextIsolation: false,
- webviewTag: true
- }
- });
-
- // Create navigation bar and webview
- const html = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Browser Info
-
-
-
-
-
-
-`;
-
- win.loadURL('data:text/html;charset=UTF-8,' + encodeURIComponent(html));
-
- // Show window when ready
- win.once('ready-to-show', () => {
- win.show();
-
- // Log cookies periodically to track changes
- setInterval(async () => {
- try {
- const cookies = await userLoginSession.cookies.get({});
- console.log('[ELECTRON BROWSER] Current cookies count:', cookies.length);
- if (cookies.length > 0) {
- console.log('[ELECTRON BROWSER] Cookie domains:', [...new Set(cookies.map(c => c.domain))]);
- }
- } catch (error) {
- console.error('[ELECTRON BROWSER] Failed to get cookies:', error);
- }
- }, 5000); // Check every 5 seconds
- });
-
- win.on('closed', async () => {
- console.log('[ELECTRON BROWSER] Window closed, preparing to quit...');
-
- // Flush storage data before quitting to ensure cookies are saved
- try {
- const { session } = require('electron');
- const fs = require('fs');
- const path = require('path');
- const userLoginSession = session.fromPartition('persist:user_login');
-
- // Log cookies before flush
- const cookiesBeforeFlush = await userLoginSession.cookies.get({});
- console.log('[ELECTRON BROWSER] Cookies count before flush:', cookiesBeforeFlush.length);
-
- // Flush storage
- console.log('[ELECTRON BROWSER] Flushing storage data...');
- await userLoginSession.flushStorageData();
- console.log('[ELECTRON BROWSER] Storage data flushed successfully');
-
- // Check cookies file after flush
- const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies');
- if (fs.existsSync(cookiesPath)) {
- const stats = fs.statSync(cookiesPath);
- console.log('[ELECTRON BROWSER] Cookies file size after flush:', stats.size, 'bytes');
- } else {
- console.log('[ELECTRON BROWSER] WARNING: Cookies file does not exist after flush!');
- }
- } catch (error) {
- console.error('[ELECTRON BROWSER] Failed to flush storage data:', error);
- }
- app.quit();
- });
-});
-
-let isQuitting = false;
-
-app.on('before-quit', async (event) => {
- if (isQuitting) return;
-
- // Prevent immediate quit to allow storage flush and cookie sync
- event.preventDefault();
- isQuitting = true;
-
- console.log('[ELECTRON BROWSER] before-quit event triggered');
-
- try {
- const { session } = require('electron');
- const fs = require('fs');
- const path = require('path');
- const userLoginSession = session.fromPartition('persist:user_login');
-
- // Log cookies before flush
- const cookiesBeforeQuit = await userLoginSession.cookies.get({});
- console.log('[ELECTRON BROWSER] Cookies count before quit:', cookiesBeforeQuit.length);
- if (cookiesBeforeQuit.length > 0) {
- console.log('[ELECTRON BROWSER] Cookie domains before quit:', [...new Set(cookiesBeforeQuit.map(c => c.domain))]);
- }
-
- // Flush storage
- console.log('[ELECTRON BROWSER] Flushing storage on quit...');
- await userLoginSession.flushStorageData();
- console.log('[ELECTRON BROWSER] Storage data flushed on quit');
- } catch (error) {
- console.error('[ELECTRON BROWSER] Failed to sync cookies:', error);
- } finally {
- console.log('[ELECTRON BROWSER] Exiting now...');
- // Force quit after sync
- app.exit(0);
- }
-});
-
-app.on('window-all-closed', () => {
- if (!isQuitting) {
- app.quit();
- }
-});
-'''
-
- # Write the Electron script
- with open(electron_script_path, 'w') as f:
- f.write(electron_script_content)
-
- # Find Electron executable
- # Try to use the same Electron version as the main app
electron_cmd = "npx"
electron_args = [
electron_cmd,
@@ -775,7 +378,9 @@ app.on('window-all-closed', () => {
cwd=app_dir,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Redirect stderr to stdout
- universal_newlines=True,
+ text=True,
+ encoding='utf-8',
+ errors='replace', # Replace undecodable chars instead of crashing
bufsize=1 # Line buffered
)
@@ -791,17 +396,7 @@ app.on('window-all-closed', () => {
# Wait a bit for Electron to start
import asyncio
await asyncio.sleep(3)
-
- # Clean up the script file after a delay
- async def cleanup_script():
- await asyncio.sleep(10)
- try:
- os.remove(electron_script_path)
- except:
- pass
-
- asyncio.create_task(cleanup_script())
-
+
logger.info(f"[PROFILE USER LOGIN] Electron browser launched with PID {process.pid}")
return {
diff --git a/backend/app/utils/toolkit/terminal_toolkit.py b/backend/app/utils/toolkit/terminal_toolkit.py
index 9109dcab..659decd5 100644
--- a/backend/app/utils/toolkit/terminal_toolkit.py
+++ b/backend/app/utils/toolkit/terminal_toolkit.py
@@ -169,7 +169,7 @@ class TerminalToolkit(BaseTerminalToolkit, AbstractToolkit):
source_cfg = os.path.join(source_venv, "pyvenv.cfg")
python_home = None
- with open(source_cfg, 'r') as f:
+ with open(source_cfg, 'r', encoding='utf-8') as f:
for line in f:
if line.startswith('home = '):
python_home = line.split('=', 1)[1].strip()