vibesurf 0.1.10__py3-none-any.whl → 0.1.11__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.

Files changed (51) hide show
  1. vibe_surf/_version.py +2 -2
  2. vibe_surf/agents/browser_use_agent.py +68 -45
  3. vibe_surf/agents/prompts/report_writer_prompt.py +73 -0
  4. vibe_surf/agents/prompts/vibe_surf_prompt.py +85 -172
  5. vibe_surf/agents/report_writer_agent.py +380 -226
  6. vibe_surf/agents/vibe_surf_agent.py +879 -825
  7. vibe_surf/agents/views.py +130 -0
  8. vibe_surf/backend/api/activity.py +3 -1
  9. vibe_surf/backend/api/browser.py +9 -5
  10. vibe_surf/backend/api/config.py +8 -5
  11. vibe_surf/backend/api/files.py +59 -50
  12. vibe_surf/backend/api/models.py +2 -2
  13. vibe_surf/backend/api/task.py +45 -12
  14. vibe_surf/backend/database/manager.py +24 -18
  15. vibe_surf/backend/database/queries.py +199 -192
  16. vibe_surf/backend/database/schemas.py +1 -1
  17. vibe_surf/backend/main.py +4 -2
  18. vibe_surf/backend/shared_state.py +28 -35
  19. vibe_surf/backend/utils/encryption.py +3 -1
  20. vibe_surf/backend/utils/llm_factory.py +41 -36
  21. vibe_surf/browser/agent_browser_session.py +0 -4
  22. vibe_surf/browser/browser_manager.py +14 -8
  23. vibe_surf/browser/utils.py +5 -3
  24. vibe_surf/browser/watchdogs/dom_watchdog.py +0 -45
  25. vibe_surf/chrome_extension/background.js +4 -0
  26. vibe_surf/chrome_extension/scripts/api-client.js +13 -0
  27. vibe_surf/chrome_extension/scripts/file-manager.js +27 -71
  28. vibe_surf/chrome_extension/scripts/session-manager.js +21 -3
  29. vibe_surf/chrome_extension/scripts/ui-manager.js +831 -48
  30. vibe_surf/chrome_extension/sidepanel.html +21 -4
  31. vibe_surf/chrome_extension/styles/activity.css +365 -5
  32. vibe_surf/chrome_extension/styles/input.css +139 -0
  33. vibe_surf/cli.py +4 -22
  34. vibe_surf/common.py +35 -0
  35. vibe_surf/llm/openai_compatible.py +148 -93
  36. vibe_surf/logger.py +99 -0
  37. vibe_surf/{controller/vibesurf_tools.py → tools/browser_use_tools.py} +233 -219
  38. vibe_surf/tools/file_system.py +415 -0
  39. vibe_surf/{controller → tools}/mcp_client.py +4 -3
  40. vibe_surf/tools/report_writer_tools.py +21 -0
  41. vibe_surf/tools/vibesurf_tools.py +657 -0
  42. vibe_surf/tools/views.py +120 -0
  43. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/METADATA +6 -2
  44. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/RECORD +49 -43
  45. vibe_surf/controller/file_system.py +0 -53
  46. vibe_surf/controller/views.py +0 -37
  47. /vibe_surf/{controller → tools}/__init__.py +0 -0
  48. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/WHEEL +0 -0
  49. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/entry_points.txt +0 -0
  50. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/licenses/LICENSE +0 -0
  51. {vibesurf-0.1.10.dist-info → vibesurf-0.1.11.dist-info}/top_level.txt +0 -0
@@ -110,7 +110,7 @@
110
110
  <div id="control-panel" class="control-panel hidden">
111
111
  <button id="cancel-btn" class="control-btn cancel-btn">
112
112
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
113
- <path d="M6 6H4C3.45 6 3 5.55 3 5V4C3 3.45 3.45 3 4 3H6V6ZM10 6H14V3H10V6ZM18 6H20C20.55 6 21 5.55 21 5V4C21 3.45 20.55 3 20 3H18V6ZM6 8V20C6 20.55 6.45 21 7 21H17C17.55 21 18 20.55 18 20V8H6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
113
+ <path d="M6 4H10V20H6V4ZM14 4H18V20H14V4Z" fill="currentColor"/>
114
114
  </svg>
