@dynamicu/chromedebug-mcp 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ import { SessionManager } from './services/session-manager.js';
7
7
  import { BrowserDaemon } from './services/browser-daemon.js';
8
8
  import { FailoverManager } from './services/failover-manager.js';
9
9
  import { getExtensionPath } from './utils/extension-path.js';
10
+ import logger from './utils/logger.js';
10
11
 
11
12
  export class ChromeController {
12
13
  constructor() {
@@ -104,10 +105,10 @@ export class ChromeController {
104
105
  this.setActiveTab(targetId);
105
106
  }
106
107
 
107
- console.log(`[TabRegistry] Registered tab ${targetId} for session ${this.sessionId}`);
108
+ logger.debug(`[TabRegistry] Registered tab ${targetId} for session ${this.sessionId}`);
108
109
  return tabData;
109
110
  } catch (error) {
110
- console.error(`[TabRegistry] Failed to register tab:`, error);
111
+ logger.error(`[TabRegistry] Failed to register tab:`, error);
111
112
  return null;
112
113
  }
113
114
  }
@@ -120,7 +121,7 @@ export class ChromeController {
120
121
  if (tabData) {
121
122
  this.activeTargetId = targetId;
122
123
  this.page = tabData.page; // Maintain backward compatibility
123
- console.log(`[TabRegistry] Active tab set to ${targetId}`);
124
+ logger.debug(`[TabRegistry] Active tab set to ${targetId}`);
124
125
  return true;
125
126
  }
126
127
  return false;
@@ -158,7 +159,7 @@ export class ChromeController {
158
159
  const removed = this.tabRegistry.delete(targetId);
159
160
 
160
161
  if (removed) {
161
- console.log(`[TabRegistry] Unregistered tab ${targetId}`);
162
+ logger.debug(`[TabRegistry] Unregistered tab ${targetId}`);
162
163
 
163
164
  // If this was the active tab, select a new active tab
164
165
  if (wasActive) {
@@ -182,7 +183,7 @@ export class ChromeController {
182
183
  this.tabRegistry.clear();
183
184
  this.activeTargetId = null;
184
185
  this.page = null;
185
- console.log(`[TabRegistry] Cleared all tabs for session ${this.sessionId}`);
186
+ logger.debug(`[TabRegistry] Cleared all tabs for session ${this.sessionId}`);
186
187
  }
187
188
 
188
189
  /**
@@ -208,7 +209,7 @@ export class ChromeController {
208
209
  // Only handle page targets (tabs)
209
210
  if (targetInfo.type === 'page') {
210
211
  try {
211
- console.log(`[TargetEvents] New tab created: ${targetInfo.targetId}`);
212
+ logger.debug(`[TargetEvents] New tab created: ${targetInfo.targetId}`);
212
213
 
213
214
  // Wait a bit for the page to be ready
214
215
  setTimeout(async () => {
@@ -224,11 +225,11 @@ export class ChromeController {
224
225
  await this.registerTab(newPage, targetInfo.targetId);
225
226
  }
226
227
  } catch (error) {
227
- console.error(`[TargetEvents] Error registering new tab:`, error);
228
+ logger.error(`[TargetEvents] Error registering new tab:`, error);
228
229
  }
229
230
  }, 100);
230
231
  } catch (error) {
231
- console.error(`[TargetEvents] Error handling target creation:`, error);
232
+ logger.error(`[TargetEvents] Error handling target creation:`, error);
232
233
  }
233
234
  }
234
235
  });
@@ -236,7 +237,7 @@ export class ChromeController {
236
237
  // Listen for tab destruction
237
238
  browserClient.on('Target.targetDestroyed', (params) => {
238
239
  const { targetId } = params;
239
- console.log(`[TargetEvents] Tab destroyed: ${targetId}`);
240
+ logger.debug(`[TargetEvents] Tab destroyed: ${targetId}`);
240
241
  this.unregisterTab(targetId);
241
242
  });
242
243
 
@@ -249,15 +250,15 @@ export class ChromeController {
249
250
  if (tabData) {
250
251
  tabData.url = targetInfo.url;
251
252
  tabData.title = targetInfo.title || 'Untitled';
252
- console.log(`[TargetEvents] Tab info updated: ${targetInfo.targetId} - ${targetInfo.title}`);
253
+ logger.debug(`[TargetEvents] Tab info updated: ${targetInfo.targetId} - ${targetInfo.title}`);
253
254
  }
254
255
  }
255
256
  });
256
257
 
257
258
  this.targetEventListenersSetup = true;
258
- console.log(`[TabRegistry] Target event listeners setup complete for session ${this.sessionId}`);
259
+ logger.debug(`[TabRegistry] Target event listeners setup complete for session ${this.sessionId}`);
259
260
  } catch (error) {
260
- console.error(`[TabRegistry] Failed to setup target event listeners:`, error);
261
+ logger.error(`[TabRegistry] Failed to setup target event listeners:`, error);
261
262
  }
262
263
  }
263
264
 
@@ -266,13 +267,13 @@ export class ChromeController {
266
267
  */
267
268
  async initializeTabRegistry() {
268
269
  if (!this.browser) {
269
- console.warn(`[TabRegistry] Cannot initialize - no browser connection`);
270
+ logger.warn(`[TabRegistry] Cannot initialize - no browser connection`);
270
271
  return;
271
272
  }
272
273
 
273
274
  try {
274
275
  const pages = await this.browser.pages();
275
- console.log(`[TabRegistry] Initializing with ${pages.length} existing tabs`);
276
+ logger.debug(`[TabRegistry] Initializing with ${pages.length} existing tabs`);
276
277
 
277
278
  for (const page of pages) {
278
279
  await this.registerTab(page);
@@ -281,9 +282,9 @@ export class ChromeController {
281
282
  // Set up event listeners after registry initialization
282
283
  await this.setupTargetEventListeners();
283
284
 
284
- console.log(`[TabRegistry] Initialization complete - ${this.tabRegistry.size} tabs registered`);
285
+ logger.debug(`[TabRegistry] Initialization complete - ${this.tabRegistry.size} tabs registered`);
285
286
  } catch (error) {
286
- console.error(`[TabRegistry] Failed to initialize tab registry:`, error);
287
+ logger.error(`[TabRegistry] Failed to initialize tab registry:`, error);
287
288
  }
288
289
  }
289
290
 
@@ -323,7 +324,7 @@ export class ChromeController {
323
324
  }
324
325
  }
325
326
  } catch (error) {
326
- console.error(`[TabRegistry] Error finding valid page:`, error);
327
+ logger.error(`[TabRegistry] Error finding valid page:`, error);
327
328
  }
328
329
  }
329
330
 
@@ -373,7 +374,7 @@ export class ChromeController {
373
374
  if (!options.allowCrossSession) {
374
375
  throw new Error(`Cross-session tab access denied. Tab belongs to session ${tabData.sessionId}, current session is ${this.sessionId}`);
375
376
  }
376
- console.warn(`[TabRegistry] Cross-session tab switch: ${tabData.sessionId} → ${this.sessionId}`);
377
+ logger.warn(`[TabRegistry] Cross-session tab switch: ${tabData.sessionId} → ${this.sessionId}`);
377
378
  }
378
379
 
379
380
  // Verify the page is still valid
@@ -385,7 +386,7 @@ export class ChromeController {
385
386
  // Switch to the tab
386
387
  const success = this.setActiveTab(targetId);
387
388
  if (success) {
388
- console.log(`[TabRegistry] Switched to tab ${targetId} (Session: ${tabData.sessionId})`);
389
+ logger.debug(`[TabRegistry] Switched to tab ${targetId} (Session: ${tabData.sessionId})`);
389
390
  return {
390
391
  success: true,
391
392
  targetId,
@@ -416,7 +417,7 @@ export class ChromeController {
416
417
  const tabData = await this.registerTab(newPage);
417
418
 
418
419
  if (tabData) {
419
- console.log(`[TabRegistry] Created new tab ${tabData.targetId} for session ${this.sessionId}`);
420
+ logger.debug(`[TabRegistry] Created new tab ${tabData.targetId} for session ${this.sessionId}`);
420
421
  return {
421
422
  success: true,
422
423
  targetId: tabData.targetId,
@@ -427,7 +428,7 @@ export class ChromeController {
427
428
 
428
429
  throw new Error('Failed to register new tab');
429
430
  } catch (error) {
430
- console.error(`[TabRegistry] Error creating new tab:`, error);
431
+ logger.error(`[TabRegistry] Error creating new tab:`, error);
431
432
  throw error;
432
433
  }
433
434
  }
@@ -442,14 +443,14 @@ export class ChromeController {
442
443
  // Security: Validate that processId is a valid number and contains no suspicious characters
443
444
  const pidStr = String(this.processId).trim();
444
445
  if (!/^\d+$/.test(pidStr)) {
445
- console.error('Invalid or suspicious process ID for Chrome process:', this.processId);
446
+ logger.error('Invalid or suspicious process ID for Chrome process:', this.processId);
446
447
  this.processId = null;
447
448
  return;
448
449
  }
449
450
 
450
451
  const pid = parseInt(pidStr, 10);
451
452
  if (isNaN(pid) || pid <= 0 || pid > 4194304) {
452
- console.error('Invalid process ID for Chrome process:', this.processId);
453
+ logger.error('Invalid process ID for Chrome process:', this.processId);
453
454
  this.processId = null;
454
455
  return;
455
456
  }
@@ -478,7 +479,7 @@ export class ChromeController {
478
479
  if (error.code === 'ESRCH') {
479
480
  // Process already dead, ignore
480
481
  } else if (error.code === 'EPERM') {
481
- console.error('Permission denied killing Chrome process:', pid);
482
+ logger.error('Permission denied killing Chrome process:', pid);
482
483
  } else {
483
484
  throw error;
484
485
  }
@@ -487,7 +488,7 @@ export class ChromeController {
487
488
  this.processId = null;
488
489
  }
489
490
  } catch (error) {
490
- console.error('Error killing Chrome process:', error.message);
491
+ logger.error('Error killing Chrome process:', error.message);
491
492
  }
492
493
  }
493
494
 
@@ -513,7 +514,7 @@ export class ChromeController {
513
514
  try {
514
515
  // Use Node.js fs.rm() instead of shell commands to prevent injection
515
516
  await fs.rm(resolvedPath, { recursive: true, force: true });
516
- console.error(`Cleaned up directory: ${resolvedPath}`);
517
+ logger.error(`Cleaned up directory: ${resolvedPath}`);
517
518
  } catch (error) {
518
519
  if (error.code === 'ENOENT') {
519
520
  // Directory doesn't exist, ignore
@@ -542,23 +543,23 @@ export class ChromeController {
542
543
  try {
543
544
  process.kill(pid, 0);
544
545
  // Process exists, skip this directory
545
- console.error(`Skipping active ChromeDebug MCP directory: ${dir} (PID ${pid} is still running)`);
546
+ logger.error(`Skipping active ChromeDebug MCP directory: ${dir} (PID ${pid} is still running)`);
546
547
  } catch (e) {
547
548
  if (e.code === 'ESRCH') {
548
549
  // Process doesn't exist, safe to clean up
549
550
  const dirPath = path.join(tmpDir, dir);
550
- console.error(`Cleaning up stale ChromeDebug MCP directory: ${dir} (PID ${pid} no longer exists)`);
551
+ logger.error(`Cleaning up stale ChromeDebug MCP directory: ${dir} (PID ${pid} no longer exists)`);
551
552
  await fs.rm(dirPath, { recursive: true, force: true });
552
553
  }
553
554
  }
554
555
  }
555
556
  }
556
557
  } catch (error) {
557
- console.error(`Error processing directory ${dir}:`, error.message);
558
+ logger.error(`Error processing directory ${dir}:`, error.message);
558
559
  }
559
560
  }
560
561
  } catch (error) {
561
- console.error('Error during stale profile cleanup:', error.message);
562
+ logger.error('Error during stale profile cleanup:', error.message);
562
563
  }
563
564
  }
564
565
 
@@ -584,7 +585,7 @@ export class ChromeController {
584
585
  return sharedResult;
585
586
  }
586
587
  } catch (error) {
587
- console.warn('[ChromeController] Shared browser unavailable, falling back to individual browser:', error.message);
588
+ logger.warn('[ChromeController] Shared browser unavailable, falling back to individual browser:', error.message);
588
589
  }
589
590
 
590
591
  // Fallback to individual browser launch
@@ -594,9 +595,9 @@ export class ChromeController {
594
595
  if (sessionData) {
595
596
  try {
596
597
  await this.sessionManager.forceCleanupSession(sessionData.sessionId);
597
- console.error(`Cleaned up session after launch failure: ${sessionData.sessionId}`);
598
+ logger.error(`Cleaned up session after launch failure: ${sessionData.sessionId}`);
598
599
  } catch (cleanupError) {
599
- console.error(`Failed to clean up session: ${sessionData.sessionId}`, cleanupError.message);
600
+ logger.error(`Failed to clean up session: ${sessionData.sessionId}`, cleanupError.message);
600
601
  }
601
602
  }
602
603
 
@@ -616,13 +617,13 @@ export class ChromeController {
616
617
  * @returns {Promise<Object>} Connection result
617
618
  */
618
619
  async connectToSharedBrowser() {
619
- console.log('[ChromeController] Attempting to connect to shared browser daemon...');
620
+ logger.debug('[ChromeController] Attempting to connect to shared browser daemon...');
620
621
 
621
622
  // Check if we should use fallback based on failover manager
622
623
  const shouldUseFallback = await this.failoverManager.shouldUseFallback('connect');
623
624
  if (shouldUseFallback) {
624
625
  // Instead of immediately failing, try to auto-start a daemon if none exists
625
- console.log('[ChromeController] Failover manager recommends fallback, but checking for auto-start opportunity...');
626
+ logger.debug('[ChromeController] Failover manager recommends fallback, but checking for auto-start opportunity...');
626
627
  }
627
628
 
628
629
  // Try to find a running daemon by checking common ports
@@ -657,7 +658,7 @@ export class ChromeController {
657
658
  const isListening = await checkPort();
658
659
  if (isListening) {
659
660
  daemonPort = port;
660
- console.log(`[ChromeController] Found potential daemon on port ${port}`);
661
+ logger.debug(`[ChromeController] Found potential daemon on port ${port}`);
661
662
  break;
662
663
  }
663
664
  } catch (error) {
@@ -667,10 +668,10 @@ export class ChromeController {
667
668
 
668
669
  if (!daemonPort) {
669
670
  try {
670
- console.log('[ChromeController] No existing daemon found, starting new daemon...');
671
+ logger.debug('[ChromeController] No existing daemon found, starting new daemon...');
671
672
  daemonPort = await this.autoStartDaemon();
672
673
  } catch (error) {
673
- console.warn('[ChromeController] Daemon auto-start failed, falling back to individual browser:', error.message);
674
+ logger.warn('[ChromeController] Daemon auto-start failed, falling back to individual browser:', error.message);
674
675
  // Now honor the failover manager's recommendation if auto-start also failed
675
676
  if (shouldUseFallback) {
676
677
  throw new Error('Failover manager recommends using individual browser after auto-start failed');
@@ -712,7 +713,7 @@ export class ChromeController {
712
713
  // Notify failover manager of successful connection
713
714
  await this.failoverManager.recordSuccessfulCheck(Date.now());
714
715
 
715
- console.log(`[ChromeController] Successfully connected to shared browser daemon on port ${daemonPort}`);
716
+ logger.debug(`[ChromeController] Successfully connected to shared browser daemon on port ${daemonPort}`);
716
717
 
717
718
  return {
718
719
  success: true,
@@ -730,7 +731,7 @@ export class ChromeController {
730
731
  * @returns {Promise<Object>} Launch result
731
732
  */
732
733
  async launchIndividualBrowser() {
733
- console.log('[ChromeController] Launching individual browser instance...');
734
+ logger.debug('[ChromeController] Launching individual browser instance...');
734
735
 
735
736
  let sessionData = null;
736
737
 
@@ -743,8 +744,8 @@ export class ChromeController {
743
744
  this.userDataDir = sessionData.profilePath;
744
745
  this.sessionId = sessionData.sessionId;
745
746
 
746
- console.error(`Launching Chrome with debugging port ${this.debugPort}`);
747
- console.error(`User data directory: ${this.userDataDir}`);
747
+ logger.error(`Launching Chrome with debugging port ${this.debugPort}`);
748
+ logger.error(`User data directory: ${this.userDataDir}`);
748
749
 
749
750
  // Detect Chrome executable path
750
751
  let executablePath;
@@ -762,7 +763,7 @@ export class ChromeController {
762
763
  executablePath = '/usr/bin/google-chrome';
763
764
  }
764
765
 
765
- console.error(`Using Chrome executable: ${executablePath}`);
766
+ logger.error(`Using Chrome executable: ${executablePath}`);
766
767
 
767
768
  // Get Chrome extension path with fallback logic
768
769
  const extensionPath = getExtensionPath();
@@ -784,7 +785,7 @@ export class ChromeController {
784
785
  `--load-extension=${extensionPath}`
785
786
  );
786
787
  } else {
787
- console.warn('[ChromeController] ChromeDebug extension not found. Visual selection features will be unavailable.');
788
+ logger.warn('[ChromeController] ChromeDebug extension not found. Visual selection features will be unavailable.');
788
789
  }
789
790
 
790
791
  // First, try to launch Chrome with a simpler configuration
@@ -798,7 +799,7 @@ export class ChromeController {
798
799
  timeout: 60000
799
800
  });
800
801
  } catch (launchError) {
801
- console.error('Simple launch failed, trying with additional flags...');
802
+ logger.error('Simple launch failed, trying with additional flags...');
802
803
 
803
804
  // Build fallback args with more flags
804
805
  const fallbackArgs = [
@@ -845,7 +846,7 @@ export class ChromeController {
845
846
 
846
847
  // Set up disconnect handler
847
848
  this.browser.on('disconnected', () => {
848
- console.error('Browser disconnected');
849
+ logger.error('Browser disconnected');
849
850
  this.browser = null;
850
851
  this.page = null;
851
852
  this.client = null;
@@ -899,7 +900,7 @@ export class ChromeController {
899
900
 
900
901
  // Get the WebSocket endpoint for future connections
901
902
  const wsEndpoint = this.browser.wsEndpoint();
902
- console.error(`Chrome WebSocket endpoint: ${wsEndpoint}`);
903
+ logger.error(`Chrome WebSocket endpoint: ${wsEndpoint}`);
903
904
 
904
905
  return {
905
906
  success: true,
@@ -917,9 +918,9 @@ export class ChromeController {
917
918
  if (sessionData) {
918
919
  try {
919
920
  await this.sessionManager.forceCleanupSession(sessionData.sessionId);
920
- console.error(`Cleaned up session after launch failure: ${sessionData.sessionId}`);
921
+ logger.error(`Cleaned up session after launch failure: ${sessionData.sessionId}`);
921
922
  } catch (cleanupError) {
922
- console.error(`Failed to clean up session: ${sessionData.sessionId}`, cleanupError.message);
923
+ logger.error(`Failed to clean up session: ${sessionData.sessionId}`, cleanupError.message);
923
924
  }
924
925
  }
925
926
 
@@ -967,7 +968,7 @@ export class ChromeController {
967
968
  async autoStartDaemon() {
968
969
  // Prevent concurrent daemon starts using class-level lock
969
970
  if (ChromeController.daemonStartPromise) {
970
- console.log('[ChromeController] Daemon start already in progress, waiting...');
971
+ logger.debug('[ChromeController] Daemon start already in progress, waiting...');
971
972
  return await ChromeController.daemonStartPromise;
972
973
  }
973
974
 
@@ -994,14 +995,14 @@ export class ChromeController {
994
995
  this.isDaemonOwner = true;
995
996
 
996
997
  const daemonPort = this.sharedDaemon.config.daemonPort;
997
- console.log(`[ChromeController] Started shared browser daemon on port ${daemonPort}`);
998
+ logger.debug(`[ChromeController] Started shared browser daemon on port ${daemonPort}`);
998
999
 
999
1000
  // Set up cleanup handlers for this specific daemon owner
1000
1001
  this.setupDaemonCleanup();
1001
1002
 
1002
1003
  return daemonPort;
1003
1004
  } catch (error) {
1004
- console.error('[ChromeController] Failed to start daemon:', error.message);
1005
+ logger.error('[ChromeController] Failed to start daemon:', error.message);
1005
1006
  this.sharedDaemon = null;
1006
1007
  this.isDaemonOwner = false;
1007
1008
  throw new Error(`Could not start shared browser daemon: ${error.message}`);
@@ -1016,11 +1017,11 @@ export class ChromeController {
1016
1017
 
1017
1018
  const cleanupHandler = async () => {
1018
1019
  if (this.isDaemonOwner && this.sharedDaemon) {
1019
- console.log('[ChromeController] Cleaning up auto-started daemon...');
1020
+ logger.debug('[ChromeController] Cleaning up auto-started daemon...');
1020
1021
  try {
1021
1022
  await this.sharedDaemon.gracefulShutdown();
1022
1023
  } catch (error) {
1023
- console.error('[ChromeController] Error stopping daemon:', error.message);
1024
+ logger.error('[ChromeController] Error stopping daemon:', error.message);
1024
1025
  }
1025
1026
  this.sharedDaemon = null;
1026
1027
  this.isDaemonOwner = false;
@@ -1040,7 +1041,7 @@ export class ChromeController {
1040
1041
  await this.close();
1041
1042
  }
1042
1043
 
1043
- console.error(`Attempting to connect to Chrome on port ${port}...`);
1044
+ logger.error(`Attempting to connect to Chrome on port ${port}...`);
1044
1045
 
1045
1046
  // Try connecting with a timeout
1046
1047
  this.browser = await this.withTimeout(
@@ -1053,10 +1054,10 @@ export class ChromeController {
1053
1054
  );
1054
1055
 
1055
1056
  this.debugPort = port;
1056
- console.error(`Successfully connected to existing Chrome on port ${port}`);
1057
+ logger.error(`Successfully connected to existing Chrome on port ${port}`);
1057
1058
 
1058
1059
  this.browser.on('disconnected', () => {
1059
- console.error('Browser disconnected');
1060
+ logger.error('Browser disconnected');
1060
1061
  this.browser = null;
1061
1062
  this.page = null;
1062
1063
  this.client = null;
@@ -1647,7 +1648,7 @@ export class ChromeController {
1647
1648
  }
1648
1649
 
1649
1650
  async forceReset() {
1650
- console.error('Force resetting Chrome...');
1651
+ logger.error('Force resetting Chrome...');
1651
1652
 
1652
1653
  await this.killOwnChromeProcess();
1653
1654
 
@@ -1658,9 +1659,9 @@ export class ChromeController {
1658
1659
  if (this.sessionManager && this.sessionId) {
1659
1660
  try {
1660
1661
  await this.sessionManager.forceCleanupSession(this.sessionId);
1661
- console.log(`[ChromeController] Force cleanup completed for session ${this.sessionId}`);
1662
+ logger.debug(`[ChromeController] Force cleanup completed for session ${this.sessionId}`);
1662
1663
  } catch (error) {
1663
- console.error('[ChromeController] Error during force cleanup:', error.message);
1664
+ logger.error('[ChromeController] Error during force cleanup:', error.message);
1664
1665
  }
1665
1666
  }
1666
1667
 
@@ -1686,7 +1687,7 @@ export class ChromeController {
1686
1687
  try {
1687
1688
  await this.browser.close();
1688
1689
  } catch (e) {
1689
- console.error('Error closing browser:', e.message);
1690
+ logger.error('Error closing browser:', e.message);
1690
1691
  } finally {
1691
1692
  this.browser = null;
1692
1693
  this.page = null;
@@ -1699,9 +1700,9 @@ export class ChromeController {
1699
1700
  if (this.sessionManager) {
1700
1701
  try {
1701
1702
  await this.sessionManager.cleanup();
1702
- console.log(`[ChromeController] Session cleanup completed for ${this.sessionId}`);
1703
+ logger.debug(`[ChromeController] Session cleanup completed for ${this.sessionId}`);
1703
1704
  } catch (error) {
1704
- console.error('[ChromeController] Error during session cleanup:', error.message);
1705
+ logger.error('[ChromeController] Error during session cleanup:', error.message);
1705
1706
  }
1706
1707
  }
1707
1708
 
@@ -1717,11 +1718,11 @@ export class ChromeController {
1717
1718
  async cleanup() {
1718
1719
  // Clean up auto-started daemon first
1719
1720
  if (this.isDaemonOwner && this.sharedDaemon) {
1720
- console.log('[ChromeController] Cleaning up auto-started daemon during cleanup...');
1721
+ logger.debug('[ChromeController] Cleaning up auto-started daemon during cleanup...');
1721
1722
  try {
1722
1723
  await this.sharedDaemon.gracefulShutdown();
1723
1724
  } catch (error) {
1724
- console.error('[ChromeController] Error stopping daemon during cleanup:', error.message);
1725
+ logger.error('[ChromeController] Error stopping daemon during cleanup:', error.message);
1725
1726
  }
1726
1727
  this.sharedDaemon = null;
1727
1728
  this.isDaemonOwner = false;
@@ -1987,7 +1988,7 @@ export class ChromeController {
1987
1988
  // Merge function traces into actions if provided
1988
1989
  let allActions = [...actions];
1989
1990
  if (functionTraces && functionTraces.length > 0) {
1990
- console.log(`[ChromeController] Merging ${functionTraces.length} function traces into actions`);
1991
+ logger.debug(`[ChromeController] Merging ${functionTraces.length} function traces into actions`);
1991
1992
  // Function traces are already in the correct format from the Chrome extension
1992
1993
  allActions = [...actions, ...functionTraces];
1993
1994
  // Sort all actions by timestamp to maintain chronological order
@@ -2005,10 +2006,10 @@ export class ChromeController {
2005
2006
  // Store logs if provided
2006
2007
  if (includeLogs && logs && logs.length > 0) {
2007
2008
  const logsResult = database.storeWorkflowLogs(workflowId, logs);
2008
- console.log(`Stored ${logsResult.storedCount} logs for workflow ${sessionId}`);
2009
+ logger.debug(`Stored ${logsResult.storedCount} logs for workflow ${sessionId}`);
2009
2010
  }
2010
2011
 
2011
- console.log(`Stored workflow recording ${sessionId} with ${actionsResult.storedCount} actions (including ${functionTraces ? functionTraces.length : 0} function traces)`);
2012
+ logger.debug(`Stored workflow recording ${sessionId} with ${actionsResult.storedCount} actions (including ${functionTraces ? functionTraces.length : 0} function traces)`);
2012
2013
 
2013
2014
  return {
2014
2015
  success: true,
@@ -2019,7 +2020,7 @@ export class ChromeController {
2019
2020
  functionTracesStored: functionTraces ? functionTraces.length : 0
2020
2021
  };
2021
2022
  } catch (error) {
2022
- console.error('Error storing workflow recording:', error);
2023
+ logger.error('Error storing workflow recording:', error);
2023
2024
  throw error;
2024
2025
  }
2025
2026
  }
@@ -2029,7 +2030,7 @@ export class ChromeController {
2029
2030
  const { database } = await import('./database.js');
2030
2031
  return database.getWorkflowRecording(sessionId);
2031
2032
  } catch (error) {
2032
- console.error('Error retrieving workflow recording:', error);
2033
+ logger.error('Error retrieving workflow recording:', error);
2033
2034
  throw error;
2034
2035
  }
2035
2036
  }
@@ -2040,7 +2041,7 @@ export class ChromeController {
2040
2041
  const recordings = database.listWorkflowRecordings();
2041
2042
  return { recordings };
2042
2043
  } catch (error) {
2043
- console.error('Error listing workflow recordings:', error);
2044
+ logger.error('Error listing workflow recordings:', error);
2044
2045
  throw error;
2045
2046
  }
2046
2047
  }
@@ -2062,7 +2063,7 @@ export class ChromeController {
2062
2063
  recording: recording
2063
2064
  };
2064
2065
  } catch (error) {
2065
- console.error('Error playing workflow recording:', error);
2066
+ logger.error('Error playing workflow recording:', error);
2066
2067
  throw error;
2067
2068
  }
2068
2069
  }
@@ -2094,7 +2095,7 @@ export class ChromeController {
2094
2095
  recording: fullRecording
2095
2096
  };
2096
2097
  } catch (error) {
2097
- console.error('Error playing workflow by name:', error);
2098
+ logger.error('Error playing workflow by name:', error);
2098
2099
  throw error;
2099
2100
  }
2100
2101
  }
@@ -2110,7 +2111,7 @@ export class ChromeController {
2110
2111
  );
2111
2112
  return result;
2112
2113
  } catch (error) {
2113
- console.error('Error saving restore point:', error);
2114
+ logger.error('Error saving restore point:', error);
2114
2115
  throw error;
2115
2116
  }
2116
2117
  }
@@ -2121,7 +2122,7 @@ export class ChromeController {
2121
2122
  const { database } = await import('./database.js');
2122
2123
  return database.getRestorePoint(restorePointId);
2123
2124
  } catch (error) {
2124
- console.error('Error getting restore point:', error);
2125
+ logger.error('Error getting restore point:', error);
2125
2126
  throw error;
2126
2127
  }
2127
2128
  }
@@ -2132,7 +2133,7 @@ export class ChromeController {
2132
2133
  const { database } = await import('./database.js');
2133
2134
  return database.listRestorePoints(workflowId);
2134
2135
  } catch (error) {
2135
- console.error('Error listing restore points:', error);
2136
+ logger.error('Error listing restore points:', error);
2136
2137
  throw error;
2137
2138
  }
2138
2139
  }
@@ -2146,7 +2147,7 @@ export class ChromeController {
2146
2147
  const result = deleteStmt.run(restorePointId);
2147
2148
  return { success: result.changes > 0 };
2148
2149
  } catch (error) {
2149
- console.error('Error deleting restore point:', error);
2150
+ logger.error('Error deleting restore point:', error);
2150
2151
  throw error;
2151
2152
  }
2152
2153
  }
@@ -2157,7 +2158,7 @@ export class ChromeController {
2157
2158
  const { database } = await import('./database.js');
2158
2159
  return database.getFrameSessionInfo(sessionId);
2159
2160
  } catch (error) {
2160
- console.error('Error getting frame session info:', error);
2161
+ logger.error('Error getting frame session info:', error);
2161
2162
  throw error;
2162
2163
  }
2163
2164
  }
@@ -2167,7 +2168,7 @@ export class ChromeController {
2167
2168
  const { database } = await import('./database.js');
2168
2169
  return database.getFrame(sessionId, frameIndex);
2169
2170
  } catch (error) {
2170
- console.error('Error getting frame:', error);
2171
+ logger.error('Error getting frame:', error);
2171
2172
  throw error;
2172
2173
  }
2173
2174
  }
@@ -2177,7 +2178,7 @@ export class ChromeController {
2177
2178
  const { database } = await import('./database.js');
2178
2179
  return database.getFrameScreenshot(sessionId, frameIndex, includeMetadata);
2179
2180
  } catch (error) {
2180
- console.error('Error getting frame screenshot:', error);
2181
+ logger.error('Error getting frame screenshot:', error);
2181
2182
  throw error;
2182
2183
  }
2183
2184
  }
@@ -2187,7 +2188,7 @@ export class ChromeController {
2187
2188
  const { database } = await import('./database.js');
2188
2189
  return database.getScreenInteractions(sessionId);
2189
2190
  } catch (error) {
2190
- console.error('Error retrieving screen interactions:', error);
2191
+ logger.error('Error retrieving screen interactions:', error);
2191
2192
  throw error;
2192
2193
  }
2193
2194
  }
@@ -2197,7 +2198,7 @@ export class ChromeController {
2197
2198
  const { database } = await import('./database.js');
2198
2199
  return database.getFrameInteractions(sessionId, frameIndex);
2199
2200
  } catch (error) {
2200
- console.error('Error retrieving frame interactions:', error);
2201
+ logger.error('Error retrieving frame interactions:', error);
2201
2202
  throw error;
2202
2203
  }
2203
2204
  }
@@ -2207,7 +2208,7 @@ export class ChromeController {
2207
2208
  const { database } = await import('./database.js');
2208
2209
  return database.getFrameSession(sessionId);
2209
2210
  } catch (error) {
2210
- console.error('Error getting frame session:', error);
2211
+ logger.error('Error getting frame session:', error);
2211
2212
  throw error;
2212
2213
  }
2213
2214
  }
@@ -2219,21 +2220,21 @@ export class ChromeController {
2219
2220
 
2220
2221
  // After storing frames, attempt to associate any deferred logs
2221
2222
  if (result && result.id) {
2222
- console.log(`[storeFrameBatch] Frames stored successfully, checking for deferred logs...`);
2223
+ logger.debug(`[storeFrameBatch] Frames stored successfully, checking for deferred logs...`);
2223
2224
  try {
2224
2225
  const deferredResult = await database.associateDeferredLogs(sessionId);
2225
2226
  if (deferredResult.success && deferredResult.logsAssociated > 0) {
2226
- console.log(`[storeFrameBatch] Associated ${deferredResult.logsAssociated} deferred logs with new frames`);
2227
+ logger.debug(`[storeFrameBatch] Associated ${deferredResult.logsAssociated} deferred logs with new frames`);
2227
2228
  }
2228
2229
  } catch (deferredError) {
2229
- console.error('[storeFrameBatch] Error associating deferred logs:', deferredError);
2230
+ logger.error('[storeFrameBatch] Error associating deferred logs:', deferredError);
2230
2231
  // Don't fail the frame storage if deferred log association fails
2231
2232
  }
2232
2233
  }
2233
2234
 
2234
2235
  return result;
2235
2236
  } catch (error) {
2236
- console.error('Error storing frame batch:', error);
2237
+ logger.error('Error storing frame batch:', error);
2237
2238
  throw error;
2238
2239
  }
2239
2240
  }
@@ -2243,7 +2244,7 @@ export class ChromeController {
2243
2244
  const { database } = await import('./database.js');
2244
2245
  return database.associateLogsWithFrames(sessionId, logs);
2245
2246
  } catch (error) {
2246
- console.error('Error associating logs with frames:', error);
2247
+ logger.error('Error associating logs with frames:', error);
2247
2248
  throw error;
2248
2249
  }
2249
2250
  }
@@ -2253,7 +2254,7 @@ export class ChromeController {
2253
2254
  const { database } = await import('./database.js');
2254
2255
  return database.streamLogsToFrames(sessionId, logs);
2255
2256
  } catch (error) {
2256
- console.error('Error streaming logs to frames:', error);
2257
+ logger.error('Error streaming logs to frames:', error);
2257
2258
  throw error;
2258
2259
  }
2259
2260
  }
@@ -2281,7 +2282,7 @@ export class ChromeController {
2281
2282
  const { database } = await import('./database.js');
2282
2283
  return database.storeSnapshot(sessionId, frameData, userNote);
2283
2284
  } catch (error) {
2284
- console.error('Error storing snapshot:', error);
2285
+ logger.error('Error storing snapshot:', error);
2285
2286
  throw error;
2286
2287
  }
2287
2288
  }
@@ -2291,7 +2292,7 @@ export class ChromeController {
2291
2292
  const { database } = await import('./database.js');
2292
2293
  return database.getSnapshots(limit);
2293
2294
  } catch (error) {
2294
- console.error('Error getting snapshots:', error);
2295
+ logger.error('Error getting snapshots:', error);
2295
2296
  throw error;
2296
2297
  }
2297
2298
  }
@@ -2334,7 +2335,7 @@ export class ChromeController {
2334
2335
  message: `Snapshot created successfully with ID: ${result}`
2335
2336
  };
2336
2337
  } catch (error) {
2337
- console.error('Error taking snapshot:', error);
2338
+ logger.error('Error taking snapshot:', error);
2338
2339
  throw error;
2339
2340
  }
2340
2341
  }
@@ -2345,7 +2346,7 @@ export class ChromeController {
2345
2346
  const { database } = await import('./database.js');
2346
2347
  return database.listRecordings();
2347
2348
  } catch (error) {
2348
- console.error('Error listing frame sessions:', error);
2349
+ logger.error('Error listing frame sessions:', error);
2349
2350
  throw error;
2350
2351
  }
2351
2352
  }
@@ -2393,7 +2394,7 @@ export class ChromeController {
2393
2394
  timestamp: log.timestamp
2394
2395
  }));
2395
2396
  } catch (error) {
2396
- console.error('Error searching frame logs:', error);
2397
+ logger.error('Error searching frame logs:', error);
2397
2398
  throw error;
2398
2399
  }
2399
2400
  }
@@ -2463,7 +2464,7 @@ export class ChromeController {
2463
2464
  logs
2464
2465
  };
2465
2466
  } catch (error) {
2466
- console.error('Error getting paginated frame logs:', error);
2467
+ logger.error('Error getting paginated frame logs:', error);
2467
2468
  throw error;
2468
2469
  }
2469
2470
  }
@@ -2478,7 +2479,7 @@ export class ChromeController {
2478
2479
  return { success: false, error: 'Recording not found' };
2479
2480
  }
2480
2481
  } catch (error) {
2481
- console.error('Error deleting recording:', error);
2482
+ logger.error('Error deleting recording:', error);
2482
2483
  throw error;
2483
2484
  }
2484
2485
  }
@@ -2493,7 +2494,7 @@ export class ChromeController {
2493
2494
  return { success: false, error: 'Workflow recording not found' };
2494
2495
  }
2495
2496
  } catch (error) {
2496
- console.error('Error deleting workflow recording:', error);
2497
+ logger.error('Error deleting workflow recording:', error);
2497
2498
  throw error;
2498
2499
  }
2499
2500
  }
@@ -2541,7 +2542,7 @@ export class ChromeController {
2541
2542
  if (workflow.url) {
2542
2543
  const currentUrl = currentPage.url();
2543
2544
  if (currentUrl !== workflow.url) {
2544
- console.log(`Navigating to workflow URL: ${workflow.url}`);
2545
+ logger.debug(`Navigating to workflow URL: ${workflow.url}`);
2545
2546
  await currentPage.goto(workflow.url, { waitUntil: 'networkidle2' });
2546
2547
  await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for page to settle
2547
2548
  }
@@ -2550,7 +2551,7 @@ export class ChromeController {
2550
2551
  // Execute each action
2551
2552
  for (const action of actions) {
2552
2553
  try {
2553
- console.log(`Executing action ${executedActions + 1}/${actions.length}: ${action.type}`);
2554
+ logger.debug(`Executing action ${executedActions + 1}/${actions.length}: ${action.type}`);
2554
2555
 
2555
2556
  // Calculate delay based on speed
2556
2557
  const delay = action.timestamp && actions.indexOf(action) > 0
@@ -2566,13 +2567,13 @@ export class ChromeController {
2566
2567
  case 'click':
2567
2568
  if (action.selector) {
2568
2569
  const fixedSelector = this.fixSelector(action.selector);
2569
- console.log(`Fixed selector: ${fixedSelector} (original: ${action.selector})`);
2570
+ logger.debug(`Fixed selector: ${fixedSelector} (original: ${action.selector})`);
2570
2571
 
2571
2572
  try {
2572
2573
  await currentPage.waitForSelector(fixedSelector, { timeout: 5000 });
2573
2574
  await currentPage.click(fixedSelector);
2574
2575
  } catch (selectorError) {
2575
- console.error(`Failed with CSS selector, trying coordinates fallback`);
2576
+ logger.error(`Failed with CSS selector, trying coordinates fallback`);
2576
2577
  if (action.x && action.y) {
2577
2578
  await currentPage.mouse.click(action.x, action.y);
2578
2579
  } else {
@@ -2587,7 +2588,7 @@ export class ChromeController {
2587
2588
  case 'input':
2588
2589
  if (action.selector) {
2589
2590
  const fixedSelector = this.fixSelector(action.selector);
2590
- console.log(`Fixed input selector: ${fixedSelector} (original: ${action.selector})`);
2591
+ logger.debug(`Fixed input selector: ${fixedSelector} (original: ${action.selector})`);
2591
2592
 
2592
2593
  await currentPage.waitForSelector(fixedSelector, { timeout: 5000 });
2593
2594
  await currentPage.click(fixedSelector); // Focus the element
@@ -2625,17 +2626,17 @@ export class ChromeController {
2625
2626
  // Wait for navigation to complete
2626
2627
  await currentPage.waitForNavigation({ waitUntil: 'networkidle2', timeout: 10000 }).catch(() => {
2627
2628
  // Navigation might not happen, continue
2628
- console.log('Navigation timeout, continuing...');
2629
+ logger.debug('Navigation timeout, continuing...');
2629
2630
  });
2630
2631
  break;
2631
2632
 
2632
2633
  default:
2633
- console.warn(`Unknown action type: ${action.type}`);
2634
+ logger.warn(`Unknown action type: ${action.type}`);
2634
2635
  }
2635
2636
 
2636
2637
  executedActions++;
2637
2638
  } catch (error) {
2638
- console.error(`Error executing action ${executedActions + 1}:`, error);
2639
+ logger.error(`Error executing action ${executedActions + 1}:`, error);
2639
2640
  lastError = error.message;
2640
2641
  // Continue with next action on error
2641
2642
  }
@@ -2651,7 +2652,7 @@ export class ChromeController {
2651
2652
  error: lastError
2652
2653
  };
2653
2654
  } catch (error) {
2654
- console.error('Error playing workflow:', error);
2655
+ logger.error('Error playing workflow:', error);
2655
2656
  throw error;
2656
2657
  }
2657
2658
  }