@dynamicu/chromedebug-mcp 2.6.7 → 2.7.1

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.
Files changed (49) hide show
  1. package/CLAUDE.md +17 -1
  2. package/README.md +1 -1
  3. package/chrome-extension/activation-manager.js +10 -10
  4. package/chrome-extension/background.js +1045 -736
  5. package/chrome-extension/browser-recording-manager.js +1 -1
  6. package/chrome-extension/chrome-debug-logger.js +168 -0
  7. package/chrome-extension/chrome-session-manager.js +5 -5
  8. package/chrome-extension/console-interception-library.js +430 -0
  9. package/chrome-extension/content.css +16 -16
  10. package/chrome-extension/content.js +739 -221
  11. package/chrome-extension/data-buffer.js +5 -5
  12. package/chrome-extension/dom-tracker.js +9 -9
  13. package/chrome-extension/extension-config.js +1 -1
  14. package/chrome-extension/firebase-client.js +13 -13
  15. package/chrome-extension/frame-capture.js +20 -38
  16. package/chrome-extension/license-helper.js +33 -7
  17. package/chrome-extension/manifest.free.json +3 -6
  18. package/chrome-extension/network-tracker.js +9 -9
  19. package/chrome-extension/options.html +10 -0
  20. package/chrome-extension/options.js +21 -8
  21. package/chrome-extension/performance-monitor.js +17 -17
  22. package/chrome-extension/popup.html +230 -193
  23. package/chrome-extension/popup.js +146 -458
  24. package/chrome-extension/pro/enhanced-capture.js +406 -0
  25. package/chrome-extension/pro/frame-editor.html +433 -0
  26. package/chrome-extension/pro/frame-editor.js +1567 -0
  27. package/chrome-extension/pro/function-tracker.js +843 -0
  28. package/chrome-extension/pro/jszip.min.js +13 -0
  29. package/chrome-extension/upload-manager.js +7 -7
  30. package/dist/chromedebug-extension-free.zip +0 -0
  31. package/package.json +3 -1
  32. package/scripts/webpack.config.free.cjs +8 -8
  33. package/scripts/webpack.config.pro.cjs +2 -0
  34. package/src/cli.js +2 -2
  35. package/src/database.js +55 -7
  36. package/src/index.js +9 -6
  37. package/src/mcp/server.js +2 -2
  38. package/src/services/process-manager.js +10 -6
  39. package/src/services/process-tracker.js +10 -5
  40. package/src/services/profile-manager.js +17 -2
  41. package/src/validation/schemas.js +12 -11
  42. package/src/index-direct.js +0 -157
  43. package/src/index-modular.js +0 -219
  44. package/src/index-monolithic-backup.js +0 -2230
  45. package/src/legacy/chrome-controller-old.js +0 -1406
  46. package/src/legacy/index-express.js +0 -625
  47. package/src/legacy/index-old.js +0 -977
  48. package/src/legacy/routes.js +0 -260
  49. package/src/legacy/shared-storage.js +0 -101
@@ -5,7 +5,7 @@
5
5
 
6
6
  // Check if already loaded
7
7
  if (window.chromePilotContentScriptLoaded) {
8
- console.log('[ChromeDebug MCP v2.0] Content script already loaded, skipping re-injection');
8
+ // console.log('[ChromeDebug MCP v2.0] Content script already loaded, skipping re-injection');
9
9
  return;
10
10
  }
11
11
 
@@ -60,7 +60,7 @@
60
60
  }
61
61
 
62
62
  if (shouldBlock) {
63
- console.log(`[ChromeDebug MCP] Skipping restricted site (${mode} mode):`, hostname);
63
+ // console.log(`[ChromeDebug MCP] Skipping restricted site (${mode} mode):`, hostname);
64
64
  return;
65
65
  }
66
66
 
@@ -72,7 +72,7 @@
72
72
  window.chromePilotContentScriptLoaded = true;
73
73
 
74
74
  const CHROME_PILOT_VERSION = '2.0.4-BUILD-20250119';
75
- console.log(`[content.js] Loaded version: ${CHROME_PILOT_VERSION}`);
75
+ // console.log(`[content.js] Loaded version: ${CHROME_PILOT_VERSION}`);
76
76
 
77
77
  let frameFlashIndicator = null;
78
78
 
@@ -88,7 +88,7 @@ function isExtensionValid() {
88
88
 
89
89
  // Initialize ChromeDebug MCP content script
90
90
  setTimeout(() => {
91
- console.log('[ChromeDebug MCP] 🚀 Content script initializing...');
91
+ // console.log('[ChromeDebug MCP] 🚀 Content script initializing...');
92
92
  }, 100);
93
93
 
94
94
  /*
@@ -119,7 +119,7 @@ let consoleMonitorInjected = false;
119
119
 
120
120
  function injectConsoleMonitor() {
121
121
  if (consoleMonitorInjected) {
122
- console.log('[ChromeDebug] Console monitor already injected');
122
+ // console.log('[ChromeDebug] Console monitor already injected');
123
123
  return Promise.resolve(true);
124
124
  }
125
125
 
@@ -128,7 +128,7 @@ function injectConsoleMonitor() {
128
128
  script.src = chrome.runtime.getURL('console-monitor.js');
129
129
 
130
130
  script.onload = function() {
131
- console.log('[ChromeDebug] Console monitor loaded successfully');
131
+ // console.log('[ChromeDebug] Console monitor loaded successfully');
132
132
  consoleMonitorInjected = true;
133
133
  this.remove();
134
134
  resolve(true);
@@ -154,7 +154,7 @@ window.addEventListener('message', (event) => {
154
154
  }
155
155
  });
156
156
 
157
- console.log('[ChromeDebug] Console monitoring ready (will inject on demand)');
157
+ // console.log('[ChromeDebug] Console monitoring ready (will inject on demand)');
158
158
  */
159
159
 
160
160
  function getAngularComponentInfo(element) {
@@ -190,7 +190,7 @@ function getAngularComponentInfo(element) {
190
190
  };
191
191
  }
192
192
  } catch (e) {
193
- console.log('Error detecting Angular component:', e);
193
+ // console.log('Error detecting Angular component:', e);
194
194
  }
195
195
 
196
196
  return null;