115
115
  Pause
116
116
  </button>
@@ -134,11 +134,28 @@
134
134
  <div class="input-container">
135
135
  <div class="input-main">
136
136
  <div class="textarea-container">
137
- <textarea
138
- id="task-input"
139
- class="task-input"
137
+ <textarea
138
+ id="task-input"
139
+ class="task-input"
140
140
  placeholder="Describe your browsing task..."
141
141
  rows="3"></textarea>
142
+ <!-- Tab Selection Dropdown -->
143
+ <div id="tab-selector-dropdown" class="tab-selector-dropdown hidden">
144
+ <div class="tab-selector-header">
145
+ <span class="tab-selector-title">Select Tabs</span>
146
+ </div>
147
+ <div class="tab-selector-content">
148
+ <div class="tab-selector-controls">
149
+ <label class="tab-option select-all-option">
150
+ <input type="radio" id="select-all-tabs" name="tab-selection" class="tab-radio">
151
+ <span class="tab-name">Select All</span>
152
+ </label>
153
+ </div>
154
+ <div id="tab-options-list" class="tab-options-list">
155
+ <!-- Tab options will be populated here -->
156
+ </div>
157
+ </div>
158
+ </div>
142
159
  <div class="input-actions">
143
160
  <button id="attach-file-btn" class="action-btn attach-btn" title="Attach Files">
144
161
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -135,7 +135,8 @@
135
135
  .message-container {
136
136
  display: flex;
137
137
  flex-direction: column;
138
- max-width: 80%;
138
+ max-width: 85%;
139
+ min-width: 0; /* Allow shrinking */
139
140
  animation: fadeIn 0.3s ease-out;
140
141
  }
141
142
 
@@ -152,34 +153,65 @@
152
153
  .message-header {
153
154
  display: flex;
154
155
  align-items: center;
155
- gap: var(--spacing-sm);
156
+ justify-content: space-between;
156
157
  margin-bottom: var(--spacing-xs);
157
158
  font-size: var(--font-size-xs);
158
159
  color: var(--text-muted);
159
160
  }
160
161
 
161
162
  .user-container .message-header {
162
- justify-content: flex-end;
163
+ flex-direction: row-reverse;
164
+ gap: var(--spacing-md);
163
165
  }
164
166
 
165
167
  .agent-container .message-header {
166
- justify-content: flex-start;
168
+ flex-direction: row;
169
+ gap: var(--spacing-md);
167
170
  }
168
171
 
169
172
  .agent-name {
170
173
  font-weight: var(--font-weight-medium);
171
174
  color: var(--text-secondary);
175
+ flex-shrink: 0;
172
176
  }
173
177
 
174
178
  .user-container .agent-name {
175
179
  color: var(--primary-color);
176
180
  }
177
181
 
182
+ .message-metadata {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: var(--spacing-sm);
186
+ font-size: 10px;
187
+ flex-shrink: 0;
188
+ }
189
+
178
190
  .message-time {
179
- font-size: var(--font-size-xs);
191
+ font-size: 10px;
180
192
  color: var(--text-muted);
181
193
  }
182
194
 
195
+ .message-metrics {
196
+ display: flex;
197
+ align-items: center;
198
+ gap: var(--spacing-xs);
199
+ }
200
+
201
+ .metric-item {
202
+ font-size: 10px;
203
+ color: var(--text-muted);
204
+ background-color: var(--bg-tertiary);
205
+ padding: 1px 4px;
206
+ border-radius: var(--radius-sm);
207
+ font-weight: var(--font-weight-normal);
208
+ }
209
+
210
+ .user-container .metric-item {
211
+ background-color: rgba(255, 255, 255, 0.2);
212
+ color: rgba(255, 255, 255, 0.9);
213
+ }
214
+
183
215
  /* Message Bubbles */
