vibesurf 0.1.21__py3-none-any.whl → 0.1.22__py3-none-any.whl

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.

Potentially problematic release.


This version of vibesurf might be problematic. Click here for more details.

vibe_surf/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.21'
32
- __version_tuple__ = version_tuple = (0, 1, 21)
31
+ __version__ = version = '0.1.22'
32
+ __version_tuple__ = version_tuple = (0, 1, 22)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -525,7 +525,7 @@ class BrowserUseAgent(Agent):
525
525
  signal_handler.register()
526
526
 
527
527
  try:
528
- self._log_agent_run()
528
+ await self._log_agent_run()
529
529
 
530
530
  self.logger.debug(
531
531
  f'🔧 Agent setup: Task ID {self.task_id[-4:]}, Session ID {self.session_id[-4:]}, Browser Session ID {self.browser_session.id[-4:] if self.browser_session else "None"}'
@@ -86,4 +86,5 @@ EXTEND_BU_SYSTEM_PROMPT = """
86
86
  * Regarding file operations, please note that you need the full relative path (including subfolders), not just the file name.
87
87
  * Especially when a file operation reports an error, please reflect whether the file path is not written correctly, such as the subfolder is not written.
88
88
  * If you are operating on files in the filesystem, be sure to use relative paths (relative to the workspace dir) instead of absolute paths.
89
+ * If you are typing in the search box, please use Enter key to search instead of clicking.
89
90
  """
@@ -43,6 +43,7 @@ from browser_use.browser.events import (
43
43
  TabClosedEvent,
44
44
  TabCreatedEvent,
45
45
  )
46
+ from browser_use.browser.profile import BrowserProfile, ProxySettings
46
47
 
47
48
  DEFAULT_BROWSER_PROFILE = AgentBrowserProfile()
48
49
 
@@ -94,7 +95,7 @@ class AgentBrowserSession(BrowserSession):
94
95
  deterministic_rendering: bool | None = None,
95
96
  allowed_domains: list[str] | None = None,
96
97
  keep_alive: bool | None = None,
97
- proxy: any | None = None,
98
+ proxy: ProxySettings | None = None,
98
99
  enable_default_extensions: bool | None = None,
99
100
  window_size: dict | None = None,
100
101
  window_position: dict | None = None,
@@ -135,12 +135,17 @@ class VibeSurfBackground {
135
135
  console.error('[VibeSurf] Failed to open side panel:', error);
136
136
 
137
137
  // Show notification with helpful message
138
- await chrome.notifications.create({
139
- type: 'basic',
140
- iconUrl: chrome.runtime.getURL('icons/icon48.png') || '',
141
- title: 'VibeSurf',
142
- message: 'Side panel failed. Please update Chrome to the latest version or try right-clicking the extension icon.'
143
- });
138
+ try {
139
+ await chrome.notifications.create({
140
+ type: 'basic',
141
+ iconUrl: '', // Use empty string to avoid icon issues
142
+ title: 'VibeSurf',
143
+ message: 'Side panel failed. Please update Chrome to the latest version or try right-clicking the extension icon.'
144
+ });
145
+ } catch (notifError) {
146
+ console.warn('[VibeSurf] Notification failed:', notifError);
147
+ // Don't throw, just log the warning
148
+ }
144
149
 
145
150
  // Fallback: try to open in new tab
146
151
  try {
@@ -365,56 +370,35 @@ class VibeSurfBackground {
365
370
  }
366
371
 
367
372
  async showNotification(data) {
368
- const { title, message, type = 'info', iconUrl = 'icons/icon48.png' } = data;
373
+ const { title, message, type = 'info', iconUrl } = data;
369
374
 
370
375
  // Map custom types to valid Chrome notification types
371
376
  const validType = ['basic', 'image', 'list', 'progress'].includes(type) ? type : 'basic';
372
377
 
373
- // Validate icon URL and provide fallback
374
- let validatedIconUrl = iconUrl;
375
- try {
376
- // Check if icon URL is accessible
377
- if (iconUrl && iconUrl !== 'icons/icon48.png') {
378
- // For custom icons, validate they exist
379
- const response = await fetch(iconUrl, { method: 'HEAD' });
380
- if (!response.ok) {
381
- validatedIconUrl = 'icons/icon48.png';
382
- }
383
- } else {
384
- // Use default icon, check if it exists
385
- const defaultIconUrl = chrome.runtime.getURL('icons/icon48.png');
386
- const response = await fetch(defaultIconUrl, { method: 'HEAD' });
387
- if (response.ok) {
388
- validatedIconUrl = defaultIconUrl;
389
- } else {
390
- // Fallback to logo.png if icon48.png doesn't exist
391
- const logoUrl = chrome.runtime.getURL('icons/logo.png');
392
- const logoResponse = await fetch(logoUrl, { method: 'HEAD' });
393
- if (logoResponse.ok) {
394
- validatedIconUrl = logoUrl;
395
- } else {
396
- // If no icons work, use empty string (browser will use default)
397
- validatedIconUrl = '';
398
- }
399
- }
400
- }
401
- } catch (error) {
402
- console.warn('[VibeSurf] Icon validation failed, using fallback:', error);
403
- // Use empty string as fallback (browser will use default icon)
404
- validatedIconUrl = '';
405
- }
378
+ // Simplified icon handling - try available icons without validation
379
+ let finalIconUrl = '';
380
+
381
+ // Try to use extension icons in order of preference, but don't validate with fetch
382
+ const iconCandidates = [
383
+ iconUrl ? chrome.runtime.getURL(iconUrl) : null,
384
+ chrome.runtime.getURL('icons/icon48.png'),
385
+ chrome.runtime.getURL('icons/logo.png')
386
+ ].filter(Boolean);
387
+
388
+ // Use the first candidate, or empty string as fallback
389
+ finalIconUrl = iconCandidates[0] || '';
406
390
 
407
391
  try {
408
392
  const notificationId = await chrome.notifications.create({
409
393
  type: validType,
410
- iconUrl: validatedIconUrl,
394
+ iconUrl: finalIconUrl,
411
395
  title: title || 'VibeSurf',
412
396
  message
413
397
  });
414
398
 
415
399
  return { notificationId };
416
400
  } catch (error) {
417
- console.error('[VibeSurf] Failed to create notification:', error);
401
+ console.warn('[VibeSurf] Notification with icon failed, trying without icon:', error);
418
402
  // Try once more with empty icon URL
419
403
  try {
420
404
  const notificationId = await chrome.notifications.create({
@@ -432,12 +416,17 @@ class VibeSurfBackground {
432
416
  }
433
417
 
434
418
  async showWelcomeNotification() {
435
- await chrome.notifications.create({
436
- type: 'basic',
437
- iconUrl: 'icons/icon48.png',
438
- title: 'Welcome to VibeSurf!',
439
- message: 'Click the VibeSurf icon in the toolbar to start automating your browsing tasks.'
440
- });
419
+ try {
420
+ await chrome.notifications.create({
421
+ type: 'basic',
422
+ iconUrl: '', // Use empty string to avoid icon issues
423
+ title: 'Welcome to VibeSurf!',
424
+ message: 'Click the VibeSurf icon in the toolbar to start automating your browsing tasks.'
425
+ });
426
+ } catch (error) {
427
+ console.warn('[VibeSurf] Welcome notification failed:', error);
428
+ // Don't throw, just log the warning
429
+ }
441
430
  }
442
431
 
443
432
  async checkBackendStatus(backendUrl = null) {
@@ -558,7 +547,40 @@ class VibeSurfBackground {
558
547
  return { success: false, error: 'No file URL provided' };
559
548
  }
560
549
 
550
+ // Add a unique request ID to track duplicate calls
551
+ const requestId = Date.now() + Math.random();
552
+ console.log(`[VibeSurf] openFileUrl called with ID: ${requestId}, URL: ${fileUrl}`);
553
+
561
554
  try {
555
+ // Validate URL format before attempting to open
556
+ try {
557
+ new URL(fileUrl);
558
+ } catch (urlError) {
559
+ console.warn('[VibeSurf] Invalid URL format:', fileUrl, urlError);
560
+ return { success: false, error: 'Invalid file URL format' };
561
+ }
562
+
563
+ // Check if this is an HTTP/HTTPS URL and handle it appropriately
564
+ if (fileUrl.startsWith('http://') || fileUrl.startsWith('https://')) {
565
+ console.log(`[VibeSurf] Detected HTTP(S) URL, creating tab for: ${fileUrl}`);
566
+
567
+ // Try to create a new tab with the URL
568
+ const tab = await chrome.tabs.create({
569
+ url: fileUrl,
570
+ active: true
571
+ });
572
+
573
+ if (tab && tab.id) {
574
+ console.log(`[VibeSurf] Successfully opened HTTP(S) URL in tab: ${tab.id} (request: ${requestId})`);
575
+ return { success: true, tabId: tab.id };
576
+ } else {
577
+ console.warn(`[VibeSurf] Tab creation returned but no tab ID for request: ${requestId}`);
578
+ return { success: false, error: 'Failed to create tab - no tab ID returned' };
579
+ }
580
+ }
581
+
582
+ // For file:// URLs, try the original approach
583
+ console.log(`[VibeSurf] Attempting to open file URL: ${fileUrl} (request: ${requestId})`);
562
584
 
563
585
  // Try to create a new tab with the file URL
564
586
  const tab = await chrome.tabs.create({
@@ -567,16 +589,25 @@ class VibeSurfBackground {
567
589
  });
568
590
 
569
591
  if (tab && tab.id) {
592
+ console.log(`[VibeSurf] Successfully opened file in tab: ${tab.id} (request: ${requestId})`);
570
593
  return { success: true, tabId: tab.id };
571
594
  } else {
572
- return { success: false, error: 'Failed to create tab' };
595
+ console.warn(`[VibeSurf] Tab creation returned but no tab ID for request: ${requestId}`);
596
+ return { success: false, error: 'Failed to create tab - no tab ID returned' };
573
597
  }
574
598
 
575
599
  } catch (error) {
576
- console.error('[VibeSurf] Error opening file URL:', error);
600
+ console.error(`[VibeSurf] Error opening file URL (request: ${requestId}):`, error);
601
+
602
+ // Provide more specific error messages
603
+ let errorMessage = error.message || 'Unknown error opening file';
604
+ if (error.message && error.message.includes('file://')) {
605
+ errorMessage = 'Browser security restricts opening local files. Try copying the file path and opening manually.';
606
+ }
607
+
577
608
  return {
578
609
  success: false,
579
- error: error.message || 'Unknown error opening file'
610
+ error: errorMessage
580
611
  };
581
612
  }
582
613
  }
@@ -16,8 +16,7 @@
16
16
  "contextMenus",
17
17
  "tabs",
18
18
  "clipboardWrite",
19
- "scripting",
20
- "microphone"
19
+ "scripting"
21
20
  ],
22
21
  "host_permissions": [
23
22
  "http://localhost:*/*",
@@ -49,15 +48,7 @@
49
48
 
50
49
  "web_accessible_resources": [
51
50
  {
52
- "resources": [
53
- "sidepanel.html",
54
- "permission-request.html",
55
- "permission-iframe.html",
56
- "styles/*",
57
- "scripts/*",
58
- "config.js",
59
- "icons/*"
60
- ],
51
+ "resources": ["sidepanel.html", "styles/*", "scripts/*", "config.js", "icons/*"],
61
52
  "matches": ["<all_urls>"]
62
53
  }
63
54
  ]
@@ -275,14 +275,28 @@ class VibeSurfFileManager {
275
275
  async handleFileLink(filePath) {
276
276
  // Prevent multiple simultaneous calls
277
277
  if (this.state.isHandlingFileLink) {
278
+ console.log('[FileManager] File link handling already in progress, skipping...');
278
279
  return;
279
280
  }
280
281
 
281
282
  this.state.isHandlingFileLink = true;
282
283
 
283
284
  try {
284
- // First decode the URL-encoded path
285
- let decodedPath = decodeURIComponent(filePath);
285
+ console.log('[FileManager] Handling file link:', filePath);
286
+
287
+ // Validate input
288
+ if (!filePath || typeof filePath !== 'string') {
289
+ throw new Error('Invalid file path provided');
290
+ }
291
+
292
+ // First decode the URL-encoded path safely
293
+ let decodedPath;
294
+ try {
295
+ decodedPath = decodeURIComponent(filePath);
296
+ } catch (decodeError) {
297
+ console.warn('[FileManager] Failed to decode URL, using original path:', decodeError);
298
+ decodedPath = filePath;
299
+ }
286
300
 
287
301
  // Remove file:// protocol prefix and normalize
288
302
  let cleanPath = decodedPath.replace(/^file:\/\/\//, '').replace(/^file:\/\//, '');
@@ -300,21 +314,28 @@ class VibeSurfFileManager {
300
314
  `file:///${cleanPath}` :
301
315
  `file:///${cleanPath.replace(/^\//, '')}`; // Remove leading slash and add triple slash
302
316
 
317
+ console.log('[FileManager] Processed file URL:', fileUrl);
318
+
303
319
  // Show user notification about the action
304
320
  this.emit('notification', {
305
321
  message: `Opening file: ${cleanPath}`,
306
322
  type: 'info'
307
323
  });
308
324
 
309
- // Use setTimeout to prevent UI blocking
325
+ // Use setTimeout to prevent UI blocking and ensure proper cleanup
310
326
  setTimeout(async () => {
311
327
  try {
312
328
  // For user-clicked file links, use OPEN_FILE_URL to keep tab open
313
329
  // This prevents the auto-close behavior in OPEN_FILE_SYSTEM
314
- const fileOpenResponse = await chrome.runtime.sendMessage({
315
- type: 'OPEN_FILE_URL',
316
- data: { fileUrl: fileUrl }
317
- });
330
+ const fileOpenResponse = await Promise.race([
331
+ chrome.runtime.sendMessage({
332
+ type: 'OPEN_FILE_URL',
333
+ data: { fileUrl: fileUrl }
334
+ }),
335
+ new Promise((_, reject) =>
336
+ setTimeout(() => reject(new Error('File open timeout')), 5000)
337
+ )
338
+ ]);
318
339
 
319
340
  if (fileOpenResponse && fileOpenResponse.success) {
320
341
  this.emit('notification', {
@@ -322,12 +343,14 @@ class VibeSurfFileManager {
322
343
  type: 'success'
323
344
  });
324
345
  return;
346
+ } else if (fileOpenResponse && fileOpenResponse.error) {
347
+ console.warn('[FileManager] Background script file open failed:', fileOpenResponse.error);
325
348
  }
326
349
 
327
- // If OPEN_FILE_URL fails, try direct browser open
350
+ // If OPEN_FILE_URL fails, try direct browser open with additional safety
328
351
  try {
329
352
  const opened = window.open(fileUrl, '_blank', 'noopener,noreferrer');
330
- if (opened) {
353
+ if (opened && !opened.closed) {
331
354
  this.emit('notification', {
332
355
  message: 'File opened in browser',
333
356
  type: 'success'
@@ -339,14 +362,32 @@ class VibeSurfFileManager {
339
362
  }
340
363
 
341
364
  // Last resort: Copy path to clipboard
342
- this.copyToClipboardFallback(fileUrl);
365
+ await this.copyToClipboardFallback(fileUrl);
343
366
 
344
367
  } catch (error) {
345
368
  console.error('[FileManager] Error in async file handling:', error);
369
+
370
+ // Provide more helpful error messages
371
+ let userMessage = 'Unable to open file';
372
+ if (error.message.includes('timeout')) {
373
+ userMessage = 'File open operation timed out. Try copying the path manually.';
374
+ } else if (error.message.includes('protocol')) {
375
+ userMessage = 'Browser security restricts opening local files. File path copied to clipboard.';
376
+ } else {
377
+ userMessage = `Unable to open file: ${error.message}`;
378
+ }
379
+
346
380
  this.emit('notification', {
347
- message: `Unable to open file: ${error.message}`,
381
+ message: userMessage,
348
382
  type: 'error'
349
383
  });
384
+
385
+ // Fallback to clipboard
386
+ try {
387
+ await this.copyToClipboardFallback(fileUrl);
388
+ } catch (clipboardError) {
389
+ console.error('[FileManager] Clipboard fallback also failed:', clipboardError);
390
+ }
350
391
  } finally {
351
392
  this.state.isHandlingFileLink = false;
352
393
  }
@@ -355,7 +396,7 @@ class VibeSurfFileManager {
355
396
  } catch (error) {
356
397
  console.error('[FileManager] Error handling file link:', error);
357
398
  this.emit('notification', {
358
- message: `Unable to open file: ${error.message}`,
399
+ message: `File link processing failed: ${error.message}`,
359
400
  type: 'error'
360
401
  });
361
402
  this.state.isHandlingFileLink = false;
@@ -189,6 +189,12 @@ class VibeSurfApp {
189
189
  // Periodic backend health check
190
190
  setInterval(async () => {
191
191
  try {
192
+ // Check if apiClient exists and is initialized
193
+ if (!this.apiClient || typeof this.apiClient.healthCheck !== 'function') {
194
+ console.warn('[VibeSurf] Health check skipped - API client not available');
195
+ return;
196
+ }
197
+
192
198
  const healthCheck = await this.apiClient.healthCheck();
193
199
 
194
200
  if (healthCheck.status === 'healthy') {
@@ -413,18 +419,37 @@ class VibeSurfApp {
413
419
 
414
420
  // Cleanup method
415
421
  destroy() {
416
- console.log('[VibeSurf] Cleaning up application...');
417
-
418
- if (this.uiManager) {
419
- this.uiManager.destroy();
422
+ // Prevent multiple cleanup calls
423
+ if (this.isDestroying || !this.isInitialized) {
424
+ console.log('[VibeSurf] Cleanup already in progress or app not initialized, skipping...');
425
+ return;
420
426
  }
421
427
 
422
- if (this.sessionManager) {
423
- this.sessionManager.destroy();
424
- }
428
+ this.isDestroying = true;
429
+ console.log('[VibeSurf] Cleaning up application...');
425
430
 
426
- this.isInitialized = false;
427
- console.log('[VibeSurf] Application cleanup complete');
431
+ try {
432
+ if (this.uiManager) {
433
+ this.uiManager.destroy();
434
+ this.uiManager = null;
435
+ }
436
+
437
+ if (this.sessionManager) {
438
+ this.sessionManager.destroy();
439
+ this.sessionManager = null;
440
+ }
441
+
442
+ if (this.apiClient) {
443
+ this.apiClient = null;
444
+ }
445
+
446
+ this.isInitialized = false;
447
+ console.log('[VibeSurf] Application cleanup complete');
448
+ } catch (error) {
449
+ console.error('[VibeSurf] Error during cleanup:', error);
450
+ } finally {
451
+ this.isDestroying = false;
452
+ }
428
453
  }
429
454
 
430
455
  // Get application status
@@ -456,11 +481,21 @@ document.addEventListener('DOMContentLoaded', async () => {
456
481
 
457
482
  // Handle page unload
458
483
  window.addEventListener('beforeunload', () => {
459
- if (window.vibeSurfApp) {
484
+ if (window.vibeSurfApp && window.vibeSurfApp.isInitialized && !window.vibeSurfApp.isDestroying) {
485
+ console.log('[VibeSurf] Page unloading, cleaning up...');
460
486
  window.vibeSurfApp.destroy();
461
487
  }
462
488
  });
463
489
 
490
+ // Handle visibility change to prevent unnecessary cleanup
491
+ document.addEventListener('visibilitychange', () => {
492
+ if (document.visibilityState === 'hidden') {
493
+ console.log('[VibeSurf] Page hidden, but not cleaning up (might be tab switch)');
494
+ } else if (document.visibilityState === 'visible') {
495
+ console.log('[VibeSurf] Page visible again');
496
+ }
497
+ });
498
+
464
499
  // Make app accessible for debugging
465
500
  if (typeof window !== 'undefined') {
466
501
  window.VibeSurfApp = VibeSurfApp;
@@ -653,11 +653,37 @@ class VibeSurfSessionManager {
653
653
 
654
654
  // Cleanup
655
655
  destroy() {
656
- this.stopActivityPolling();
657
- this.eventListeners.clear();
658
- this.currentSession = null;
659
- this.activityLogs = [];
656
+ // Prevent multiple cleanup calls
657
+ if (this.isDestroying) {
658
+ console.log('[SessionManager] Cleanup already in progress, skipping...');
659
+ return;
660
+ }
660
661
 
662
+ this.isDestroying = true;
663
+ console.log('[SessionManager] Destroying session manager...');
664
+
665
+ try {
666
+ this.stopActivityPolling();
667
+ this.eventListeners.clear();
668
+
669
+ // Clear any ongoing requests
670
+ if (this.pollingTimer) {
671
+ clearTimeout(this.pollingTimer);
672
+ this.pollingTimer = null;
673
+ }
674
+
675
+ // Reset state
676
+ this.currentSession = null;
677
+ this.currentTaskId = null;
678
+ this.activityLogs = [];
679
+ this.isPolling = false;
680
+
681
+ console.log('[SessionManager] Session manager cleanup complete');
682
+ } catch (error) {
683
+ console.error('[SessionManager] Error during destroy:', error);
684
+ } finally {
685
+ this.isDestroying = false;
686
+ }
661
687
  }
662
688
 
663
689
  // Status helpers
@@ -1338,6 +1338,15 @@ class VibeSurfUIManager {
1338
1338
  terminateBtn?.classList.remove('hidden');
1339
1339
  break;
1340
1340
 
1341
+ case 'done':
1342
+ case 'completed':
1343
+ case 'finished':
1344
+ console.log(`[UIManager] Task completed with status: ${status}, hiding panel after delay`);
1345
+ // Treat as ready state
1346
+ panel.classList.add('hidden');
1347
+ panel.classList.remove('error-state');
1348
+ break;
1349
+
1341
1350
  default:
1342
1351
  console.log(`[UIManager] Unknown control panel status: ${status}, hiding panel`);
1343
1352
  panel.classList.add('hidden');
@@ -1443,9 +1452,21 @@ class VibeSurfUIManager {
1443
1452
  }
1444
1453
 
1445
1454
  logs.forEach(log => this.addActivityLog(log));
1455
+
1456
+ // Bind link click handlers to all existing activity items after loading
1457
+ this.bindLinkHandlersToAllActivityItems();
1458
+
1446
1459
  this.scrollActivityToBottom();
1447
1460
  }
1448
1461
 
1462
+ bindLinkHandlersToAllActivityItems() {
1463
+ // Bind link click handlers to all existing activity items
1464
+ const activityItems = this.elements.activityLog.querySelectorAll('.activity-item');
1465
+ activityItems.forEach(item => {
1466
+ this.bindLinkClickHandlers(item);
1467
+ });
1468
+ }
1469
+
1449
1470
  addActivityLog(activityData) {
1450
1471
  // Filter out "done" status messages from UI display only
1451
1472
  const agentStatus = activityData.agent_status || activityData.status || '';
@@ -1475,6 +1496,9 @@ class VibeSurfUIManager {
1475
1496
 
1476
1497
  // Bind copy button functionality
1477
1498
  this.bindCopyButtonEvent(activityItem, activityData);
1499
+
1500
+ // Bind link click handlers to prevent extension freezing
1501
+ this.bindLinkClickHandlers(activityItem);
1478
1502
  }
1479
1503
  }
1480
1504
  }
@@ -1677,6 +1701,147 @@ class VibeSurfUIManager {
1677
1701
  }
1678
1702
  }
1679
1703
 
1704
+ bindLinkClickHandlers(activityItem) {
1705
+ // Handle all link clicks within activity items to prevent extension freezing
1706
+ const links = activityItem.querySelectorAll('a');
1707
+
1708
+ links.forEach(link => {
1709
+ // Check if handler is already attached to prevent double binding
1710
+ if (link.hasAttribute('data-link-handler-attached')) {
1711
+ return;
1712
+ }
1713
+
1714
+ link.setAttribute('data-link-handler-attached', 'true');
1715
+
1716
+ link.addEventListener('click', async (e) => {
1717
+ console.log('[VibeSurf] Link click event detected:', e);
1718
+
1719
+ // Comprehensive event prevention
1720
+ e.preventDefault();
1721
+ e.stopPropagation();
1722
+ e.stopImmediatePropagation(); // Prevent any other handlers
1723
+
1724
+ // Remove href temporarily to prevent default browser behavior
1725
+ const originalHref = link.getAttribute('href');
1726
+ link.setAttribute('href', '#');
1727
+
1728
+ const href = originalHref;
1729
+ if (!href || href === '#') return;
1730
+
1731
+ // Debounce - prevent rapid repeated clicks
1732
+ if (link.hasAttribute('data-link-processing')) {
1733
+ console.log('[VibeSurf] Link already processing, ignoring duplicate click');
1734
+ return;
1735
+ }
1736
+
1737
+ link.setAttribute('data-link-processing', 'true');
1738
+
1739
+ try {
1740
+ console.log('[VibeSurf] Processing link:', href);
1741
+
1742
+ // Handle file:// links using existing logic
1743
+ if (href.startsWith('file://')) {
1744
+ await this.handleFileLinkClick(href);
1745
+ }
1746
+ // Handle HTTP/HTTPS links
1747
+ else if (href.startsWith('http://') || href.startsWith('https://')) {
1748
+ await this.handleHttpLinkClick(href);
1749
+ }
1750
+ // Handle other protocols or relative URLs
1751
+ else {
1752
+ await this.handleOtherLinkClick(href);
1753
+ }
1754
+
1755
+ console.log('[VibeSurf] Link processed successfully:', href);
1756
+ } catch (error) {
1757
+ console.error('[VibeSurf] Error handling link click:', error);
1758
+ this.showNotification(`Failed to open link: ${error.message}`, 'error');
1759
+ } finally {
1760
+ // Restore original href
1761
+ link.setAttribute('href', originalHref);
1762
+
1763
+ // Remove processing flag after a short delay
1764
+ setTimeout(() => {
1765
+ link.removeAttribute('data-link-processing');
1766
+ }, 1000);
1767
+ }
1768
+ });
1769
+ });
1770
+ }
1771
+
1772
+ async handleFileLinkClick(fileUrl) {
1773
+ console.log('[UIManager] Opening file URL:', fileUrl);
1774
+
1775
+ // Use the background script to handle file URLs
1776
+ const result = await chrome.runtime.sendMessage({
1777
+ type: 'OPEN_FILE_URL',
1778
+ data: { fileUrl }
1779
+ });
1780
+
1781
+ if (!result.success) {
1782
+ throw new Error(result.error || 'Failed to open file');
1783
+ }
1784
+ }
1785
+
1786
+ async handleHttpLinkClick(url) {
1787
+ console.log('[VibeSurf] Opening HTTP URL:', url);
1788
+
1789
+ try {
1790
+ // Open HTTP/HTTPS links in a new tab
1791
+ const result = await chrome.runtime.sendMessage({
1792
+ type: 'OPEN_FILE_URL',
1793
+ data: { fileUrl: url }
1794
+ });
1795
+
1796
+ console.log('[VibeSurf] Background script response:', result);
1797
+
1798
+ if (!result || !result.success) {
1799
+ throw new Error(result?.error || 'Failed to create tab for URL');
1800
+ }
1801
+
1802
+ console.log('[VibeSurf] Successfully opened tab:', result.tabId);
1803
+ } catch (error) {
1804
+ console.error('[VibeSurf] Error opening HTTP URL:', error);
1805
+ throw error;
1806
+ }
1807
+ }
1808
+
1809
+ async handleOtherLinkClick(url) {
1810
+ console.log('[UIManager] Opening other URL:', url);
1811
+
1812
+ // For relative URLs or other protocols, try to open in new tab
1813
+ try {
1814
+ // Use the background script to handle URL opening
1815
+ const result = await chrome.runtime.sendMessage({
1816
+ type: 'OPEN_FILE_URL',
1817
+ data: { fileUrl: url }
1818
+ });
1819
+
1820
+ if (!result.success) {
1821
+ throw new Error(result.error || 'Failed to open URL');
1822
+ }
1823
+ } catch (error) {
1824
+ // If the background script method fails, try to construct absolute URL
1825
+ if (!url.startsWith('http')) {
1826
+ try {
1827
+ const absoluteUrl = new URL(url, window.location.href).href;
1828
+ const result = await chrome.runtime.sendMessage({
1829
+ type: 'OPEN_FILE_URL',
1830
+ data: { fileUrl: absoluteUrl }
1831
+ });
1832
+
1833
+ if (!result.success) {
1834
+ throw new Error(result.error || 'Failed to open absolute URL');
1835
+ }
1836
+ } catch (urlError) {
1837
+ throw new Error(`Failed to open URL: ${urlError.message}`);
1838
+ }
1839
+ } else {
1840
+ throw error;
1841
+ }
1842
+ }
1843
+ }
1844
+
1680
1845
  async copyMessageToClipboard(activityData) {
1681
1846
  try {
1682
1847
  // Extract only the message content (no agent info or timestamps)
@@ -2492,45 +2657,83 @@ class VibeSurfUIManager {
2492
2657
 
2493
2658
  // Cleanup
2494
2659
  destroy() {
2495
- // Stop task status monitoring
2496
- this.stopTaskStatusMonitoring();
2497
-
2498
- // Cleanup voice recorder
2499
- if (this.voiceRecorder) {
2500
- this.voiceRecorder.cleanup();
2660
+ // Prevent multiple cleanup calls
2661
+ if (this.isDestroying) {
2662
+ console.log('[UIManager] Cleanup already in progress, skipping...');
2663
+ return;
2501
2664
  }
2502
2665
 
2503
- // Cleanup managers
2504
- if (this.settingsManager) {
2505
- // Cleanup settings manager if it has destroy method
2506
- if (typeof this.settingsManager.destroy === 'function') {
2507
- this.settingsManager.destroy();
2508
- }
2509
- }
2666
+ this.isDestroying = true;
2667
+ console.log('[UIManager] Destroying UI manager...');
2510
2668
 
2511
- if (this.historyManager) {
2512
- // Cleanup history manager if it has destroy method
2513
- if (typeof this.historyManager.destroy === 'function') {
2514
- this.historyManager.destroy();
2669
+ try {
2670
+ // Stop task status monitoring
2671
+ this.stopTaskStatusMonitoring();
2672
+
2673
+ // Cleanup voice recorder
2674
+ if (this.voiceRecorder) {
2675
+ this.voiceRecorder.cleanup();
2676
+ this.voiceRecorder = null;
2515
2677
  }
2516
- }
2517
-
2518
- if (this.fileManager) {
2519
- // Cleanup file manager if it has destroy method
2520
- if (typeof this.fileManager.destroy === 'function') {
2521
- this.fileManager.destroy();
2678
+
2679
+ // Cleanup managers with error handling
2680
+ if (this.settingsManager) {
2681
+ try {
2682
+ if (typeof this.settingsManager.destroy === 'function') {
2683
+ this.settingsManager.destroy();
2684
+ }
2685
+ } catch (error) {
2686
+ console.error('[UIManager] Error destroying settings manager:', error);
2687
+ }
2688
+ this.settingsManager = null;
2522
2689
  }
2523
- }
2524
-
2525
- if (this.modalManager) {
2526
- // Cleanup modal manager if it has destroy method
2527
- if (typeof this.modalManager.destroy === 'function') {
2528
- this.modalManager.destroy();
2690
+
2691
+ if (this.historyManager) {
2692
+ try {
2693
+ if (typeof this.historyManager.destroy === 'function') {
2694
+ this.historyManager.destroy();
2695
+ }
2696
+ } catch (error) {
2697
+ console.error('[UIManager] Error destroying history manager:', error);
2698
+ }
2699
+ this.historyManager = null;
2529
2700
  }
2701
+
2702
+ if (this.fileManager) {
2703
+ try {
2704
+ if (typeof this.fileManager.destroy === 'function') {
2705
+ this.fileManager.destroy();
2706
+ }
2707
+ } catch (error) {
2708
+ console.error('[UIManager] Error destroying file manager:', error);
2709
+ }
2710
+ this.fileManager = null;
2711
+ }
2712
+
2713
+ if (this.modalManager) {
2714
+ try {
2715
+ if (typeof this.modalManager.destroy === 'function') {
2716
+ this.modalManager.destroy();
2717
+ }
2718
+ } catch (error) {
2719
+ console.error('[UIManager] Error destroying modal manager:', error);
2720
+ }
2721
+ this.modalManager = null;
2722
+ }
2723
+
2724
+ // Clear state
2725
+ this.state = {
2726
+ isLoading: false,
2727
+ isTaskRunning: false,
2728
+ taskInfo: null
2729
+ };
2730
+
2731
+ console.log('[UIManager] UI manager cleanup complete');
2732
+ } catch (error) {
2733
+ console.error('[UIManager] Error during destroy:', error);
2734
+ } finally {
2735
+ this.isDestroying = false;
2530
2736
  }
2531
-
2532
- // Clear state
2533
- this.state.currentModal = null;
2534
2737
  }
2535
2738
 
2536
2739
  // Tab Selector Methods
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibesurf
3
- Version: 0.1.21
3
+ Version: 0.1.22
4
4
  Summary: VibeSurf: A powerful browser assistant for vibe surfing
5
5
  Author: Shao Warm
6
6
  License: Apache-2.0
@@ -37,7 +37,7 @@ Requires-Dist: aiosqlite>=0.21.0
37
37
  Requires-Dist: rich>=13.0.0
38
38
  Requires-Dist: greenlet>=3.2.4
39
39
  Requires-Dist: getmac>=0.9.5
40
- Requires-Dist: browser-use==0.7.8
40
+ Requires-Dist: browser-use==0.7.9
41
41
  Requires-Dist: markdown-pdf>=1.9
42
42
  Requires-Dist: nanoid>=2.0.0
43
43
  Requires-Dist: markdownify>=1.2.0
@@ -1,16 +1,16 @@
1
1
  vibe_surf/__init__.py,sha256=WtduuMFGauMD_9dpk4fnRnLTAP6ka9Lfu0feAFNzLfo,339
2
- vibe_surf/_version.py,sha256=QwRysHnO-cJwIFSvXReHDj93DEPhlibOTtnnb25J9-c,706
2
+ vibe_surf/_version.py,sha256=o3nZ3vj6LXerN2NKds558INvVml0G0wcb-duWVc5JMs,706
3
3
  vibe_surf/cli.py,sha256=pbep2dBeQqralZ8AggkH4h2nayBarbdN8lhZxo35gNU,16689
4
4
  vibe_surf/common.py,sha256=_WWMxen5wFwzUjEShn3yDVC1OBFUiJ6Vccadi6tuG6w,1215
5
5
  vibe_surf/logger.py,sha256=k53MFA96QX6t9OfcOf1Zws8PP0OOqjVJfhUD3Do9lKw,3043
6
6
  vibe_surf/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- vibe_surf/agents/browser_use_agent.py,sha256=qmm3TAVzEYjvOvSQEa5xUZOgpBOR_8qePME8BjLjOd0,45951
7
+ vibe_surf/agents/browser_use_agent.py,sha256=jeUYV7yk6vyycw6liju_597GdjB3CW_B2wEhn2F0ekk,45957
8
8
  vibe_surf/agents/report_writer_agent.py,sha256=pCF2k6VLyO-sSviGBqqIyVD3SLqaZtSqiW3kvNfPY1I,20967
9
9
  vibe_surf/agents/vibe_surf_agent.py,sha256=i7O4Djw3Pd1ijwbkGbXkQqO1y0RunlelCqajjfJFfaQ,73687
10
10
  vibe_surf/agents/views.py,sha256=yHjNJloa-aofVTGyuRy08tBYP_Y3XLqt1DUWOUmHRng,4825
11
11
  vibe_surf/agents/prompts/__init__.py,sha256=l4ieA0D8kLJthyNN85FKLNe4ExBa3stY3l-aImLDRD0,36
12
12
  vibe_surf/agents/prompts/report_writer_prompt.py,sha256=sZE8MUT1CDLmRzbnbEQzAvTwJjpITgh2Q8g1_eXmkzE,4454
13
- vibe_surf/agents/prompts/vibe_surf_prompt.py,sha256=gn8Q234zwtUxVzduzmINmqV-iooE-aJ9u2-yXQ3Wo6M,5573
13
+ vibe_surf/agents/prompts/vibe_surf_prompt.py,sha256=rC6EtcJH9nuHDcTdVELFsv02Lghp3wWp1fsJm9l1v4o,5664
14
14
  vibe_surf/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  vibe_surf/backend/llm_config.py,sha256=9V8Gg065TQALbOKQnOqFWd8RzOJjegOD8w6YOf90Q7Y,5036
16
16
  vibe_surf/backend/main.py,sha256=SWbYXXbPGirGSujyVQqdHCzCR-d7Ffu94_J9JyY7jK8,7292
@@ -38,17 +38,17 @@ vibe_surf/backend/utils/encryption.py,sha256=CjLNh_n0Luhfa-6BB-icfzkiiDqj5b4Gu6M
38
38
  vibe_surf/backend/utils/llm_factory.py,sha256=mNy8o3sw7vYJ8gwiTsrgXbG7Ri_B11ylE4KGcfHULp8,8972
39
39
  vibe_surf/browser/__init__.py,sha256=_UToO2fZfSCrfjOcxhn4Qq7ZLbYeyPuUUEmqIva-Yv8,325
40
40
  vibe_surf/browser/agen_browser_profile.py,sha256=J06hCBJSJ-zAFVM9yDFz8UpmiLuFyWke1EMekpU45eo,5871
41
- vibe_surf/browser/agent_browser_session.py,sha256=YRpRH74_jRDEaReXhtIW8Pnm29Li4Kf3KjLi-ZFSDZg,33890
41
+ vibe_surf/browser/agent_browser_session.py,sha256=UBU4yiPg9v2DDR6yY3KkNTNH-g7of8fm-mpdXOWvYbE,33970
42
42
  vibe_surf/browser/browser_manager.py,sha256=PFJ9flmqR2uokuRZ3PDh_Dy6_6qcQ6kH_eRc1yT6Iq8,11257
43
43
  vibe_surf/browser/utils.py,sha256=bBtpMiyz2ixWOr31GbJwZ8pVYcnxztKjTJJO92z1BDY,35742
44
44
  vibe_surf/browser/watchdogs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  vibe_surf/browser/watchdogs/action_watchdog.py,sha256=6lM0nOR67clLzC6nVEMZ2Vam8VHDW8GRlg_jbGUHbPk,5297
46
46
  vibe_surf/browser/watchdogs/dom_watchdog.py,sha256=c0AJo2yckWFZqpgnPz7RbsRjcpwlhjD4mSIzCAbRn48,10994
47
- vibe_surf/chrome_extension/background.js,sha256=QNzF_dm7TvOzcZupogDvi1i5mEd0DPmQn4gp3yfcwPY,28666
47
+ vibe_surf/chrome_extension/background.js,sha256=9YLbLmBl__PPUwN6Edf0EQfE53Br1VfjlUiIkznf4n4,30181
48
48
  vibe_surf/chrome_extension/config.js,sha256=g53UkfsaOFNC6fZG-THlBxdSjvswPsaQ9w8rxiHNq2E,1093
49
49
  vibe_surf/chrome_extension/content.js,sha256=cB67jK3vIE5zrpXAfi3p50H3EyTqK5xockOph0Q4kQg,13708
50
50
  vibe_surf/chrome_extension/dev-reload.js,sha256=xQpi-1Ekb5P8Ogsm6rUK09QzxafwH0H409zBKmaUFNw,1790
51
- vibe_surf/chrome_extension/manifest.json,sha256=csaBh7tf_45FHg8eVplMXz0neMahpXbgqk9rJ5EXts4,1277
51
+ vibe_surf/chrome_extension/manifest.json,sha256=B08nHuU-bPc-pUr30Y-of39TjMlrE7D5gP2sZjZ8CrE,1142
52
52
  vibe_surf/chrome_extension/permission-iframe.html,sha256=R6VM1JfrzkfXTTD5mGCKui1dDWTqHEe9n8TtVdZNPNg,948
53
53
  vibe_surf/chrome_extension/permission-request.html,sha256=ct1LTl_9euABiHcqNU6AFcvpCAfANWO0y_dDEAjtwfE,2905
54
54
  vibe_surf/chrome_extension/popup.html,sha256=n3dI_-WbILm0q8O_za6xX0WvOofz5lwT_7YXs0u9RAE,4248
@@ -56,16 +56,16 @@ vibe_surf/chrome_extension/sidepanel.html,sha256=-ND1Q_HLHf9Pg1F3Q1u-32x_RoN5czO
56
56
  vibe_surf/chrome_extension/icons/logo.icns,sha256=ZzY1eIKF4dNhNW4CeE1UBQloxNVC7bQx3qcClo3CnMQ,1569615
57
57
  vibe_surf/chrome_extension/icons/logo.png,sha256=PLmv1E6sCGXUE5ZDxr-pFPQd9Gvaw_f1TnYmF8VIssU,566385
58
58
  vibe_surf/chrome_extension/scripts/api-client.js,sha256=qAQ0WlARCSBb0mFkmjCgT68ra7P82U2xpXFCNWVjUJc,15704
59
- vibe_surf/chrome_extension/scripts/file-manager.js,sha256=WcEaeoECq84jXqEo3Q2ywmqppwSUVm-0dtrbTYXL07g,15809
59
+ vibe_surf/chrome_extension/scripts/file-manager.js,sha256=dtaYJNrpUnKH9zCsIpAAEkFN43ownDRtkyUhV8zxGZ0,17585
60
60
  vibe_surf/chrome_extension/scripts/history-manager.js,sha256=J_EiBKrRp2cTxuy0Sq5oCju5YuX0_2pGG6NWrJSjC24,22218
61
- vibe_surf/chrome_extension/scripts/main.js,sha256=UsLTBHh3xAcZAAvQeWIHBPCZ-C8d7h7etzwBwAppUmM,17199
61
+ vibe_surf/chrome_extension/scripts/main.js,sha256=hmRQsnq5pEqrBgfuyJ9brfpTGgyl_lJHHPmyjr9MdNY,18509
62
62
  vibe_surf/chrome_extension/scripts/markdown-it.min.js,sha256=gZ3xe0BdCJplNiHWTKrm6AGZydPy34jJKZqFIf-7hIw,102948
63
63
  vibe_surf/chrome_extension/scripts/modal-manager.js,sha256=9ekFaTmy8sk94KK9HZJ7739ObsZ6ssllmRLP9rQxUKU,14187
64
64
  vibe_surf/chrome_extension/scripts/permission-iframe-request.js,sha256=JTin53qSN8PqH4yoXluoK_llGJl1UlOgswp_9ojqxuk,8541
65
65
  vibe_surf/chrome_extension/scripts/permission-request.js,sha256=9WEeTqMD0tHm1aX2ySkZgJ23siVZLZWAjVQe2dSmnoI,5168
66
- vibe_surf/chrome_extension/scripts/session-manager.js,sha256=sXh4j4dv3eKOGYeov8iUPt-DX5jKQLhcASDXRX9qW5Y,21126
66
+ vibe_surf/chrome_extension/scripts/session-manager.js,sha256=rOPGDTyV1oK-qYfqJKK8mpvQFSdnz0_F0wCcbxPfTSw,21887
67
67
  vibe_surf/chrome_extension/scripts/settings-manager.js,sha256=9UGJFxQ1DbDbfndEBDv32MHfAW8YdfZmwg0vW6ABXOQ,77257
68
- vibe_surf/chrome_extension/scripts/ui-manager.js,sha256=7mSgf3CHeA_jt2Lv5cPHi3YBnTwgvHfcxz1RDnk5BOg,102452
68
+ vibe_surf/chrome_extension/scripts/ui-manager.js,sha256=iznuSHhwZVGS7uuXdwPkZSMIADT2VTHRh_zz7MgBYVw,109068
69
69
  vibe_surf/chrome_extension/scripts/user-settings-storage.js,sha256=5aGuHXwTokX5wKjdNnu3rVkZv9XoD15FmgCELRRE3Xw,14191
70
70
  vibe_surf/chrome_extension/scripts/voice-recorder.js,sha256=rIq9Rhyq-QyeCxJxxZGbnbPC0MCjQtNx6T2UC1g_al4,16852
71
71
  vibe_surf/chrome_extension/styles/activity.css,sha256=aEFa_abskrDQvwsesPVOyJW3rUQUEBQpMKPHhY94CoA,19601
@@ -93,9 +93,9 @@ vibe_surf/tools/report_writer_tools.py,sha256=sUqUFr-_Rs8RJ0Bs77Hrp07kNwRIvHv7Er
93
93
  vibe_surf/tools/vibesurf_tools.py,sha256=VVhM2IZOXwpGvJ3v9jTXFHmxTxF2jAzhrwqFqxFVuX4,29976
94
94
  vibe_surf/tools/views.py,sha256=aPoabrXOCrn5vPCAauMKYvpyP9n0qC2xKn1IbjAGXwE,4218
95
95
  vibe_surf/tools/voice_asr.py,sha256=AJG0yq_Jq-j8ulDlbPhVFfK1jch9_ASesis73iki9II,4702
96
- vibesurf-0.1.21.dist-info/licenses/LICENSE,sha256=czn6QYya0-jhLnStD9JqnMS-hwP5wRByipkrGTvoXLI,11355
97
- vibesurf-0.1.21.dist-info/METADATA,sha256=ZU8_6P_WYntKGLDSxNx4zfdnYHLMeMvQUByxS-xFKyM,5158
98
- vibesurf-0.1.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
99
- vibesurf-0.1.21.dist-info/entry_points.txt,sha256=UxqpvMocL-PR33S6vLF2OmXn-kVzM-DneMeZeHcPMM8,48
100
- vibesurf-0.1.21.dist-info/top_level.txt,sha256=VPZGHqSb6EEqcJ4ZX6bHIuWfon5f6HXl3c7BYpbRqnY,10
101
- vibesurf-0.1.21.dist-info/RECORD,,
96
+ vibesurf-0.1.22.dist-info/licenses/LICENSE,sha256=czn6QYya0-jhLnStD9JqnMS-hwP5wRByipkrGTvoXLI,11355
97
+ vibesurf-0.1.22.dist-info/METADATA,sha256=vQdjdd1Sh3UUcQEriaqFOUkZOCuuXEZJM-BcdgwRwoE,5158
98
+ vibesurf-0.1.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
99
+ vibesurf-0.1.22.dist-info/entry_points.txt,sha256=UxqpvMocL-PR33S6vLF2OmXn-kVzM-DneMeZeHcPMM8,48
100
+ vibesurf-0.1.22.dist-info/top_level.txt,sha256=VPZGHqSb6EEqcJ4ZX6bHIuWfon5f6HXl3c7BYpbRqnY,10
101
+ vibesurf-0.1.22.dist-info/RECORD,,