@@ -218,8 +218,8 @@ function getReactComponentInfo(element) {
218
218
 
219
219
  // Debug: Log the first fiber to see what properties are available
220
220
  if (fiber) {
221
- console.log('React Fiber found:', fiber);
222
- console.log('Fiber properties:', Object.keys(fiber));
221
+ // console.log('React Fiber found:', fiber);
222
+ // console.log('Fiber properties:', Object.keys(fiber));
223
223
  }
224
224
 
225
225
  while (currentFiber) {
@@ -239,7 +239,7 @@ function getReactComponentInfo(element) {
239
239
  lineNumber: currentFiber._debugSource.lineNumber,
240
240
  columnNumber: currentFiber._debugSource.columnNumber
241
241
  };
242
- console.log('Found _debugSource:', sourceInfo);
242
+ // console.log('Found _debugSource:', sourceInfo);
243
243
  }
244
244
 
245
245
  // Method 2: _owner and _source
@@ -297,7 +297,7 @@ function getSelector(element) {
297
297
  }
298
298
 
299
299
  if (element.className && typeof element.className === 'string') {
300
- const classes = element.className.trim().split(/\s+/).filter(c => !c.startsWith('chrome-pilot'));
300
+ const classes = element.className.trim().split(/\s+/).filter(c => !c.startsWith('chrome-debug'));
301
301
  if (classes.length > 0) {
302
302
  return `${element.tagName.toLowerCase()}.${classes.join('.')}`;
303
303
  }
@@ -350,8 +350,8 @@ function getComponentInfo(element) {
350
350
  while (currentElement && depth < maxDepth) {
351
351
  // Log for debugging
352
352
  if (depth === 0) {
353
- console.log(`Checking element:`, currentElement);
354
- console.log(`Element keys:`, Object.keys(currentElement).filter(k => k.includes('react')));
353
+ // console.log(`Checking element:`, currentElement);
354
+ // console.log(`Element keys:`, Object.keys(currentElement).filter(k => k.includes('react')));
355
355
  }
356
356
 
357
357
  // Try to find React info on current element
@@ -388,7 +388,7 @@ function getComponentInfo(element) {
388
388
  return angularInfo;
389
389
  }
390
390
 
391
- console.log('No component info found');
391
+ // console.log('No component info found');
392
392
  return null;
393
393
  }
394
394
 
@@ -401,12 +401,12 @@ let cleanupExecuted = false;
401
401
  async function cleanup() {
402
402
  // Idempotent protection - only run cleanup once
403
403
  if (cleanupExecuted) {
404
- console.log('[ChromeDebug MCP] Cleanup already executed, skipping');
404
+ // console.log('[ChromeDebug MCP] Cleanup already executed, skipping');
405
405
  return;
406
406
  }
407
407
 
408
408
  cleanupExecuted = true;
409
- console.log('[ChromeDebug MCP] Executing cleanup...');
409
+ // console.log('[ChromeDebug MCP] Executing cleanup...');
410
410
 
411
411
  // Clean up recording indicators and event listeners
412
412
  try {
@@ -414,7 +414,7 @@ async function cleanup() {
414
414
 
415
415
  // Stop workflow recording if active
416
416
  if (typeof isWorkflowRecording !== 'undefined' && isWorkflowRecording) {
417
- console.log('[ChromeDebug MCP] Stopping workflow recording during cleanup');
417
+ // console.log('[ChromeDebug MCP] Stopping workflow recording during cleanup');
418
418
  if (typeof stopWorkflowRecording === 'function') {
419
419
  await stopWorkflowRecording();
420
420
  }
@@ -422,13 +422,13 @@ async function cleanup() {
422
422
 
423
423
  // Stop screen interaction tracking if active
424
424
  if (typeof isScreenRecording !== 'undefined' && isScreenRecording) {
425
- console.log('[ChromeDebug MCP] Stopping screen recording during cleanup');
425
+ // console.log('[ChromeDebug MCP] Stopping screen recording during cleanup');
426
426
  if (typeof stopScreenInteractionTracking === 'function') {
427
427
  stopScreenInteractionTracking();
428
428
  }
429
429
  }
430
430
 
431
- console.log('[ChromeDebug MCP] Cleanup completed successfully');
431
+ // console.log('[ChromeDebug MCP] Cleanup completed successfully');
432
432
  } catch (error) {
433
433
  console.warn('[ChromeDebug MCP] Error during cleanup:', error);
434
434
  }
@@ -449,7 +449,7 @@ if (isExtensionValid()) {
449
449
  });
450
450
  return true; // Keep channel open for async response
451
451
  } else if (request.action === 'showRecordingUI') {
452
- console.log('Received showRecordingUI message');
452
+ // console.log('Received showRecordingUI message');
453
453
  showRecordingInterface();
454
454
  sendResponse({ success: true });
455
455
  return true; // Keep channel open for async response
@@ -458,9 +458,9 @@ if (isExtensionValid()) {
458
458
  sendResponse({ success: true });
459
459
  } else if (request.action === 'recordingComplete') {
460
460
  // Show the recording ID in the floating UI
461
- console.log('Recording complete with ID:', request.recordingId);
461
+ // console.log('Recording complete with ID:', request.recordingId);
462
462
  if (recordingOverlay) {
463
- const statusDiv = document.getElementById('chrome-pilot-recording-status');
463
+ const statusDiv = document.getElementById('chrome-debug-recording-status');
464
464
  if (statusDiv && request.recordingId) {
465
465
  statusDiv.innerHTML = `<strong style="color: #4CAF50;">Recording saved!</strong><br>ID: <code style="background: #f0f0f0; padding: 2px 6px; border-radius: 3px; font-family: monospace;">${request.recordingId}</code>`;
466
466
 
@@ -476,32 +476,49 @@ if (isExtensionValid()) {
476
476
  sendResponse({ success: true });
477
477
  } else if (request.action === 'recordingStarted') {
478
478
  // Recording indicator now handled by ScreenCaptureVisualFeedback
479
- console.log('[ChromeDebug MCP] Received recordingStarted message with scheduled start time:', request.scheduledStartTime);
479
+ // console.log('[ChromeDebug MCP] Received recordingStarted message with scheduled start time:', request.scheduledStartTime);
480
480
  // Start tracking screen interactions with scheduled timing
481
481
  startScreenInteractionTracking(request.scheduledStartTime, request.sessionId);
482
482
  sendResponse({ success: true });
483
483
  } else if (request.action === 'recordingStopped') {
484
484
  // Recording indicator cleanup now handled by ScreenCaptureVisualFeedback
485
- console.log('[ChromeDebug MCP] Received recordingStopped message');
485
+ // console.log('[ChromeDebug MCP] Received recordingStopped message');
486
486
  // Stop tracking screen interactions
487
487
  stopScreenInteractionTracking();
488
488
  sendResponse({ success: true });
489
489
  } else if (request.action === 'recordingSessionComplete') {
490
490
  // Recording indicator cleanup now handled by ScreenCaptureVisualFeedback
491
- console.log('[ChromeDebug MCP] Received recordingSessionComplete message');
491
+ // console.log('[ChromeDebug MCP] Received recordingSessionComplete message');
492
492
  // Stop tracking screen interactions
493
493
  stopScreenInteractionTracking();
494
494
  sendResponse({ success: true });
495
495
  } else if (request.action === 'startWorkflowRecording') {
496
- console.log('[ChromeDebug MCP] Starting workflow recording with settings:', request.screenshotSettings);
496
+ // console.log('[ChromeDebug MCP] Starting workflow recording with settings:', request.screenshotSettings);
497
+ // Store tabId for use when stopping recording from mini-menu
498
+ workflowTabId = request.tabId;
497
499
  startWorkflowRecording(request.screenshotSettings);
498
500
  sendResponse({ success: true });
499
- } else if (request.action === 'stopWorkflowRecording') {
500
- console.log('[ChromeDebug MCP] Stopping workflow recording');
501
- stopWorkflowRecording().then(workflow => {
501
+ } else if (request.action === 'getWorkflowData') {
502
+ // Called by background script to retrieve workflow data
503
+ // This happens when popup stops the recording (not mini-menu)
504
+ // console.log('[ChromeDebug MCP] Getting workflow data');
505
+ stopWorkflowRecording().then(async workflow => {
502
506
  sendResponse({ success: true, workflow: workflow });
507
+
508
+ // CRITICAL FIX: Show completion UI in mini-menu after data is sent
509
+ // When popup stops recording, the mini-menu needs to show the completion state
510
+ // Get the workflowId from storage (set by background.js when recording started)
511
+ try {
512
+ const storedData = await chrome.storage.local.get(['currentWorkflowId']);
513
+ const workflowId = storedData.currentWorkflowId || 'Recording saved';
514
+ const actionCount = workflow.actions?.length || 0;
515
+ // console.log('[ChromeDebug MCP] Showing completion UI with workflowId:', workflowId, 'actionCount:', actionCount);
516
+ showWorkflowRecordingComplete(workflowId, actionCount);
517
+ } catch (e) {
518
+ // console.log('[ChromeDebug MCP] Could not show completion UI:', e);
519
+ }
503
520
  }).catch(error => {
504
- console.error('[ChromeDebug MCP] Error stopping workflow recording:', error);
521
+ console.error('[ChromeDebug MCP] Error getting workflow data:', error);
505
522
  sendResponse({ success: false, error: error.message });
506
523
  });
507
524
  return true; // Keep channel open for async response
@@ -531,7 +548,7 @@ if (isExtensionValid()) {
531
548
  return true; // Keep channel open for async response
532
549
  } else if (request.action === 'startFullDataRecording') {
533
550
  // Start full data recording with user configuration
534
- console.log('[ChromeDebug MCP] Starting full data recording with config:', request.config);
551
+ // console.log('[ChromeDebug MCP] Starting full data recording with config:', request.config);
535
552
  startFullDataRecording(request.config).then(() => {
536
553
  sendResponse({ success: true });
537
554
  }).catch(error => {
@@ -540,7 +557,7 @@ if (isExtensionValid()) {
540
557
  return true; // Keep channel open for async response
541
558
  } else if (request.action === 'stopFullDataRecording') {
542
559
  // Stop full data recording
543
- console.log('[ChromeDebug MCP] Stopping full data recording');
560
+ // console.log('[ChromeDebug MCP] Stopping full data recording');
544
561
  stopFullDataRecording().then(() => {
545
562
  sendResponse({ success: true });
546
563
  }).catch(error => {
@@ -606,7 +623,7 @@ async function waitForPageLoad(timeout = 10000) {
606
623
  // Set up timeout
607
624
  timeoutId = setTimeout(() => {
608
625
  cleanup();
609
- console.log('[ChromePilot] Page load timeout reached, continuing...');
626
+ // console.log('[ChromePilot] Page load timeout reached, continuing...');
610
627
  resolve();
611
628
  }, timeout);
612
629
  });
@@ -629,12 +646,12 @@ async function waitForElement(selector, timeout = 5000) {
629
646
 
630
647
  // Function to play a workflow recording
631
648
  async function playWorkflowRecording(workflow, actions) {
632
- console.log('[ChromePilot] Starting workflow playback with', actions.length, 'actions');
649
+ // console.log('[ChromePilot] Starting workflow playback with', actions.length, 'actions');
633
650
 
634
651
  try {
635
652
  // Show playback indicator
636
653
  const playbackIndicator = document.createElement('div');
637
- playbackIndicator.id = 'chrome-pilot-playback-indicator';
654
+ playbackIndicator.id = 'chrome-debug-playback-indicator';
638
655
  playbackIndicator.style.cssText = `
639
656
  position: fixed;
640
657
  top: 20px;
@@ -683,7 +700,7 @@ async function playWorkflowRecording(workflow, actions) {
683
700
  actionCounter.textContent = i + 1;
684
701
 
685
702
  try {
686
- console.log(`[ChromePilot] Executing action ${i + 1}/${actions.length}:`, action.type, 'selector:', action.selector);
703
+ // console.log(`[ChromePilot] Executing action ${i + 1}/${actions.length}:`, action.type, 'selector:', action.selector);
687
704
 
688
705
  // Calculate delay based on timestamps
689
706
  let delay = 500; // Default delay
@@ -692,7 +709,7 @@ async function playWorkflowRecording(workflow, actions) {
692
709
  // Apply reasonable limits
693
710
  delay = Math.min(delay, 10000); // Cap at 10 seconds
694
711
  delay = Math.max(delay, 100); // Minimum 100ms
695
- console.log(`[ChromePilot] Calculated delay: ${delay}ms`);
712
+ // console.log(`[ChromePilot] Calculated delay: ${delay}ms`);
696
713
  }
697
714
 
698
715
  // Wait between actions
@@ -710,13 +727,13 @@ async function playWorkflowRecording(workflow, actions) {
710
727
  let element = document.querySelector(fixedSelector);
711
728
  if (!element && action.xpath) {
712
729
  // Try XPath as fallback
713
- console.log('[ChromePilot] Trying XPath fallback:', action.xpath);
730
+ // console.log('[ChromePilot] Trying XPath fallback:', action.xpath);
714
731
  const xpathResult = document.evaluate(action.xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
715
732
  element = xpathResult.singleNodeValue;
716
733
  }
717
734
 
718
735
  if (!element) {
719
- console.log('[ChromePilot] Element not found immediately, waiting...');
736
+ // console.log('[ChromePilot] Element not found immediately, waiting...');
720
737
  element = await waitForElement(fixedSelector, 3000);
721
738
  }
722
739
 
@@ -728,7 +745,7 @@ async function playWorkflowRecording(workflow, actions) {
728
745
  clickableElement = element.closest('button, a') || element;
729
746
  }
730
747
 
731
- console.log('[ChromePilot] Found element:', clickableElement.tagName, 'for selector:', fixedSelector);
748
+ // console.log('[ChromePilot] Found element:', clickableElement.tagName, 'for selector:', fixedSelector);
732
749
  clickableElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
733
750
  await new Promise(resolve => setTimeout(resolve, 200)); // Wait for scroll
734
751
 
@@ -741,7 +758,7 @@ async function playWorkflowRecording(workflow, actions) {
741
758
  // Try to click
742
759
  try {
743
760
  clickableElement.click();
744
- console.log('[ChromePilot] Clicked element successfully');
761
+ // console.log('[ChromePilot] Clicked element successfully');
745
762
  } catch (e) {
746
763
  console.error('[ChromePilot] Error clicking element:', e);
747
764
  // Try alternative click method
@@ -754,7 +771,7 @@ async function playWorkflowRecording(workflow, actions) {
754
771
 
755
772
  // If URL changed, wait for page load
756
773
  if (window.location.href !== currentUrl) {
757
- console.log('[ChromePilot] Navigation detected after click, waiting for page load...');
774
+ // console.log('[ChromePilot] Navigation detected after click, waiting for page load...');
758
775
  await waitForPageLoad();
759
776
  }
760
777
  } else {
@@ -774,12 +791,12 @@ async function playWorkflowRecording(workflow, actions) {
774
791
  // Wait for element to appear if it's not immediately available
775
792
  let element = document.querySelector(action.selector);
776
793
  if (!element) {
777
- console.log('[ChromePilot] Input element not found immediately, waiting...');
794
+ // console.log('[ChromePilot] Input element not found immediately, waiting...');
778
795
  element = await waitForElement(action.selector, 3000);
779
796
  }
780
797
 
781
798
  if (element) {
782
- console.log('[ChromePilot] Found input element:', element.tagName, 'type:', element.type, 'for selector:', action.selector);
799
+ // console.log('[ChromePilot] Found input element:', element.tagName, 'type:', element.type, 'for selector:', action.selector);
783
800
  element.scrollIntoView({ behavior: 'smooth', block: 'center' });
784
801
  await new Promise(resolve => setTimeout(resolve, 200)); // Wait for scroll
785
802
 
@@ -791,7 +808,7 @@ async function playWorkflowRecording(workflow, actions) {
791
808
 
792
809
  // Set new value
793
810
  element.value = action.value || '';
794
- console.log('[ChromePilot] Set input value to:', action.value);
811
+ // console.log('[ChromePilot] Set input value to:', action.value);
795
812
 
796
813
  // Trigger events in the right order
797
814
  element.dispatchEvent(new Event('focus', { bubbles: true }));
@@ -819,7 +836,7 @@ async function playWorkflowRecording(workflow, actions) {
819
836
 
820
837
  case 'navigation':
821
838
  // Navigation will be handled by the browser
822
- console.log('[ChromePilot] Navigation detected');
839
+ // console.log('[ChromePilot] Navigation detected');
823
840
  break;
824
841
 
825
842
  default:
@@ -844,7 +861,7 @@ async function playWorkflowRecording(workflow, actions) {
844
861
  style.remove();
845
862
  }, 3000);
846
863
 
847
- console.log('[ChromePilot] Workflow playback completed');
864
+ // console.log('[ChromePilot] Workflow playback completed');
848
865
 
849
866
  } catch (error) {
850
867
  console.error('[ChromePilot] Error during workflow playback:', error);
@@ -857,6 +874,7 @@ let isWorkflowRecording = false;
857
874
  let workflowActions = [];
858
875
  let workflowRecordingIndicator = null;
859
876
  let workflowScreenshotSettings = null;
877
+ let workflowTabId = null; // Store tabId for use when stopping recording
860
878
  let lastScreenshotTime = 0;
861
879
  let pendingScreenshots = []; // Track pending screenshot captures
862
880
 
@@ -936,7 +954,7 @@ function getUniqueSelector(element) {
936
954
  // Try unique class combination
937
955
  if (element.className && typeof element.className === 'string') {
938
956
  const classes = element.className.trim().split(/\s+/)
939
- .filter(c => !c.startsWith('chrome-pilot'))
957
+ .filter(c => !c.startsWith('chrome-debug'))
940
958
  .filter(c => !c.includes(':')) // Filter out pseudo-class artifacts
941
959
  .map(c => {
942
960
  // Escape special characters in class names
@@ -985,18 +1003,17 @@ function getXPath(element) {
985
1003
 
986
1004
  // Create workflow recording indicator
987
1005
  function createWorkflowRecordingIndicator() {
988
- if (workflowRecordingIndicator) return;
989
-
1006
+ // CRITICAL FIX: If old indicator exists (showing completion), remove it completely
1007
+ // This ensures the old popup closes immediately before showing the new recording indicator
1008
+ if (workflowRecordingIndicator && workflowRecordingIndicator.parentNode) {
1009
+ workflowRecordingIndicator.parentNode.removeChild(workflowRecordingIndicator);
1010
+ workflowRecordingIndicator = null;
1011
+ }
1012
+
1013
+ // Always create fresh element for new recording
990
1014
  workflowRecordingIndicator = document.createElement('div');
991
- workflowRecordingIndicator.id = 'chrome-pilot-workflow-indicator';
992
- workflowRecordingIndicator.innerHTML = `
993
- <div style="display: flex; align-items: center; gap: 8px;">
994
- <span style="color: #9c27b0; font-size: 20px; animation: pulse 1.5s infinite;">●</span>
995
- <span>Recording Workflow...</span>
996
- <span id="workflow-action-count" style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 12px; font-size: 12px;">0 actions</span>
997
- </div>
998
- `;
999
-
1015
+ workflowRecordingIndicator.id = 'chrome-debug-workflow-indicator';
1016
+
1000
1017
  Object.assign(workflowRecordingIndicator.style, {
1001
1018
  position: 'fixed',
1002
1019
  bottom: '20px',
@@ -1012,11 +1029,77 @@ function createWorkflowRecordingIndicator() {
1012
1029
  boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
1013
1030
  backdropFilter: 'blur(10px)',
1014
1031
  WebkitBackdropFilter: 'blur(10px)',
1015
- pointerEvents: 'none',
1032
+ pointerEvents: 'auto',
1016
1033
  userSelect: 'none'
1017
1034
  });
1018
-
1035
+
1036
+ workflowRecordingIndicator.innerHTML = `
1037
+ <div style="display: flex; align-items: center; gap: 12px;">
1038
+ <div style="display: flex; align-items: center; gap: 8px; flex: 1;">
1039
+ <span style="color: #9c27b0; font-size: 20px; animation: pulse 1.5s infinite;">●</span>
1040
+ <span>Recording Workflow...</span>
1041
+ <span id="workflow-action-count" style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 12px; font-size: 12px;">0 actions</span>
1042
+ </div>
1043
+ <button id="workflow-stop-btn" style="background: #f44336; color: white; border: none; padding: 6px 16px; border-radius: 15px; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit;">Stop</button>
1044
+ <button id="workflow-close-btn" style="background: transparent; color: white; border: none; padding: 4px 8px; font-size: 16px; cursor: pointer; font-family: inherit; opacity: 0.7;" title="Close notification">×</button>
1045
+ </div>
1046
+ `;
1047
+
1019
1048
  document.body.appendChild(workflowRecordingIndicator);
1049
+
1050
+ // Add stop button click handler
1051
+ const stopBtn = document.getElementById('workflow-stop-btn');
1052
+ const closeBtn = document.getElementById('workflow-close-btn');
1053
+
1054
+ if (stopBtn) {
1055
+ stopBtn.addEventListener('click', async (e) => {
1056
+ e.stopPropagation();
1057
+ stopBtn.disabled = true;
1058
+ stopBtn.textContent = 'Stopping...';
1059
+
1060
+ try {
1061
+ // Stop workflow recording via background script (which handles saving automatically)
1062
+ // Include tabId explicitly - sender.tab.id can be undefined in some edge cases
1063
+ chrome.runtime.sendMessage({
1064
+ action: 'stopWorkflowRecording',
1065
+ tabId: workflowTabId
1066
+ }, (response) => {
1067
+ if (chrome.runtime.lastError) {
1068
+ console.error('[WorkflowRecording] Error:', chrome.runtime.lastError.message);
1069
+ stopBtn.textContent = 'Error';
1070
+ stopBtn.style.background = '#666';
1071
+ return;
1072
+ }
1073
+
1074
+ if (response && response.success) {
1075
+ // console.log('[WorkflowRecording] Stop response:', response);
1076
+ const workflowId = response.workflow?.sessionId || 'unknown';
1077
+ const actionCount = response.workflow?.actions?.length || 0;
1078
+ // console.log('[WorkflowRecording] Extracted workflowId:', workflowId, 'actionCount:', actionCount);
1079
+ // Show completion with action buttons
1080
+ showWorkflowRecordingComplete(workflowId, actionCount);
1081
+ } else {
1082
+ console.error('[WorkflowRecording] Failed to save:', response?.error);
1083
+ // Don't remove indicator, just show error
1084
+ stopBtn.textContent = 'Error';
1085
+ stopBtn.style.background = '#666';
1086
+ }
1087
+ });
1088
+ } catch (error) {
1089
+ console.error('[WorkflowRecording] Error stopping:', error);
1090
+ // Don't remove indicator, just show error
1091
+ stopBtn.textContent = 'Error';
1092
+ stopBtn.style.background = '#666';
1093
+ }
1094
+ });
1095
+ }
1096
+
1097
+ if (closeBtn) {
1098
+ closeBtn.addEventListener('click', (e) => {
1099
+ e.stopPropagation();
1100
+ removeWorkflowRecordingIndicator();
1101
+ });
1102
+ }
1020
1103
  }
1021
1104
 
1022
1105
  function removeWorkflowRecordingIndicator() {
@@ -1033,6 +1116,97 @@ function updateWorkflowActionCount() {
1033
1116
  }
1034
1117
  }
1035
1118
 
1119
+ // Show workflow recording completion with action buttons
1120
+ function showWorkflowRecordingComplete(workflowId, actionCount) {
1121
+ if (!workflowRecordingIndicator) return;
1122
+
1123
+ workflowRecordingIndicator.innerHTML = `
1124
+ <div style="display: flex; flex-direction: column; gap: 10px; position: relative; padding-right: 30px;">
1125
+ <button class="wf-close-complete" style="position: absolute; top: -8px; right: -8px; background: transparent; color: white; border: none; padding: 4px 8px; font-size: 20px; cursor: pointer; font-family: inherit; opacity: 0.7; line-height: 1;" title="Close notification">×</button>
1126
+
1127
+ <div style="display: flex; align-items: center; gap: 8px;">
1128
+ <span style="color: #4CAF50; font-size: 16px;">✓</span>
1129
+ <span style="font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 400px;" title="${workflowId}">${workflowId}</span>
1130
+ </div>
1131
+
1132
+ <div style="font-size: 11px; color: rgba(255,255,255,0.7); margin-top: -5px;">
1133
+ ${actionCount} actions • ${new Date().toLocaleString()}
1134
+ </div>
1135
+
1136
+ <div style="display: flex; gap: 6px; flex-wrap: wrap;">
1137
+ <button class="wf-copy-id" data-id="${workflowId}" style="background: #2196F3; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Copy ID</button>
1138
+ <button class="wf-copy-prompt" data-id="${workflowId}" style="background: #4CAF50; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Copy Prompt</button>
1139
+ <button class="wf-view" data-id="${workflowId}" style="background: #9C27B0; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">View</button>
1140
+ <button class="wf-delete" data-id="${workflowId}" style="background: #f44336; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Delete</button>
1141
+ </div>
1142
+ </div>
1143
+ `;
1144
+
1145
+ // Add event listeners for action buttons
1146
+ const copyIdBtn = workflowRecordingIndicator.querySelector('.wf-copy-id');
1147
+ const copyPromptBtn = workflowRecordingIndicator.querySelector('.wf-copy-prompt');
1148
+ const viewBtn = workflowRecordingIndicator.querySelector('.wf-view');
1149
+ const deleteBtn = workflowRecordingIndicator.querySelector('.wf-delete');
1150
+ const closeBtn = workflowRecordingIndicator.querySelector('.wf-close-complete');
1151
+
1152
+ if (copyIdBtn) {
1153
+ copyIdBtn.addEventListener('click', async () => {
1154
+ try {
1155
+ await navigator.clipboard.writeText(workflowId);
1156
+ copyIdBtn.textContent = 'Copied!';
1157
+ setTimeout(() => copyIdBtn.textContent = 'Copy ID', 2000);
1158
+ } catch (error) {
1159
+ console.error('[WorkflowRecording] Failed to copy ID:', error);
1160
+ }
1161
+ });
1162
+ }
1163
+
1164
+ if (copyPromptBtn) {
1165
+ copyPromptBtn.addEventListener('click', async () => {
1166
+ const prompt = `Please use the get_workflow_recording function in Chrome Debug to load the workflow recording "${workflowId}".`;
1167
+ try {
1168
+ await navigator.clipboard.writeText(prompt);
1169
+ copyPromptBtn.textContent = 'Copied!';
1170
+ setTimeout(() => copyPromptBtn.textContent = 'Copy Prompt', 2000);
1171
+ } catch (error) {
1172
+ console.error('[WorkflowRecording] Failed to copy prompt:', error);
1173
+ }
1174
+ });
1175
+ }
1176
+
1177
+ if (viewBtn) {
1178
+ viewBtn.addEventListener('click', () => {
1179
+ // Ask background to open frame editor (content scripts can't create tabs)
1180
+ chrome.runtime.sendMessage({
1181
+ action: 'openFrameEditor',
1182
+ sessionId: workflowId,
1183
+ type: 'workflow'
1184
+ });
1185
+ });
1186
+ }
1187
+
1188
+ if (deleteBtn) {
1189
+ deleteBtn.addEventListener('click', async () => {
1190
+ if (confirm('Delete this workflow recording?')) {
1191
+ chrome.runtime.sendMessage({
1192
+ action: 'deleteWorkflowRecording',
1193
+ workflowId: workflowId
1194
+ }, (response) => {
1195
+ if (response && response.success) {
1196
+ removeWorkflowRecordingIndicator();
1197
+ }
1198
+ });
1199
+ }
1200
+ });
1201
+ }
1202
+
1203
+ if (closeBtn) {
1204
+ closeBtn.addEventListener('click', () => {
1205
+ removeWorkflowRecordingIndicator();
1206
+ });
1207
+ }
1208
+ }
1209
+
1036
1210
  // Enhanced click tracking helper functions - Pro Feature
1037
1211
  // Try to import enhanced capture module (only exists in pro build)
1038
1212
  let enhancedCaptureModule = null;
@@ -1052,9 +1226,9 @@ let getPerformanceMetrics = null;
1052
1226
  captureElementState = module.captureElementState;
1053
1227
  getEnhancedComponentInfo = module.getEnhancedComponentInfo;
1054
1228
  getPerformanceMetrics = module.getPerformanceMetrics;
1055
- console.log('[ChromePilot Pro] Enhanced capture module loaded');
1229
+ // console.log('[ChromePilot Pro] Enhanced capture module loaded');
1056
1230
  } catch (e) {
1057
- console.log('[ChromePilot Free] Enhanced capture not available - using basic mode');
1231
+ // console.log('[ChromePilot Free] Enhanced capture not available - using basic mode');
1058
1232
  // Create stub functions that return empty data for free version
1059
1233
  captureElementHTML = () => '';
1060
1234
  extractEventHandlers = () => ({});
@@ -1076,19 +1250,16 @@ async function shouldEnhanceCapture() {
1076
1250
  // Record click action
1077
1251
  function recordClick(event) {
1078
1252
  if (!isWorkflowRecording) {
1079
- console.log('[ChromePilot] Click ignored - not recording');
1080
1253
  return;
1081
1254
  }
1082
1255
 
1083
- console.log('[ChromePilot] Recording click event');
1084
-
1085
1256
  let element = event.target;
1086
1257
 
1087
1258
  // If clicking on an SVG element or its children, find the parent button/link
1088
1259
  if (element.tagName === 'svg' || element.tagName === 'path' || element.tagName === 'g' || element.tagName === 'circle' || element.tagName === 'rect') {
1089
1260
  const clickableParent = element.closest('button, a, [role="button"], [onclick]');
1090
1261
  if (clickableParent) {
1091
- console.log('[ChromePilot] Adjusted click target from', element.tagName, 'to', clickableParent.tagName);
1262
+ // console.log('[ChromePilot] Adjusted click target from', element.tagName, 'to', clickableParent.tagName);
1092
1263
  element = clickableParent;
1093
1264
  }
1094
1265
  }
@@ -1116,8 +1287,6 @@ function recordClick(event) {
1116
1287
  shouldEnhanceCapture().then(enhanceCapture => {
1117
1288
  if (enhanceCapture) {
1118
1289
  try {
1119
- console.log('[ChromePilot] Capturing enhanced click data asynchronously...');
1120
-
1121
1290
  // Capture enhanced element data (only include fields with meaningful values)
1122
1291
  const capturedHTML = captureElementHTML(element);
1123
1292
  if (capturedHTML) {
@@ -1168,14 +1337,13 @@ function recordClick(event) {
1168
1337
  }
1169
1338
  }
1170
1339
 
1171
- console.log('[ChromePilot] Enhanced click data captured successfully');
1340
+ // Enhanced click data captured successfully - no need to log
1172
1341
  } catch (error) {
1173
1342
  console.warn('[ChromePilot] Error capturing enhanced click data:', error);
1174
1343
  // Continue with basic click recording if enhanced capture fails
1175
1344
  }
1176
- } else {
1177
- console.log('[ChromePilot] Enhanced click capture disabled - using basic capture only');
1178
1345
  }
1346
+ // Enhanced capture setting checked - no need to log state
1179
1347
  }).catch(error => {
1180
1348
  console.error('[ChromePilot] Error checking enhanced capture setting:', error);
1181
1349
  });
@@ -1303,12 +1471,12 @@ function startWorkflowRecording(screenshotSettings) {
1303
1471
  pendingScreenshots = []; // Clear any pending screenshots from previous recording
1304
1472
  createWorkflowRecordingIndicator();
1305
1473
 
1306
- console.log('[ChromePilot] Workflow recording started with settings:', screenshotSettings);
1474
+ // console.log('[ChromePilot] Workflow recording started with settings:', screenshotSettings);
1307
1475
 
1308
1476
  // Start runtime bridge recording for function traces
1309
1477
  if (window.__chromePilot && window.__chromePilot.startRecording) {
1310
1478
  window.__chromePilot.startRecording();
1311
- console.log('[ChromePilot] Started runtime bridge recording for function traces');
1479
+ // console.log('[ChromePilot] Started runtime bridge recording for function traces');
1312
1480
  }
1313
1481
 
1314
1482
  // Connect to the existing FunctionTracker for workflow recording
@@ -1334,17 +1502,19 @@ function startWorkflowRecording(screenshotSettings) {
1334
1502
  timestamp: event.timestamp,
1335
1503
  stack: event.call_stack || null
1336
1504
  });
1337
-
1338
- console.log('[ChromePilot] Function trace captured for workflow:', event.function_name);
1505
+
1506
+ // REMOVED: console.log that logged EVERY function execution (thousands per second)
1507
+ // Function traces are already stored in workflowActions array - no need to log each one
1339
1508
  }
1340
1509
  });
1341
1510
  };
1342
1511
 
1343
1512
  // Enable function tracking via ChromePilotTracker
1344
1513
  window.ChromePilotTracker._setRecordingStatus(true);
1345
- console.log('[ChromePilot] Connected workflow recording to FunctionTracker');
1514
+ // console.log('[ChromePilot] Connected workflow recording to FunctionTracker');
1346
1515
  } else {
1347
- console.warn('[ChromePilot] FunctionTracker not available for workflow recording');
1516
+ // FunctionTracker is a PRO feature - use debug level to avoid confusing FREE users
1517
+ console.debug('[ChromePilot] FunctionTracker not available (PRO feature)');
1348
1518
  }
1349
1519
 
1350
1520
  // Add event listeners for recording
@@ -1373,17 +1543,19 @@ function startWorkflowRecording(screenshotSettings) {
1373
1543
  // Stop workflow recording
1374
1544
  async function stopWorkflowRecording() {
1375
1545
  isWorkflowRecording = false;
1376
- removeWorkflowRecordingIndicator();
1546
+ workflowTabId = null; // Reset tabId when recording stops
1547
+ // DON'T remove indicator here - let the completion screen handle it
1548
+ // removeWorkflowRecordingIndicator();
1377
1549
 
1378
- console.log(`[ChromePilot] Stopping recording. Captured ${workflowActions.length} actions`);
1550
+ // console.log(`[ChromePilot] Stopping recording. Captured ${workflowActions.length} actions`);
1379
1551
 
1380
1552
  // Wait for all pending screenshots to complete
1381
1553
  if (pendingScreenshots.length > 0) {
1382
- console.log(`[SCREENSHOT-DEBUG] Waiting for ${pendingScreenshots.length} pending screenshots to complete...`);
1554
+ // console.log(`[SCREENSHOT-DEBUG] Waiting for ${pendingScreenshots.length} pending screenshots to complete...`);
1383
1555
  await Promise.all(pendingScreenshots);
1384
- console.log('[SCREENSHOT-DEBUG] All pending screenshots completed!');
1556
+ // console.log('[SCREENSHOT-DEBUG] All pending screenshots completed!');
1385
1557
  } else {
1386
- console.log('[SCREENSHOT-DEBUG] No pending screenshots to wait for');
1558
+ // console.log('[SCREENSHOT-DEBUG] No pending screenshots to wait for');
1387
1559
  }
1388
1560
 
1389
1561
  // Disconnect from FunctionTracker and disable recording
@@ -1393,7 +1565,7 @@ async function stopWorkflowRecording() {
1393
1565
 
1394
1566
  // Count function traces captured during workflow recording
1395
1567
  const functionTraces = workflowActions.filter(action => action.type === 'function-trace');
1396
- console.log(`[ChromePilot] Function tracking stopped. Captured ${functionTraces.length} function traces`);
1568
+ // console.log(`[ChromePilot] Function tracking stopped. Captured ${functionTraces.length} function traces`);
1397
1569
  }
1398
1570
 
1399
1571
  // Remove event listeners
@@ -1412,7 +1584,7 @@ async function stopWorkflowRecording() {
1412
1584
 
1413
1585
  // First, get any function traces from the runtime bridge
1414
1586
  if (window.__chromePilot && window.__chromePilot.stopRecording) {
1415
- console.log('[ChromeDebug MCP] Stopping runtime bridge recording...');
1587
+ // console.log('[ChromeDebug MCP] Stopping runtime bridge recording...');
1416
1588
  const bridgeTraces = window.__chromePilot.stopRecording();
1417
1589
  if (Array.isArray(bridgeTraces)) {
1418
1590
  // Convert bridge traces to workflow action format
@@ -1430,31 +1602,31 @@ async function stopWorkflowRecording() {
1430
1602
  placeholder: null,
1431
1603
  screenshot_data: null
1432
1604
  }));
1433
- console.log(`[Chrome Debug] Retrieved ${functionTraces.length} function traces from runtime bridge`);
1605
+ // console.log(`[Chrome Debug] Retrieved ${functionTraces.length} function traces from runtime bridge`);
1434
1606
  }
1435
1607
  }
1436
1608
 
1437
1609
  // Also include any function traces that were added to workflowActions
1438
1610
  const embeddedTraces = workflowActions.filter(action => action.type === 'function-trace');
1439
1611
  if (embeddedTraces.length > 0) {
1440
- console.log(`[Chrome Debug] Found ${embeddedTraces.length} embedded function traces`);
1612
+ // console.log(`[Chrome Debug] Found ${embeddedTraces.length} embedded function traces`);
1441
1613
  functionTraces = [...functionTraces, ...embeddedTraces];
1442
1614
  }
1443
1615
 
1444
1616
  // Log screenshot data before returning
1445
- console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Preparing to return workflow');
1446
- console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Total actions:', workflowActions.length);
1617
+ // console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Preparing to return workflow');
1618
+ // console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Total actions:', workflowActions.length);
1447
1619
 
1448
1620
  const actionsWithScreenshots = workflowActions.filter(a => a.screenshot_data);
1449
- console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Actions WITH screenshot_data:', actionsWithScreenshots.length);
1621
+ // console.log('[SCREENSHOT-DEBUG] stopWorkflowRecording - Actions WITH screenshot_data:', actionsWithScreenshots.length);
1450
1622
 
1451
1623
  workflowActions.forEach((action, index) => {
1452
- console.log(`[SCREENSHOT-DEBUG] stopWorkflowRecording - Action ${index}:`, {
1453
- type: action.type,
1454
- hasScreenshotData: !!action.screenshot_data,
1455
- screenshotDataLength: action.screenshot_data?.length,
1456
- screenshotPreview: action.screenshot_data?.substring(0, 50)
1457
- });
1624
+ // console.log(`[SCREENSHOT-DEBUG] stopWorkflowRecording - Action ${index}:`, {
1625
+ // type: action.type,
1626
+ // hasScreenshotData: !!action.screenshot_data,
1627
+ // screenshotDataLength: action.screenshot_data?.length,
1628
+ // screenshotPreview: action.screenshot_data?.substring(0, 50)
1629
+ // });
1458
1630
  });
1459
1631
 
1460
1632
  // Return the recorded workflow with proper functionTraces field
@@ -1601,7 +1773,7 @@ function captureConsoleLogs() {
1601
1773
 
1602
1774
  // Create restore point
1603
1775
  async function createRestorePoint(actionIndex) {
1604
- console.log('[ChromePilot] Creating restore point at action index:', actionIndex);
1776
+ // console.log('[ChromePilot] Creating restore point at action index:', actionIndex);
1605
1777
 
1606
1778
  try {
1607
1779
  // Capture all data
@@ -1630,7 +1802,7 @@ async function createRestorePoint(actionIndex) {
1630
1802
  });
1631
1803
 
1632
1804
  if (response && response.success) {
1633
- console.log('[ChromePilot] Restore point saved:', response.restorePointId);
1805
+ // console.log('[ChromePilot] Restore point saved:', response.restorePointId);
1634
1806
  // Visual feedback
1635
1807
  showRestorePointNotification('Restore point saved!');
1636
1808
  return response.restorePointId;
@@ -1646,7 +1818,7 @@ async function createRestorePoint(actionIndex) {
1646
1818
 
1647
1819
  // Restore from a restore point
1648
1820
  async function restoreFromPoint(restorePointData) {
1649
- console.log('[ChromePilot] Restoring from restore point');
1821
+ // console.log('[ChromePilot] Restoring from restore point');
1650
1822
 
1651
1823
  try {
1652
1824
  // First check if we need to navigate
@@ -1802,8 +1974,6 @@ async function recordScreenClick(event) {
1802
1974
  const enhanceCapture = await shouldEnhanceCapture();
1803
1975
  if (enhanceCapture) {
1804
1976
  try {
1805
- console.log('[ChromePilot] Capturing enhanced screen click data...');
1806
-
1807
1977
  // Capture enhanced element data (only include fields with meaningful values)
1808
1978
  const capturedHTML = captureElementHTML(element);
1809
1979
  if (capturedHTML) {
@@ -1854,14 +2024,13 @@ async function recordScreenClick(event) {
1854
2024
  }
1855
2025
  }
1856
2026
 
1857
- console.log('[ChromePilot] Enhanced screen click data captured successfully');
2027
+ // Enhanced screen click data captured successfully - no need to log
1858
2028
  } catch (error) {
1859
2029
  console.warn('[ChromePilot] Error capturing enhanced screen click data:', error);
1860
2030
  // Continue with basic click recording if enhanced capture fails
1861
2031
  }
1862
- } else {
1863
- console.log('[ChromePilot] Enhanced screen click capture disabled - using basic capture only');
1864
2032
  }
2033
+ // Enhanced capture setting checked - no need to log state
1865
2034
 
1866
2035
  sendScreenInteraction(interaction);
1867
2036
 
@@ -2000,7 +2169,7 @@ function startScreenInteractionTracking(scheduledStartTime, sessionId) {
2000
2169
  recordingScheduledStartTime = scheduledStartTime;
2001
2170
  recordingSessionId = sessionId;
2002
2171
 
2003
- console.log('[ChromePilot] Screen interaction tracking scheduled to start at:', new Date(scheduledStartTime));
2172
+ // console.log('[ChromePilot] Screen interaction tracking scheduled to start at:', new Date(scheduledStartTime));
2004
2173
 
2005
2174
  // Trigger visual feedback start
2006
2175
  if (window.screenCaptureVisualFeedback) {
@@ -2021,7 +2190,7 @@ function startScreenInteractionTracking(scheduledStartTime, sessionId) {
2021
2190
  document.addEventListener('mousedown', recordScreenMouseDown, true);
2022
2191
  document.addEventListener('mouseup', recordScreenMouseUp, true);
2023
2192
 
2024
- console.log('[ChromePilot] Screen interaction tracking started at scheduled time');
2193
+ // console.log('[ChromePilot] Screen interaction tracking started at scheduled time');
2025
2194
  }, waitTime);
2026
2195
  }
2027
2196
 
@@ -2054,7 +2223,7 @@ function stopScreenInteractionTracking() {
2054
2223
  screenRecordingDragStartX = 0; // CRITICAL: This was missing
2055
2224
  screenRecordingDragStartY = 0; // CRITICAL: This was missing
2056
2225
 
2057
- console.log('[ChromePilot] Screen interaction tracking stopped');
2226
+ // console.log('[ChromePilot] Screen interaction tracking stopped');
2058
2227
 
2059
2228
  // Visual feedback stop with error isolation
2060
2229
  try {
@@ -2148,7 +2317,7 @@ let isFullDataRecordingActive = false;
2148
2317
 
2149
2318
  // Create floating recording interface
2150
2319
  function showRecordingInterface() {
2151
- console.log('showRecordingInterface called');
2320
+ // console.log('showRecordingInterface called');
2152
2321
 
2153
2322
  // Remove any existing recording overlay
2154
2323
  if (recordingOverlay) {
@@ -2157,7 +2326,7 @@ function showRecordingInterface() {
2157
2326
 
2158
2327
  // Create recording overlay
2159
2328
  recordingOverlay = document.createElement('div');
2160
- recordingOverlay.id = 'chrome-pilot-recording-overlay';
2329
+ recordingOverlay.id = 'chrome-debug-recording-overlay';
2161
2330
  recordingOverlay.style.cssText = `
2162
2331
  position: fixed;
2163
2332
  bottom: 20px;
@@ -2175,13 +2344,13 @@ function showRecordingInterface() {
2175
2344
  recordingOverlay.innerHTML = `
2176
2345
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
2177
2346
  <h3 style="margin: 0; font-size: 16px; color: #333;">Screen Recording</h3>
2178
- <button id="chrome-pilot-close-recording" style="background: none; border: none; font-size: 20px; cursor: pointer; color: #666;">&times;</button>
2347
+ <button id="chrome-debug-close-recording" style="background: none; border: none; font-size: 20px; cursor: pointer; color: #666;">&times;</button>
2179
2348
  </div>
2180
2349
  <p style="margin: 0 0 15px 0; font-size: 13px; color: #666;">
2181
2350
  Recording this tab with console logs
2182
2351
  </p>
2183
- <div id="chrome-pilot-recording-status" style="text-align: center; margin-bottom: 15px; font-size: 14px; color: #666;"></div>
2184
- <button id="chrome-pilot-record-btn" style="
2352
+ <div id="chrome-debug-recording-status" style="text-align: center; margin-bottom: 15px; font-size: 14px; color: #666;"></div>
2353
+ <button id="chrome-debug-record-btn" style="
2185
2354
  width: 100%;
2186
2355
  padding: 10px;
2187
2356
  background: #f44336;
@@ -2192,13 +2361,13 @@ function showRecordingInterface() {
2192
2361
  font-size: 14px;
2193
2362
  font-weight: 500;
2194
2363
  ">Start Recording</button>
2195
- <div id="chrome-pilot-recording-result" style="margin-top: 15px; display: none;"></div>
2364
+ <div id="chrome-debug-recording-result" style="margin-top: 15px; display: none;"></div>
2196
2365
  `;
2197
2366
 
2198
2367
  document.body.appendChild(recordingOverlay);
2199
2368
 
2200
2369
  // Add event listeners
2201
- document.getElementById('chrome-pilot-close-recording').addEventListener('click', () => {
2370
+ document.getElementById('chrome-debug-close-recording').addEventListener('click', () => {
2202
2371
  if (isRecording) {
2203
2372
  if (confirm('Stop recording and close?')) {
2204
2373
  stopRecording();
@@ -2211,7 +2380,7 @@ function showRecordingInterface() {
2211
2380
  }
2212
2381
  });
2213
2382
 
2214
- document.getElementById('chrome-pilot-record-btn').addEventListener('click', () => {
2383
+ document.getElementById('chrome-debug-record-btn').addEventListener('click', () => {
2215
2384
  if (!isRecording) {
2216
2385
  startRecording();
2217
2386
  } else {
@@ -2222,8 +2391,8 @@ function showRecordingInterface() {
2222
2391
 
2223
2392
  // Start recording from content script
2224
2393
  function startRecording() {
2225
- const recordBtn = document.getElementById('chrome-pilot-record-btn');
2226
- const statusDiv = document.getElementById('chrome-pilot-recording-status');
2394
+ const recordBtn = document.getElementById('chrome-debug-record-btn');
2395
+ const statusDiv = document.getElementById('chrome-debug-recording-status');
2227
2396
 
2228
2397
  recordBtn.disabled = true;
2229
2398
  recordBtn.textContent = 'Starting...';
@@ -2250,7 +2419,7 @@ function startRecording() {
2250
2419
  // Start performance monitoring when recording begins
2251
2420
  if (performanceMonitor) {
2252
2421
  performanceMonitor.startMonitoring();
2253
- console.log('[ChromeDebug MCP] Performance monitoring started with recording');
2422
+ // console.log('[ChromeDebug MCP] Performance monitoring started with recording');
2254
2423
  }
2255
2424
 
2256
2425
  // Start timer display
@@ -2270,9 +2439,9 @@ function startRecording() {
2270
2439
 
2271
2440
  // Stop recording
2272
2441
  function stopRecording() {
2273
- const recordBtn = document.getElementById('chrome-pilot-record-btn');
2274
- const statusDiv = document.getElementById('chrome-pilot-recording-status');
2275
- const resultDiv = document.getElementById('chrome-pilot-recording-result');
2442
+ const recordBtn = document.getElementById('chrome-debug-record-btn');
2443
+ const statusDiv = document.getElementById('chrome-debug-recording-status');
2444
+ const resultDiv = document.getElementById('chrome-debug-recording-result');
2276
2445
 
2277
2446
  recordBtn.disabled = true;
2278
2447
  recordBtn.textContent = 'Stopping...';
@@ -2311,7 +2480,7 @@ function stopRecording() {
2311
2480
  // Stop performance monitoring when recording ends
2312
2481
  if (performanceMonitor) {
2313
2482
  performanceMonitor.stopMonitoring();
2314
- console.log('[ChromeDebug MCP] Performance monitoring stopped with recording');
2483
+ // console.log('[ChromeDebug MCP] Performance monitoring stopped with recording');
2315
2484
  }
2316
2485
  });
2317
2486
  }
@@ -2350,7 +2519,7 @@ function showFrameFlash() {
2350
2519
  /*
2351
2520
  async function initializeFullDataRecordingSystem() {
2352
2521
  try {
2353
- console.log('[ChromeDebug MCP] Initializing full data recording system...');
2522
+ // console.log('[ChromeDebug MCP] Initializing full data recording system...');
2354
2523
 
2355
2524
  // Initialize core components
2356
2525
  if (typeof DataBuffer !== 'undefined') {
@@ -2397,7 +2566,7 @@ async function initializeFullDataRecordingSystem() {
2397
2566
  if (dataBuffer) {
2398
2567
  try {
2399
2568
  await dataBuffer.addBatch(events);
2400
- console.log(`[Chrome Debug] Persisted ${events.length} function traces`);
2569
+ // console.log(`[Chrome Debug] Persisted ${events.length} function traces`);
2401
2570
  } catch (error) {
2402
2571
  console.error('[ChromeDebug MCP] Failed to persist function traces:', error);
2403
2572
  }
@@ -2477,10 +2646,10 @@ async function initializeFullDataRecordingSystem() {
2477
2646
  }
2478
2647
  };
2479
2648
 
2480
- console.log('[ChromeDebug MCP] ChromePilotTracker API exposed for manual instrumentation');
2649
+ // console.log('[ChromeDebug MCP] ChromePilotTracker API exposed for manual instrumentation');
2481
2650
  }
2482
2651
 
2483
- console.log('[ChromeDebug MCP] Full data recording system initialized successfully');
2652
+ // console.log('[ChromeDebug MCP] Full data recording system initialized successfully');
2484
2653
  return true;
2485
2654
 
2486
2655
  } catch (error) {
@@ -2497,7 +2666,7 @@ async function startFullDataRecording(config) {
2497
2666
  return;
2498
2667
  }
2499
2668
 
2500
- console.log('[ChromeDebug MCP] Starting full data recording with config:', config);
2669
+ // console.log('[ChromeDebug MCP] Starting full data recording with config:', config);
2501
2670
 
2502
2671
  // Initialize system if not already done
2503
2672
  if (!dataBuffer) {
@@ -2527,7 +2696,7 @@ async function startFullDataRecording(config) {
2527
2696
  // Start performance monitoring (lazy loading - only when recording)
2528
2697
  if (performanceMonitor) {
2529
2698
  performanceMonitor.startMonitoring();
2530
- console.log('[ChromeDebug MCP] Performance monitoring started');
2699
+ // console.log('[ChromeDebug MCP] Performance monitoring started');
2531
2700
  }
2532
2701
 
2533
2702
  // Configure and start DOM tracking
@@ -2540,7 +2709,7 @@ async function startFullDataRecording(config) {
2540
2709
  mutationThrottle: config.instrumentationLevel <= 2 ? 20 : 50 // Throttle for lower levels
2541
2710
  });
2542
2711
  domTracker.startTracking();
2543
- console.log('[ChromeDebug MCP] DOM tracking started');
2712
+ // console.log('[ChromeDebug MCP] DOM tracking started');
2544
2713
  }
2545
2714
 
2546
2715
  // Configure and start network tracking
@@ -2555,7 +2724,7 @@ async function startFullDataRecording(config) {
2555
2724
  maxBodySize: config.instrumentationLevel >= 4 ? 50 * 1024 : 10 * 1024
2556
2725
  });
2557
2726
  networkTracker.startTracking();
2558
- console.log('[ChromeDebug MCP] Network tracking started');
2727
+ // console.log('[ChromeDebug MCP] Network tracking started');
2559
2728
  }
2560
2729
 
2561
2730
  // Configure and start function tracking
@@ -2572,7 +2741,7 @@ async function startFullDataRecording(config) {
2572
2741
  if (chrome.runtime.lastError) {
2573
2742
  console.error('[ChromeDebug MCP] Failed to send function traces to background:', chrome.runtime.lastError);
2574
2743
  } else {
2575
- console.log(`[Chrome Debug] Sent ${data.length} function traces to background for upload`);
2744
+ // console.log(`[Chrome Debug] Sent ${data.length} function traces to background for upload`);
2576
2745
  }
2577
2746
  });
2578
2747
  }
@@ -2601,7 +2770,7 @@ async function startFullDataRecording(config) {
2601
2770
  window.ChromePilotTracker._functionTracker = functionTracker;
2602
2771
  }
2603
2772
 
2604
- console.log('[ChromeDebug MCP] Function tracking started');
2773
+ // console.log('[ChromeDebug MCP] Function tracking started');
2605
2774
  }
2606
2775
 
2607
2776
  // Start upload manager via background script
@@ -2611,7 +2780,7 @@ async function startFullDataRecording(config) {
2611
2780
  if (chrome.runtime.lastError) {
2612
2781
  console.error('[ChromeDebug MCP] Error starting upload manager:', chrome.runtime.lastError.message);
2613
2782
  } else {
2614
- console.log('[ChromeDebug MCP] Upload manager started via background script');
2783
+ // console.log('[ChromeDebug MCP] Upload manager started via background script');
2615
2784
  }
2616
2785
  });
2617
2786
 
@@ -2619,7 +2788,7 @@ async function startFullDataRecording(config) {
2619
2788
 
2620
2789
  // Full data recording indicator removed - functionality disabled
2621
2790
 
2622
- console.log('[ChromeDebug MCP] Full data recording started successfully:', recordingId);
2791
+ // console.log('[ChromeDebug MCP] Full data recording started successfully:', recordingId);
2623
2792
 
2624
2793
  } catch (error) {
2625
2794
  console.error('[ChromeDebug MCP] Failed to start full data recording:', error);
@@ -2635,17 +2804,17 @@ async function stopFullDataRecording() {
2635
2804
  return;
2636
2805
  }
2637
2806
 
2638
- console.log('[ChromeDebug MCP] Stopping full data recording...');
2807
+ // console.log('[ChromeDebug MCP] Stopping full data recording...');
2639
2808
 
2640
2809
  // Stop all trackers
2641
2810
  if (domTracker) {
2642
2811
  domTracker.stopTracking();
2643
- console.log('[ChromeDebug MCP] DOM tracking stopped');
2812
+ // console.log('[ChromeDebug MCP] DOM tracking stopped');
2644
2813
  }
2645
2814
 
2646
2815
  if (networkTracker) {
2647
2816
  networkTracker.stopTracking();
2648
- console.log('[ChromeDebug MCP] Network tracking stopped');
2817
+ // console.log('[ChromeDebug MCP] Network tracking stopped');
2649
2818
  }
2650
2819
 
2651
2820
  if (functionTracker) {
@@ -2656,13 +2825,13 @@ async function stopFullDataRecording() {
2656
2825
  window.ChromePilotTracker._setRecordingStatus(false);
2657
2826
  }
2658
2827
 
2659
- console.log('[ChromeDebug MCP] Function tracking stopped');
2828
+ // console.log('[ChromeDebug MCP] Function tracking stopped');
2660
2829
  }
2661
2830
 
2662
2831
  // Stop performance monitoring
2663
2832
  if (performanceMonitor) {
2664
2833
  performanceMonitor.stopMonitoring();
2665
- console.log('[ChromeDebug MCP] Performance monitoring stopped');
2834
+ // console.log('[ChromeDebug MCP] Performance monitoring stopped');
2666
2835
  }
2667
2836
 
2668
2837
  // Create final batch for any remaining events
@@ -2673,7 +2842,7 @@ async function stopFullDataRecording() {
2673
2842
  if (result.currentRecordingId) {
2674
2843
  // Create a batch with any remaining events
2675
2844
  await dataBuffer.createBatch(result.currentRecordingId);
2676
- console.log('[ChromeDebug MCP] Final batch created for remaining events');
2845
+ // console.log('[ChromeDebug MCP] Final batch created for remaining events');
2677
2846
  }
2678
2847
  } catch (error) {
2679
2848
  console.warn('[ChromeDebug MCP] Could not create final batch:', error);
@@ -2689,7 +2858,7 @@ async function stopFullDataRecording() {
2689
2858
  if (chrome.runtime.lastError) {
2690
2859
  console.error('[ChromeDebug MCP] Error finalizing uploads:', chrome.runtime.lastError.message);
2691
2860
  } else {
2692
- console.log('[ChromeDebug MCP] Upload manager stopped via background script');
2861
+ // console.log('[ChromeDebug MCP] Upload manager stopped via background script');
2693
2862
  }
2694
2863
  resolve();
2695
2864
  });
@@ -2700,7 +2869,7 @@ async function stopFullDataRecording() {
2700
2869
 
2701
2870
  // Full data recording indicator removed - functionality disabled
2702
2871
 
2703
- console.log('[ChromeDebug MCP] Full data recording stopped successfully');
2872
+ // console.log('[ChromeDebug MCP] Full data recording stopped successfully');
2704
2873
 
2705
2874
  } catch (error) {
2706
2875
  console.error('[ChromeDebug MCP] Failed to stop full data recording:', error);
@@ -2734,6 +2903,7 @@ class ScreenCaptureVisualFeedback {
2734
2903
  init() {
2735
2904
  // Listen for screen capture events
2736
2905
  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
2906
+ // console.log('[ScreenCapture] Received message:', message.type, message);
2737
2907
  switch (message.type) {
2738
2908
  case 'start-screen-capture-tracking':
2739
2909
  this.handleStartScreenCapture(message);
@@ -2747,11 +2917,27 @@ class ScreenCaptureVisualFeedback {
2747
2917
  case 'stop-screen-capture-tracking':
2748
2918
  this.handleStopScreenCapture(message);
2749
2919
  break;
2920
+ case 'recording-complete-show-ui':
2921
+ // Show completion UI when stopped from popup (not from mini menu button)
2922
+ // console.log('[ScreenCapture] Processing recording-complete-show-ui, sessionId:', message.sessionId, 'actionCount:', this.actionCount);
2923
+ if (message.sessionId) {
2924
+ // console.log('[ScreenCapture] Calling showScreenRecordingComplete with sessionId:', message.sessionId);
2925
+ this.showScreenRecordingComplete(message.sessionId, this.actionCount);
2926
+ } else {
2927
+ // console.log('[ScreenCapture] ERROR: No sessionId in recording-complete-show-ui message!');
2928
+ }
2929
+ break;
2930
+ default:
2931
+ // Log unknown message types for debugging
2932
+ if (message.type && message.type.includes('screen-capture') || message.type && message.type.includes('recording')) {
2933
+ // console.log('[ScreenCapture] Unknown screen capture message type:', message.type);
2934
+ }
2750
2935
  }
2751
2936
  });
2752
2937
  }
2753
2938
 
2754
2939
  handleStartScreenCapture(message) {
2940
+ // console.log('[ScreenCapture] Starting new recording, current indicator exists:', !!this.recordingIndicatorElement);
2755
2941
  this.isRecording = true;
2756
2942
  this.actionCount = 0;
2757
2943
  this.showRecordingIndicator();
@@ -2798,9 +2984,11 @@ class ScreenCaptureVisualFeedback {
2798
2984
 
2799
2985
  handleStopScreenCapture(message) {
2800
2986
  this.isRecording = false;
2801
- this.hideRecordingIndicator();
2987
+ // DON'T hide indicator here - let the completion screen handle it
2988
+ // this.hideRecordingIndicator();
2802
2989
  this.hideActionCounter();
2803
- this.cleanup();
2990
+ // Don't cleanup yet - we want to keep the indicator visible
2991
+ // this.cleanup();
2804
2992
  }
2805
2993
 
2806
2994
  showClickHighlight(x, y) {
@@ -2836,80 +3024,96 @@ class ScreenCaptureVisualFeedback {
2836
3024
  }
2837
3025
 
2838
3026
  showRecordingIndicator() {
2839
- if (!this.recordingIndicatorElement) {
2840
- // Add required CSS styles if not already added
2841
- if (!document.getElementById('screen-capture-styles')) {
2842
- const style = document.createElement('style');
2843
- style.id = 'screen-capture-styles';
2844
- style.textContent = `
2845
- @keyframes pulse {
2846
- 0% { opacity: 1; }
2847
- 50% { opacity: 0.5; }
2848
- 100% { opacity: 1; }
2849
- }
2850
- @keyframes screen-capture-pulse {
2851
- 0% { opacity: 1; transform: scale(1); }
2852
- 50% { opacity: 0.7; transform: scale(1.1); }
2853
- 100% { opacity: 1; transform: scale(1); }
2854
- }
2855
- .screen-capture-click-highlight {
2856
- position: fixed;
2857
- width: 40px;
2858
- height: 40px;
2859
- border: 3px solid #4CAF50;
2860
- border-radius: 50%;
2861
- background: rgba(76, 175, 80, 0.3);
2862
- transform: translate(-50%, -50%);
2863
- pointer-events: none;
2864
- z-index: 2147483646;
2865
- animation: screen-capture-ripple 0.5s ease-out;
3027
+ // CRITICAL FIX: Clear any existing countdown interval FIRST
3028
+ if (this.countdownInterval) {
3029
+ // console.log('[ScreenCapture] Clearing existing countdown interval');
3030
+ clearInterval(this.countdownInterval);
3031
+ this.countdownInterval = null;
3032
+ }
3033
+
3034
+ // CRITICAL FIX: If old indicator exists (showing completion), remove it completely
3035
+ // This ensures the old popup closes immediately before showing the new countdown
3036
+ if (this.recordingIndicatorElement && this.recordingIndicatorElement.parentNode) {
3037
+ // console.log('[ScreenCapture] Removing old indicator element from DOM');
3038
+ this.recordingIndicatorElement.parentNode.removeChild(this.recordingIndicatorElement);
3039
+ this.recordingIndicatorElement = null;
3040
+ // console.log('[ScreenCapture] Old indicator removed successfully');
3041
+ } else {
3042
+ // console.log('[ScreenCapture] No old indicator to remove, creating fresh');
3043
+ }
3044
+
3045
+ // Add required CSS styles if not already added
3046
+ if (!document.getElementById('screen-capture-styles')) {
3047
+ const style = document.createElement('style');
3048
+ style.id = 'screen-capture-styles';
3049
+ style.textContent = `
3050
+ @keyframes pulse {
3051
+ 0% { opacity: 1; }
3052
+ 50% { opacity: 0.5; }
3053
+ 100% { opacity: 1; }
3054
+ }
3055
+ @keyframes screen-capture-pulse {
3056
+ 0% { opacity: 1; transform: scale(1); }
3057
+ 50% { opacity: 0.7; transform: scale(1.1); }
3058
+ 100% { opacity: 1; transform: scale(1); }
3059
+ }
3060
+ .screen-capture-click-highlight {
3061
+ position: fixed;
3062
+ width: 40px;
3063
+ height: 40px;
3064
+ border: 3px solid #4CAF50;
3065
+ border-radius: 50%;
3066
+ background: rgba(76, 175, 80, 0.3);
3067
+ transform: translate(-50%, -50%);
3068
+ pointer-events: none;
3069
+ z-index: 2147483646;
3070
+ animation: screen-capture-ripple 0.5s ease-out;
3071
+ }
3072
+ @keyframes screen-capture-ripple {
3073
+ 0% {
3074
+ transform: translate(-50%, -50%) scale(0);
3075
+ opacity: 1;
2866
3076
  }
2867
- @keyframes screen-capture-ripple {
2868
- 0% {
2869
- transform: translate(-50%, -50%) scale(0);
2870
- opacity: 1;
2871
- }
2872
- 100% {
2873
- transform: translate(-50%, -50%) scale(1);
2874
- opacity: 0;
2875
- }
3077
+ 100% {
3078
+ transform: translate(-50%, -50%) scale(1);
3079
+ opacity: 0;
2876
3080
  }
2877
- `;
2878
- document.head.appendChild(style);
2879
- }
2880
-
2881
- this.recordingIndicatorElement = document.createElement('div');
2882
- this.recordingIndicatorElement.className = 'screen-capture-recording-indicator-unified';
2883
-
2884
- // Use inline styles to match workflow recording exactly
2885
- Object.assign(this.recordingIndicatorElement.style, {
2886
- position: 'fixed',
2887
- bottom: '80px', // Keep different from workflow to avoid collision
2888
- left: '20px',
2889
- background: 'rgba(0, 0, 0, 0.9)',
2890
- color: 'white',
2891
- padding: '12px 20px',
2892
- borderRadius: '25px',
2893
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
2894
- fontSize: '14px',
2895
- fontWeight: '500',
2896
- zIndex: '2147483647',
2897
- display: 'flex',
2898
- alignItems: 'center',
2899
- gap: '8px',
2900
- boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
2901
- backdropFilter: 'blur(10px)',
2902
- WebkitBackdropFilter: 'blur(10px)',
2903
- pointerEvents: 'none',
2904
- userSelect: 'none'
2905
- });
3081
+ }
3082
+ `;
3083
+ document.head.appendChild(style);
3084
+ }
3085
+
3086
+ // Always create fresh element for new recording
3087
+ this.recordingIndicatorElement = document.createElement('div');
3088
+ this.recordingIndicatorElement.className = 'screen-capture-recording-indicator-unified';
3089
+
3090
+ // Use inline styles to match workflow recording exactly
3091
+ Object.assign(this.recordingIndicatorElement.style, {
3092
+ position: 'fixed',
3093
+ bottom: '80px', // Keep different from workflow to avoid collision
3094
+ left: '20px',
3095
+ background: 'rgba(0, 0, 0, 0.9)',
3096
+ color: 'white',
3097
+ padding: '12px 20px',
3098
+ borderRadius: '25px',
3099
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
3100
+ fontSize: '14px',
3101
+ fontWeight: '500',
3102
+ zIndex: '2147483647',
3103
+ display: 'flex',
3104
+ alignItems: 'center',
3105
+ gap: '8px',
3106
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
3107
+ backdropFilter: 'blur(10px)',
3108
+ WebkitBackdropFilter: 'blur(10px)',
3109
+ pointerEvents: 'none',
3110
+ userSelect: 'none'
3111
+ });
2906
3112
 
2907
- // Start with countdown
2908
- this.startCountdownSequence();
2909
- document.body.appendChild(this.recordingIndicatorElement);
2910
- }
3113
+ document.body.appendChild(this.recordingIndicatorElement);
2911
3114
 
2912
- this.recordingIndicatorElement.style.display = 'flex';
3115
+ // Start countdown sequence
3116
+ this.startCountdownSequence();
2913
3117
  }
2914
3118
 
2915
3119
  startCountdownSequence() {
@@ -2932,18 +3136,223 @@ class ScreenCaptureVisualFeedback {
2932
3136
  <span class="action-count-badge" style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 12px; font-size: 12px;">0 actions</span>
2933
3137
  `;
2934
3138
  } else {
2935
- // Switch to recording display
3139
+ // Countdown complete! Notify background to start inactivity monitoring NOW
3140
+ if (isExtensionValid()) {
3141
+ chrome.runtime.sendMessage({ action: 'countdownComplete' }).catch(err => {
3142
+ console.warn('[ScreenCapture] Could not send countdownComplete:', err);
3143
+ });
3144
+ }
3145
+
3146
+ // Switch to recording display with two-row layout
3147
+ this.recordingIndicatorElement.style.pointerEvents = 'auto'; // Enable clicking
2936
3148
  this.recordingIndicatorElement.innerHTML = `
2937
- <span style="color: #4CAF50; font-size: 20px; animation: pulse 1.5s infinite;">●</span>
2938
- <span>Recording Screen Capture...</span>
2939
- <span class="action-count-badge" style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 12px; font-size: 12px;">0 actions</span>
3149
+ <div style="display: flex; flex-direction: column; gap: 8px;">
3150
+ <!-- Row 1: Status and primary actions -->
3151
+ <div style="display: flex; align-items: center; gap: 8px;">
3152
+ <span style="color: #4CAF50; font-size: 18px; animation: pulse 1.5s infinite;">●</span>
3153
+ <span style="font-size: 13px; font-weight: 500;">Recording Screen Capture...</span>
3154
+ <span class="action-count-badge" style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 10px; font-size: 11px;">0 actions</span>
3155
+ <div style="flex: 1;"></div>
3156
+ <button id="screen-stop-btn" style="background: #f44336; color: white; border: none; padding: 6px 14px; border-radius: 15px; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit;">Stop</button>
3157
+ <button id="screen-close-btn" style="background: transparent; color: white; border: none; padding: 4px 8px; font-size: 16px; cursor: pointer; font-family: inherit; opacity: 0.7;" title="Close notification">×</button>
3158
+ </div>
3159
+ <!-- Row 2: Frame count, countdown, and disable button -->
3160
+ <div style="display: flex; align-items: center; gap: 10px; font-size: 11px; color: rgba(255,255,255,0.8); padding-left: 26px;">
3161
+ <span class="frame-count-badge">0 frames</span>
3162
+ <span style="opacity: 0.5;">|</span>
3163
+ <span class="inactivity-countdown-badge" style="color: rgba(255,152,0,0.9);">⏱ --</span>
3164
+ <button id="disable-inactivity-btn" style="background: rgba(255,152,0,0.4); color: white; border: none; padding: 4px 10px; border-radius: 10px; font-size: 11px; cursor: pointer; font-family: inherit;" title="Disable auto-stop timeout">Disable</button>
3165
+ </div>
3166
+ </div>
2940
3167
  `;
2941
3168
  clearInterval(this.countdownInterval);
2942
3169
  this.countdownInterval = null;
3170
+
3171
+ // Add stop button click handler
3172
+ const stopBtn = document.getElementById('screen-stop-btn');
3173
+ const closeBtn = document.getElementById('screen-close-btn');
3174
+
3175
+ if (stopBtn) {
3176
+ stopBtn.addEventListener('click', async (e) => {
3177
+ e.stopPropagation();
3178
+ stopBtn.disabled = true;
3179
+ stopBtn.textContent = 'Stopping...';
3180
+
3181
+ // Send message to background to stop recording (correct action name)
3182
+ chrome.runtime.sendMessage({ action: 'stopRecording' }, (response) => {
3183
+ if (response && response.success && response.sessionId) {
3184
+ // Show completion with action buttons
3185
+ this.showScreenRecordingComplete(response.sessionId, this.actionCount);
3186
+ } else {
3187
+ console.error('[ScreenRecording] Failed to stop:', response?.error);
3188
+ // Don't hide indicator, just show error
3189
+ stopBtn.textContent = 'Error';
3190
+ stopBtn.style.background = '#666';
3191
+ }
3192
+ });
3193
+ });
3194
+ }
3195
+
3196
+ if (closeBtn) {
3197
+ closeBtn.addEventListener('click', (e) => {
3198
+ e.stopPropagation();
3199
+ this.hideRecordingIndicator();
3200
+ });
3201
+ }
3202
+
3203
+ // Add disable inactivity timeout button handler
3204
+ const disableBtn = document.getElementById('disable-inactivity-btn');
3205
+ if (disableBtn) {
3206
+ disableBtn.addEventListener('click', async (e) => {
3207
+ e.stopPropagation();
3208
+ try {
3209
+ const response = await chrome.runtime.sendMessage({ action: 'toggleInactivityTimeout' });
3210
+ if (response && response.success) {
3211
+ const countdownBadge = this.recordingIndicatorElement?.querySelector('.inactivity-countdown-badge');
3212
+ if (response.disabled) {
3213
+ // Timeout disabled - show Enable button (green)
3214
+ disableBtn.textContent = 'Enable';
3215
+ disableBtn.title = 'Enable auto-stop timeout';
3216
+ disableBtn.style.background = 'rgba(76, 175, 80, 0.5)';
3217
+ if (countdownBadge) {
3218
+ countdownBadge.textContent = '⏱ OFF';
3219
+ countdownBadge.style.color = 'rgba(76, 175, 80, 0.9)';
3220
+ }
3221
+ } else {
3222
+ // Timeout enabled - show Disable button (orange)
3223
+ disableBtn.textContent = 'Disable';
3224
+ disableBtn.title = 'Disable auto-stop timeout';
3225
+ disableBtn.style.background = 'rgba(255,152,0,0.4)';
3226
+ if (countdownBadge) {
3227
+ countdownBadge.style.color = 'rgba(255,152,0,0.9)';
3228
+ }
3229
+ }
3230
+ }
3231
+ } catch (err) {
3232
+ console.warn('[ScreenCapture] Could not toggle inactivity timeout:', err);
3233
+ }
3234
+ });
3235
+ }
2943
3236
  }
2944
3237
  }, 1000);
2945
3238
  }
2946
3239
 
3240
+ showScreenRecordingComplete(sessionId, actionCount) {
3241
+ if (!this.recordingIndicatorElement) return;
3242
+
3243
+ this.recordingIndicatorElement.innerHTML = `
3244
+ <div style="display: flex; flex-direction: column; gap: 10px; position: relative; padding-right: 30px;">
3245
+ <button class="sc-close-complete" style="position: absolute; top: -8px; right: -8px; background: transparent; color: white; border: none; padding: 4px 8px; font-size: 20px; cursor: pointer; font-family: inherit; opacity: 0.7; line-height: 1;" title="Close notification">×</button>
3246
+
3247
+ <div style="display: flex; align-items: center; gap: 8px;">
3248
+ <span style="color: #4CAF50; font-size: 16px;">🎬</span>
3249
+ <span style="font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 400px;" title="${sessionId}">${sessionId} (frames)</span>
3250
+ </div>
3251
+
3252
+ <div style="font-size: 11px; color: rgba(255,255,255,0.7); margin-top: -5px;">
3253
+ ${actionCount} actions • ${new Date().toLocaleString()}
3254
+ </div>
3255
+
3256
+ <div style="display: flex; gap: 6px; flex-wrap: wrap;">
3257
+ <button class="sc-copy-id" data-id="${sessionId}" style="background: #2196F3; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Copy ID</button>
3258
+ <button class="sc-copy-prompt" data-id="${sessionId}" style="background: #4CAF50; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Copy Prompt</button>
3259
+ <button class="sc-view" data-id="${sessionId}" style="background: #9C27B0; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">View</button>
3260
+ <button class="sc-delete" data-id="${sessionId}" style="background: #f44336; color: white; border: none; padding: 6px 12px; border-radius: 12px; font-size: 11px; cursor: pointer; font-family: inherit; font-weight: 500;">Delete</button>
3261
+ </div>
3262
+ </div>
3263
+ `;
3264
+
3265
+ // Add event listeners for action buttons
3266
+ const copyIdBtn = this.recordingIndicatorElement.querySelector('.sc-copy-id');
3267
+ const copyPromptBtn = this.recordingIndicatorElement.querySelector('.sc-copy-prompt');
3268
+ const viewBtn = this.recordingIndicatorElement.querySelector('.sc-view');
3269
+ const deleteBtn = this.recordingIndicatorElement.querySelector('.sc-delete');
3270
+ const closeBtn = this.recordingIndicatorElement.querySelector('.sc-close-complete');
3271
+
3272
+ if (copyIdBtn) {
3273
+ copyIdBtn.addEventListener('click', async () => {
3274
+ try {
3275
+ await navigator.clipboard.writeText(sessionId);
3276
+ copyIdBtn.textContent = 'Copied!';
3277
+ setTimeout(() => copyIdBtn.textContent = 'Copy ID', 2000);
3278
+ } catch (error) {
3279
+ console.error('[ScreenRecording] Failed to copy ID:', error);
3280
+ }
3281
+ });
3282
+ }
3283
+
3284
+ if (copyPromptBtn) {
3285
+ copyPromptBtn.addEventListener('click', async () => {
3286
+ const prompt = `Please use the chrome_debug_show_frames function in Chrome Debug to display the screen recording "${sessionId}".`;
3287
+ try {
3288
+ await navigator.clipboard.writeText(prompt);
3289
+ copyPromptBtn.textContent = 'Copied!';
3290
+ setTimeout(() => copyPromptBtn.textContent = 'Copy Prompt', 2000);
3291
+ } catch (error) {
3292
+ console.error('[ScreenRecording] Failed to copy prompt:', error);
3293
+ }
3294
+ });
3295
+ }
3296
+
3297
+ if (viewBtn) {
3298
+ viewBtn.addEventListener('click', () => {
3299
+ // Ask background to open frame editor (content scripts can't create tabs)
3300
+ chrome.runtime.sendMessage({
3301
+ action: 'openFrameEditor',
3302
+ sessionId: sessionId
3303
+ });
3304
+ });
3305
+ }
3306
+
3307
+ if (deleteBtn) {
3308
+ deleteBtn.addEventListener('click', async () => {
3309
+ if (confirm('Delete this screen recording?')) {
3310
+ // Hide immediately for better UX
3311
+ this.hideRecordingIndicator();
3312
+
3313
+ // Show brief "Deleting..." toast
3314
+ const toast = document.createElement('div');
3315
+ Object.assign(toast.style, {
3316
+ position: 'fixed',
3317
+ bottom: '80px',
3318
+ left: '20px',
3319
+ background: 'rgba(0, 0, 0, 0.9)',
3320
+ color: 'white',
3321
+ padding: '12px 20px',
3322
+ borderRadius: '20px',
3323
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
3324
+ fontSize: '13px',
3325
+ zIndex: '2147483646'
3326
+ });
3327
+ toast.textContent = 'Deleting...';
3328
+ document.body.appendChild(toast);
3329
+
3330
+ chrome.runtime.sendMessage({
3331
+ action: 'deleteScreenRecording',
3332
+ sessionId: sessionId
3333
+ }, (response) => {
3334
+ // Update toast with result
3335
+ if (response && response.success) {
3336
+ toast.textContent = '✓ Recording deleted';
3337
+ toast.style.background = 'rgba(76, 175, 80, 0.9)';
3338
+ } else {
3339
+ toast.textContent = '✗ Delete failed';
3340
+ toast.style.background = 'rgba(244, 67, 54, 0.9)';
3341
+ }
3342
+ // Remove toast after 2 seconds
3343
+ setTimeout(() => toast.remove(), 2000);
3344
+ });
3345
+ }
3346
+ });
3347
+ }
3348
+
3349
+ if (closeBtn) {
3350
+ closeBtn.addEventListener('click', () => {
3351
+ this.hideRecordingIndicator();
3352
+ });
3353
+ }
3354
+ }
3355
+
2947
3356
  hideRecordingIndicator() {
2948
3357
  // Clear countdown interval if running
2949
3358
  if (this.countdownInterval) {
@@ -3077,16 +3486,125 @@ setTimeout(() => {
3077
3486
  }
3078
3487
  };
3079
3488
 
3080
- console.log('[ChromeDebug MCP] ChromePilotTracker initialized for workflow recording');
3489
+ // console.log('[ChromeDebug MCP] ChromePilotTracker initialized for workflow recording');
3081
3490
  }
3082
3491
 
3083
3492
  // Initialize minimal workflow recording support
3084
- console.log('[ChromeDebug MCP] Basic workflow recording ready (lightweight mode)');
3493
+ // console.log('[ChromeDebug MCP] Basic workflow recording ready (lightweight mode)');
3085
3494
  }
3086
3495
  }, 500);
3087
3496
 
3088
3497
  // Full data recording system will be initialized on-demand when recording begins
3089
3498
  // This prevents unnecessary resource usage on every page load
3090
3499
 
3500
+ // =============================================================================
3501
+ // INACTIVITY TRACKER - Auto-stop recording if user is inactive
3502
+ // =============================================================================
3503
+ (function initInactivityTracker() {
3504
+ let lastActivityTime = Date.now();
3505
+ let isTrackingActivity = false;
3506
+ let inactivityCheckInterval = null;
3507
+
3508
+ // Debounce activity updates to avoid flooding background script
3509
+ let activityDebounceTimer = null;
3510
+ const ACTIVITY_DEBOUNCE_MS = 1000; // Report activity at most once per second
3511
+
3512
+ function reportActivity() {
3513
+ if (!isTrackingActivity) return;
3514
+
3515
+ lastActivityTime = Date.now();
3516
+
3517
+ // Debounced report to background
3518
+ if (activityDebounceTimer) return;
3519
+ activityDebounceTimer = setTimeout(() => {
3520
+ activityDebounceTimer = null;
3521
+ if (isExtensionValid()) {
3522
+ chrome.runtime.sendMessage({
3523
+ action: 'userActivity',
3524
+ timestamp: lastActivityTime
3525
+ }).catch(() => {});
3526
+ }
3527
+ }, ACTIVITY_DEBOUNCE_MS);
3528
+ }
3529
+
3530
+ // Activity event listeners (passive for performance)
3531
+ const activityEvents = ['mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart', 'click'];
3532
+
3533
+ function startTracking() {
3534
+ if (isTrackingActivity) return;
3535
+ isTrackingActivity = true;
3536
+ lastActivityTime = Date.now();
3537
+
3538
+ activityEvents.forEach(event => {
3539
+ document.addEventListener(event, reportActivity, { passive: true, capture: true });
3540
+ });
3541
+
3542
+ // Send IMMEDIATE activity report on start to sync with background timer
3543
+ // This prevents premature auto-stop due to setup delay
3544
+ if (isExtensionValid()) {
3545
+ chrome.runtime.sendMessage({
3546
+ action: 'userActivity',
3547
+ timestamp: lastActivityTime
3548
+ }).catch(() => {});
3549
+ }
3550
+ }
3551
+
3552
+ function stopTracking() {
3553
+ if (!isTrackingActivity) return;
3554
+ isTrackingActivity = false;
3555
+
3556
+ activityEvents.forEach(event => {
3557
+ document.removeEventListener(event, reportActivity, { capture: true });
3558
+ });
3559
+
3560
+ if (activityDebounceTimer) {
3561
+ clearTimeout(activityDebounceTimer);
3562
+ activityDebounceTimer = null;
3563
+ }
3564
+ }
3565
+
3566
+ // Listen for start/stop tracking messages from background
3567
+ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
3568
+ if (message.action === 'startActivityTracking') {
3569
+ startTracking();
3570
+ sendResponse({ success: true });
3571
+ } else if (message.action === 'stopActivityTracking') {
3572
+ stopTracking();
3573
+ sendResponse({ success: true });
3574
+ } else if (message.action === 'updateInactivityCountdown') {
3575
+ // Update countdown badge in recording indicator
3576
+ const countdownBadge = document.querySelector('.inactivity-countdown-badge');
3577
+ if (countdownBadge) {
3578
+ if (message.disabled) {
3579
+ countdownBadge.textContent = '⏱ OFF';
3580
+ countdownBadge.style.background = 'rgba(76, 175, 80, 0.3)';
3581
+ countdownBadge.style.color = 'rgba(255,255,255,0.9)';
3582
+ } else {
3583
+ countdownBadge.textContent = `⏱ ${message.timeRemaining}s`;
3584
+ // Warning colors
3585
+ if (message.timeRemaining <= 3) {
3586
+ countdownBadge.style.background = 'rgba(244, 67, 54, 0.5)';
3587
+ countdownBadge.style.color = '#fff';
3588
+ } else if (message.timeRemaining <= 5) {
3589
+ countdownBadge.style.background = 'rgba(255, 152, 0, 0.5)';
3590
+ countdownBadge.style.color = '#fff';
3591
+ } else {
3592
+ countdownBadge.style.background = 'rgba(255, 152, 0, 0.3)';
3593
+ countdownBadge.style.color = 'rgba(255,255,255,0.9)';
3594
+ }
3595
+ }
3596
+ }
3597
+ sendResponse({ success: true });
3598
+ } else if (message.action === 'updateFrameCount') {
3599
+ // Update frame count badge in recording indicator
3600
+ const frameBadge = document.querySelector('.frame-count-badge');
3601
+ if (frameBadge) {
3602
+ frameBadge.textContent = `${message.frameCount} frames`;
3603
+ }
3604
+ sendResponse({ success: true });
3605
+ }
3606
+ });
3607
+ })();
3608
+
3091
3609
  } // End of initializeChromePilot function
3092
3610
  })(); // End of IIFE wrapper