184
216
  .message-bubble {
185
217
  padding: var(--spacing-md);
@@ -187,6 +219,9 @@
187
219
  position: relative;
188
220
  word-wrap: break-word;
189
221
  box-shadow: var(--shadow-sm);
222
+ min-width: 0; /* Allow shrinking */
223
+ max-width: 100%;
224
+ overflow-wrap: break-word;
190
225
  }
191
226
 
192
227
  /* Copy Message Button */
@@ -300,6 +335,8 @@
300
335
  .message-content {
301
336
  line-height: 1.6;
302
337
  font-size: var(--font-size-sm);
338
+ min-width: 0; /* Allow shrinking */
339
+ overflow-wrap: break-word;
303
340
  }
304
341
 
305
342
  .user-bubble .message-content {
@@ -348,6 +385,28 @@
348
385
  font-size: var(--font-size-xs);
349
386
  margin: var(--spacing-sm) 0;
350
387
  border: 1px solid var(--border-color);
388
+ max-width: 100%;
389
+ white-space: pre-wrap;
390
+ word-break: break-all;
391
+ }
392
+
393
+ /* Custom scrollbar for code blocks */
394
+ .message-content .code-block::-webkit-scrollbar {
395
+ height: 6px;
396
+ }
397
+
398
+ .message-content .code-block::-webkit-scrollbar-track {
399
+ background: var(--bg-secondary);
400
+ border-radius: 3px;
401
+ }
402
+
403
+ .message-content .code-block::-webkit-scrollbar-thumb {
404
+ background: var(--border-color);
405
+ border-radius: 3px;
406
+ }
407
+
408
+ .message-content .code-block::-webkit-scrollbar-thumb:hover {
409
+ background: var(--border-hover);
351
410
  }
352
411
 
353
412
  .user-bubble .code-block {
@@ -361,6 +420,8 @@
361
420
  border-radius: var(--radius-sm);
362
421
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
363
422
  font-size: var(--font-size-xs);
423
+ word-break: break-all;
424
+ overflow-wrap: break-word;
364
425
  }
365
426
 
366
427
  .user-bubble .inline-code {
@@ -376,6 +437,28 @@
376
437
  font-size: var(--font-size-xs);
377
438
  margin: var(--spacing-sm) 0;
378
439
  border: 1px solid var(--border-color);
440
+ max-width: 100%;
441
+ white-space: pre-wrap;
442
+ word-break: break-all;
443
+ }
444
+
445
+ /* Custom scrollbar for JSON content */
446
+ .message-content .json-content::-webkit-scrollbar {
447
+ height: 6px;
448
+ }
449
+
450
+ .message-content .json-content::-webkit-scrollbar-track {
451
+ background: var(--bg-secondary);
452
+ border-radius: 3px;
453
+ }
454
+
455
+ .message-content .json-content::-webkit-scrollbar-thumb {
456
+ background: var(--border-color);
457
+ border-radius: 3px;
458
+ }
459
+
460
+ .message-content .json-content::-webkit-scrollbar-thumb:hover {
461
+ background: var(--border-hover);
379
462
  }
380
463
 
381
464
  .user-bubble .json-content {
@@ -571,4 +654,281 @@
571
654
 
572
655
  .message-content em {
573
656
  font-style: italic;
657
+ }
658
+
659
+ /* Suggestion Tasks Styles */
660
+ .suggestion-tasks-container {
661
+ margin: var(--spacing-lg) 0;
662
+ padding: var(--spacing-md);
663
+ background: linear-gradient(135deg, rgba(0, 122, 204, 0.02), rgba(0, 122, 204, 0.05));
664
+ border: 1px solid rgba(0, 122, 204, 0.1);
665
+ border-radius: var(--radius-xl);
666
+ position: relative;
667
+ overflow: visible;
668
+ display: block;
669
+ width: 100%;
670
+ box-sizing: border-box;
671
+ min-height: auto;
672
+ }
673
+
674
+ .suggestion-tasks-container::before {
675
+ content: '';
676
+ position: absolute;
677
+ top: 0;
678
+ left: 0;
679
+ right: 0;
680
+ height: 3px;
681
+ background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
682
+ border-radius: var(--radius-xl) var(--radius-xl) 0 0;
683
+ }
684
+
685
+ .suggestion-tasks-header {
686
+ text-align: center;
687
+ margin-bottom: var(--spacing-md);
688
+ padding: 0;
689
+ display: block;
690
+ width: 100%;
691
+ }
692
+
693
+ .suggestion-tasks-header h4 {
694
+ font-size: var(--font-size-xl);
695
+ font-weight: var(--font-weight-bold);
696
+ color: var(--text-primary);
697
+ margin: 0;
698
+ display: block;
699
+ text-align: center;
700
+ line-height: 1.3;
701
+ white-space: normal;
702
+ overflow: visible;
703
+ word-wrap: break-word;
704
+ }
705
+
706
+ .suggestion-tasks-header p {
707
+ font-size: var(--font-size-sm);
708
+ color: var(--text-secondary);
709
+ margin: 0;
710
+ opacity: 0.8;
711
+ line-height: 1.4;
712
+ display: block;
713
+ }
714
+
715
+ .suggestion-cards {
716
+ display: flex;
717
+ flex-direction: column;
718
+ gap: var(--spacing-sm);
719
+ width: 100%;
720
+ min-height: auto;
721
+ }
722
+
723
+ .suggestion-task-card {
724
+ display: flex;
725
+ align-items: center;
726
+ gap: var(--spacing-md);
727
+ padding: var(--spacing-md);
728
+ background: var(--bg-primary);
729
+ border: 2px solid var(--border-color);
730
+ border-radius: var(--radius-lg);
731
+ cursor: pointer;
732
+ transition: all var(--transition-fast);
733
+ position: relative;
734
+ overflow: visible;
735
+ width: 100%;
736
+ min-height: 50px;
737
+ box-sizing: border-box;
738
+ margin-bottom: 0;
739
+ }
740
+
741
+ .suggestion-task-card:last-child {
742
+ margin-bottom: 0;
743
+ }
744
+
745
+ .suggestion-task-card::before {
746
+ content: '';
747
+ position: absolute;
748
+ top: 0;
749
+ left: 0;
750
+ bottom: 0;
751
+ width: 4px;
752
+ background: var(--primary-color);
753
+ transform: scaleX(0);
754
+ transform-origin: left;
755
+ transition: transform var(--transition-fast);
756
+ }
757
+
758
+ .suggestion-task-card:hover {
759
+ border-color: var(--primary-color);
760
+ background: var(--bg-hover);
761
+ transform: translateY(-2px);
762
+ box-shadow: var(--shadow-lg);
763
+ }
764
+
765
+ .suggestion-task-card:hover::before {
766
+ transform: scaleX(1);
767
+ }
768
+
769
+ .suggestion-task-card:active {
770
+ transform: translateY(-1px);
771
+ box-shadow: var(--shadow-md);
772
+ }
773
+
774
+ .suggestion-card-icon {
775
+ flex-shrink: 0;
776
+ width: 40px;
777
+ height: 40px;
778
+ display: flex;
779
+ align-items: center;
780
+ justify-content: center;
781
+ background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
782
+ border-radius: var(--radius-md);
783
+ color: white;
784
+ transition: transform var(--transition-fast);
785
+ }
786
+
787
+ .suggestion-task-card:hover .suggestion-card-icon {
788
+ transform: scale(1.1);
789
+ }
790
+
791
+ .suggestion-card-content {
792
+ flex: 1;
793
+ min-width: 0;
794
+ display: flex;
795
+ flex-direction: column;
796
+ justify-content: center;
797
+ }
798
+
799
+ .suggestion-task-text {
800
+ font-size: var(--font-size-sm);
801
+ color: var(--text-primary);
802
+ line-height: 1.5;
803
+ font-weight: var(--font-weight-medium);
804
+ word-wrap: break-word;
805
+ overflow-wrap: break-word;
806
+ white-space: normal;
807
+ text-overflow: clip;
808
+ }
809
+
810
+ .suggestion-tasks-section {
811
+ margin: var(--spacing-lg) 0;
812
+ width: 100%;
813
+ }
814
+
815
+ .suggestion-tasks-header {
816
+ display: flex;
817
+ align-items: center;
818
+ gap: var(--spacing-sm);
819
+ margin-bottom: var(--spacing-md);
820
+ padding: 0 var(--spacing-sm);
821
+ min-height: 24px;
822
+ width: 100%;
823
+ overflow: visible;
824
+ }
825
+
826
+ .suggestion-tasks-header h4 {
827
+ font-size: var(--font-size-base);
828
+ font-weight: var(--font-weight-bold);
829
+ color: var(--text-primary);
830
+ margin: 0;
831
+ white-space: nowrap;
832
+ overflow: visible;
833
+ text-overflow: clip;
834
+ }
835
+
836
+ .suggestion-cards-container {
837
+ display: flex;
838
+ flex-direction: column;
839
+ gap: var(--spacing-md);
840
+ width: 100%;
841
+ padding: 0 var(--spacing-sm);
842
+ }
843
+
844
+ .suggestion-card-arrow {
845
+ flex-shrink: 0;
846
+ width: 24px;
847
+ height: 24px;
848
+ display: flex;
849
+ align-items: center;
850
+ justify-content: center;
851
+ color: var(--text-muted);
852
+ transition: all var(--transition-fast);
853
+ }
854
+
855
+ .suggestion-task-card:hover .suggestion-card-arrow {
856
+ color: var(--primary-color);
857
+ transform: translateX(4px);
858
+ }
859
+
860
+ /* Animation for suggestion cards */
861
+ .suggestion-tasks-container.fade-in {
862
+ animation: suggestionFadeIn 0.5s ease-out;
863
+ }
864
+
865
+ @keyframes suggestionFadeIn {
866
+ from {
867
+ opacity: 0;
868
+ transform: translateY(20px);
869
+ }
870
+ to {
871
+ opacity: 1;
872
+ transform: translateY(0);
873
+ }
874
+ }
875
+
876
+ /* Responsive design for suggestion cards */
877
+ @media (max-width: 480px) {
878
+ .suggestion-tasks-container {
879
+ margin: var(--spacing-lg) 0;
880
+ padding: var(--spacing-md);
881
+ }
882
+
883
+ .suggestion-task-card {
884
+ padding: var(--spacing-md);
885
+ gap: var(--spacing-sm);
886
+ }
887
+
888
+ .suggestion-card-icon {
889
+ width: 32px;
890
+ height: 32px;
891
+ }
892
+
893
+ .suggestion-card-icon svg {
894
+ width: 14px;
895
+ height: 14px;
896
+ }
897
+
898
+ .suggestion-task-text {
899
+ font-size: var(--font-size-xs);
900
+ }
901
+
902
+ .suggestion-tasks-header h4 {
903
+ font-size: var(--font-size-base);
904
+ }
905
+ }
906
+
907
+ /* Loading state for suggestion cards */
908
+ .suggestion-task-card.loading {
909
+ pointer-events: none;
910
+ opacity: 0.6;
911
+ }
912
+
913
+ .suggestion-task-card.loading .suggestion-card-icon {
914
+ animation: pulse 1.5s ease-in-out infinite;
915
+ }
916
+
917
+ @keyframes pulse {
918
+ 0%, 100% {
919
+ opacity: 1;
920
+ }
921
+ 50% {
922
+ opacity: 0.7;
923
+ }
924
+ }
925
+
926
+ /* Success state when card is clicked */
927
+ .suggestion-task-card.success {
928
+ border-color: var(--accent-color);
929
+ background: rgba(40, 167, 69, 0.05);
930
+ }
931
+
932
+ .suggestion-task-card.success .suggestion-card-icon {
933
+ background: var(--accent-color);
574
934
  }
@@ -426,4 +426,143 @@ select.task-running-disabled {
426
426
  color: var(--danger-color);
427
427
  font-size: var(--font-size-sm);
428
428
  text-align: center;
429
+ }
430
+
431
+ /* Tab Selection Dropdown */
432
+ .tab-selector-dropdown {
433
+ position: fixed !important;
434
+ z-index: 1000;
435
+ background: var(--bg-primary);
436
+ border: 1px solid var(--border-color);
437
+ border-radius: var(--radius-md);
438
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
439
+ max-height: 300px;
440
+ overflow: hidden;
441
+ display: none;
442
+ }
443
+
444
+ .tab-selector-header {
445
+ display: flex;
446
+ align-items: center;
447
+ justify-content: space-between;
448
+ padding: var(--spacing-sm) var(--spacing-md);
449
+ background: var(--bg-secondary);
450
+ border-bottom: 1px solid var(--border-color);
451
+ }
452
+
453
+ .tab-selector-title {
454
+ font-size: var(--font-size-sm);
455
+ font-weight: var(--font-weight-medium);
456
+ color: var(--text-primary);
457
+ }
458
+
459
+ .tab-selector-close {
460
+ width: 24px;
461
+ height: 24px;
462
+ border: none;
463
+ background: none;
464
+ font-size: 18px;
465
+ color: var(--text-muted);
466
+ cursor: pointer;
467
+ border-radius: var(--radius-sm);
468
+ display: flex;
469
+ align-items: center;
470
+ justify-content: center;
471
+ transition: all var(--transition-fast);
472
+ }
473
+
474
+ .tab-selector-close:hover {
475
+ background: var(--bg-hover);
476
+ color: var(--text-primary);
477
+ }
478
+
479
+ .tab-selector-content {
480
+ max-height: 200px;
481
+ overflow-y: auto;
482
+ padding: var(--spacing-xs);
483
+ }
484
+
485
+ .tab-selector-controls {
486
+ padding: var(--spacing-xs) var(--spacing-sm);
487
+ border-bottom: 1px solid var(--border-color);
488
+ margin-bottom: var(--spacing-xs);
489
+ }
490
+
491
+ .select-all-option {
492
+ font-weight: var(--font-weight-medium);
493
+ color: var(--primary-color);
494
+ }
495
+
496
+ .tab-options-list {
497
+ display: flex;
498
+ flex-direction: column;
499
+ gap: 2px;
500
+ }
501
+
502
+ .tab-option {
503
+ display: flex;
504
+ align-items: center;
505
+ gap: var(--spacing-sm);
506
+ padding: var(--spacing-xs) var(--spacing-sm);
507
+ cursor: pointer;
508
+ border-radius: var(--radius-sm);
509
+ transition: background-color var(--transition-fast);
510
+ }
511
+
512
+ .tab-option:hover {
513
+ background: var(--bg-hover);
514
+ }
515
+
516
+ .tab-option.active-tab {
517
+ background: rgba(144, 238, 144, 0.3);
518
+ border: 1px solid rgba(144, 238, 144, 0.6);
519
+ box-shadow: 0 2px 4px rgba(144, 238, 144, 0.2);
520
+ }
521
+
522
+ .tab-option.active-tab .tab-name {
523
+ color: #2d5a2d;
524
+ font-weight: var(--font-weight-medium);
525
+ }
526
+
527
+ .tab-option.active-tab .tab-id {
528
+ color: #1a4d1a;
529
+ font-weight: var(--font-weight-medium);
530
+ }
531
+
532
+ .tab-radio {
533
+ width: 16px;
534
+ height: 16px;
535
+ cursor: pointer;
536
+ }
537
+
538
+ .tab-name {
539
+ flex: 1;
540
+ font-size: var(--font-size-sm);
541
+ color: var(--text-primary);
542
+ overflow: hidden;
543
+ text-overflow: ellipsis;
544
+ white-space: nowrap;
545
+ }
546
+
547
+ /* Remove footer and buttons for single-select auto-confirm */
548
+
549
+ /* Tab selection indicator in textarea */
550
+ .task-input.has-selected-tabs {
551
+ border-color: var(--primary-color);
552
+ background: rgba(0, 122, 204, 0.02);
553
+ }
554
+
555
+ /* Selected tabs display */
556
+ .selected-tabs-indicator {
557
+ position: absolute;
558
+ bottom: 8px;
559
+ left: 8px;
560
+ background: var(--primary-color);
561
+ color: white;
562
+ padding: 2px 6px;
563
+ border-radius: var(--radius-sm);
564
+ font-size: 10px;
565
+ font-weight: var(--font-weight-medium);
566
+ pointer-events: none;
567
+ z-index: 2;
429
568
  }
vibe_surf/cli.py CHANGED
@@ -41,15 +41,8 @@ VIBESURF_LOGO = """
41
41
  console = Console()
42
42
 
43
43
  # Add logger import for the workspace directory logging
44
- try:
45
- import logging
46
- logger = logging.getLogger(__name__)
47
- logging.basicConfig(level=logging.INFO)
48
- except ImportError:
49
- class SimpleLogger:
50
- def info(self, msg):
51
- console.print(f"[dim]{msg}[/dim]")
52
- logger = SimpleLogger()
44
+ from vibe_surf.logger import get_logger
45
+ logger = get_logger(__name__)
53
46
 
54
47
 
55
48
  def find_chrome_browser() -> Optional[str]:
@@ -348,19 +341,8 @@ def start_backend(port: int) -> None:
348
341
  def get_browser_execution_path() -> Optional[str]:
349
342
  """Get browser execution path from envs.json or environment variables."""
350
343
  # 1. Load environment variables
351
- env_workspace_dir = os.getenv("VIBESURF_WORKSPACE", "")
352
- if not env_workspace_dir or not env_workspace_dir.strip():
353
- # Set default workspace directory based on OS
354
- if platform.system() == "Windows":
355
- default_workspace = os.path.join(os.environ.get("APPDATA", ""), "VibeSurf")
356
- elif platform.system() == "Darwin": # macOS
357
- default_workspace = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "VibeSurf")
358
- else: # Linux and others
359
- default_workspace = os.path.join(os.path.expanduser("~"), ".vibesurf")
360
- workspace_dir = default_workspace
361
- else:
362
- workspace_dir = env_workspace_dir
363
- workspace_dir = os.path.abspath(workspace_dir)
344
+ from .common import get_workspace_dir
345
+ workspace_dir = get_workspace_dir()
364
346
  os.makedirs(workspace_dir, exist_ok=True)
365
347
  logger.info("WorkSpace directory: {}".format(workspace_dir))
366
348
 
vibe_surf/common.py ADDED
@@ -0,0 +1,35 @@
1
+ """
2
+ Common utilities and configurations for VibeSurf.
3
+ """
4
+ import os
5
+ import platform
6
+ from dotenv import load_dotenv
7
+
8
+ project_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
9
+
10
+ load_dotenv(os.path.join(project_dir, ".env"))
11
+
12
+
13
+ def get_workspace_dir():
14
+ """
15
+ Get the workspace directory for VibeSurf.
16
+
17
+ Returns:
18
+ str: The absolute path to the workspace directory.
19
+ """
20
+ env_workspace_dir = os.getenv("VIBESURF_WORKSPACE", "")
21
+ if not env_workspace_dir or not env_workspace_dir.strip():
22
+ # Set default workspace directory based on OS
23
+ if platform.system() == "Windows":
24
+ default_workspace = os.path.join(os.environ.get("APPDATA", ""), "VibeSurf")
25
+ elif platform.system() == "Darwin": # macOS
26
+ default_workspace = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "VibeSurf")
27
+ else: # Linux and others
28
+ default_workspace = os.path.join(os.path.expanduser("~"), ".vibesurf")
29
+ workspace_dir = default_workspace
30
+ else:
31
+ workspace_dir = env_workspace_dir
32
+
33
+ workspace_dir = os.path.abspath(workspace_dir)
34
+ os.makedirs(workspace_dir, exist_ok=True)
35
+ return workspace_dir