vg-coder-cli 2.0.24 → 2.0.26

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.
@@ -94,44 +94,84 @@ body.resizing {
94
94
  padding-right: 0px;
95
95
  }
96
96
 
97
- /* --- COMPONENT STYLES --- */
97
+ /* --- HEADER REDESIGN --- */
98
98
  .header {
99
99
  display: flex;
100
- justify-content: space-between;
101
- align-items: center; /* Align items vertically center */
100
+ flex-direction: column;
101
+ gap: 6px; /* Space between rows */
102
102
  margin-bottom: 15px;
103
103
  }
104
104
 
105
- .header-content {
105
+ .header-top-row {
106
+ display: flex;
107
+ justify-content: space-between;
108
+ align-items: center;
109
+ width: 100%;
110
+ }
111
+
112
+ .header-left-group {
106
113
  display: flex;
107
114
  align-items: center;
108
115
  gap: 12px;
116
+ flex: 1; /* Take available space */
117
+ min-width: 0; /* Enable truncation */
109
118
  }
110
119
 
111
120
  .status {
112
121
  font-size: 14px;
113
122
  color: var(--ios-green);
114
123
  line-height: 1;
124
+ flex-shrink: 0;
115
125
  }
116
126
 
117
- /* NEW: Project Info Styles */
118
- .project-info {
127
+ /* Project Switcher replaces Project Title */
128
+ .project-switcher {
119
129
  display: flex;
120
- flex-direction: column;
121
- justify-content: center;
122
- line-height: 1.2;
130
+ align-items: center;
131
+ gap: 8px;
132
+ flex: 1;
133
+ min-width: 0;
123
134
  }
124
135
 
125
- .project-name {
126
- font-weight: 700;
127
- font-size: 16px;
136
+ .project-selector {
137
+ padding: 5px 10px;
138
+ background: var(--ios-input-bg);
139
+ border: 1px solid var(--ios-separator);
140
+ border-radius: 6px;
141
+ font-size: 14px; /* Slightly bigger font like a title */
142
+ font-weight: 700; /* Bold like a title */
128
143
  color: var(--text-primary);
144
+ cursor: pointer;
145
+ outline: none;
146
+ transition: all 0.2s;
147
+ max-width: 100%;
148
+ text-overflow: ellipsis;
129
149
  }
130
150
 
131
- .project-meta {
132
- font-size: 11px;
151
+ .project-selector:hover {
152
+ border-color: var(--ios-blue);
153
+ }
154
+
155
+ .project-selector:focus {
156
+ border-color: var(--ios-blue);
157
+ box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.1);
158
+ }
159
+
160
+ .project-count {
161
+ font-size: 10px;
133
162
  color: var(--text-secondary);
134
- font-family: monospace;
163
+ background: var(--ios-gray-light);
164
+ padding: 3px 7px;
165
+ border-radius: 10px;
166
+ font-weight: 600;
167
+ white-space: nowrap;
168
+ }
169
+
170
+ .header-actions {
171
+ display: flex;
172
+ align-items: center;
173
+ gap: 8px;
174
+ flex-shrink: 0;
135
175
  }
136
176
 
137
177
  .theme-toggle {
@@ -144,6 +184,45 @@ body.resizing {
144
184
  box-shadow: 0 2px 5px var(--shadow-color);
145
185
  }
146
186
 
187
+ .stop-server-btn {
188
+ width: 28px;
189
+ height: 28px;
190
+ border-radius: 50%;
191
+ border: none;
192
+ background: var(--ios-red);
193
+ color: white;
194
+ cursor: pointer;
195
+ box-shadow: 0 2px 5px var(--shadow-color);
196
+ display: flex;
197
+ align-items: center;
198
+ justify-content: center;
199
+ font-size: 14px;
200
+ transition: all 0.2s;
201
+ }
202
+
203
+ .stop-server-btn:hover {
204
+ opacity: 0.8;
205
+ transform: scale(1.05);
206
+ }
207
+
208
+ /* Bottom Row - Full Width Metadata */
209
+ .header-bottom-row {
210
+ width: 100%;
211
+ padding-left: 2px;
212
+ }
213
+
214
+ .project-meta {
215
+ font-size: 11px;
216
+ color: var(--text-secondary);
217
+ font-family: monospace;
218
+ white-space: nowrap;
219
+ overflow: hidden;
220
+ text-overflow: ellipsis;
221
+ display: block;
222
+ width: 100%;
223
+ line-height: 1.4;
224
+ }
225
+
147
226
  .system-prompt-card,
148
227
  .endpoint-card {
149
228
  background: var(--ios-card);
@@ -343,8 +422,304 @@ body.resizing {
343
422
  flex: none;
344
423
  width: 100%;
345
424
  max-width: 100%;
346
- height: 50vh;
425
+ height: 100vh;
347
426
  border-right: none;
348
427
  border-bottom: 1px solid var(--ios-separator);
349
428
  }
350
429
  }
430
+
431
+ /* --- SAVED COMMANDS STYLES --- */
432
+ .saved-commands-panel {
433
+ margin-bottom: 12px;
434
+ background: var(--ios-card);
435
+ }
436
+
437
+ .saved-commands-header {
438
+ display: flex;
439
+ justify-content: space-between;
440
+ align-items: center;
441
+ margin-bottom: 10px;
442
+ }
443
+
444
+ .saved-commands-title {
445
+ display: flex;
446
+ align-items: center;
447
+ gap: 8px;
448
+ font-weight: 600;
449
+ font-size: 13px;
450
+ color: var(--text-primary);
451
+ }
452
+
453
+ .command-icon-header {
454
+ font-size: 16px;
455
+ }
456
+
457
+ .saved-commands-actions {
458
+ display: flex;
459
+ gap: 6px;
460
+ }
461
+
462
+ .btn-new-terminal {
463
+ width: 28px;
464
+ height: 28px;
465
+ border-radius: 6px;
466
+ background: var(--ios-gray-light);
467
+ border: 1px solid var(--ios-separator);
468
+ color: var(--text-primary);
469
+ cursor: pointer;
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: center;
473
+ font-size: 14px;
474
+ transition: all 0.2s;
475
+ }
476
+
477
+ .btn-new-terminal:hover {
478
+ background: var(--ios-separator);
479
+ transform: scale(1.05);
480
+ }
481
+
482
+ .btn-add-command {
483
+ width: 28px;
484
+ height: 28px;
485
+ border-radius: 6px;
486
+ background: var(--ios-blue);
487
+ border: none;
488
+ color: white;
489
+ cursor: pointer;
490
+ display: flex;
491
+ align-items: center;
492
+ justify-content: center;
493
+ font-size: 14px;
494
+ transition: all 0.2s;
495
+ }
496
+
497
+ .btn-add-command:hover {
498
+ opacity: 0.8;
499
+ transform: scale(1.05);
500
+ }
501
+
502
+ .saved-commands-content {
503
+ margin-top: 0;
504
+ }
505
+
506
+ /* NEW: Grid Layout for Commands */
507
+ .commands-list {
508
+ display: grid;
509
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
510
+ gap: 8px;
511
+ max-height: 300px;
512
+ overflow-y: auto;
513
+ padding-right: 2px; /* For scrollbar */
514
+ }
515
+
516
+ /* Custom Scrollbar for list */
517
+ .commands-list::-webkit-scrollbar {
518
+ width: 4px;
519
+ }
520
+ .commands-list::-webkit-scrollbar-thumb {
521
+ background: var(--ios-separator);
522
+ border-radius: 2px;
523
+ }
524
+
525
+ .command-card {
526
+ display: flex;
527
+ justify-content: space-between;
528
+ align-items: center;
529
+ padding: 6px 8px; /* Tighter padding */
530
+ background: var(--ios-input-bg);
531
+ border-radius: 6px;
532
+ cursor: pointer;
533
+ transition: all 0.2s;
534
+ border: 1px solid transparent;
535
+ height: 42px; /* Fixed height for consistency */
536
+ overflow: hidden;
537
+ }
538
+
539
+ .command-card:hover {
540
+ background: var(--ios-gray-light);
541
+ border-color: var(--ios-blue);
542
+ transform: translateY(-1px);
543
+ }
544
+
545
+ .command-card-main {
546
+ display: flex;
547
+ align-items: center;
548
+ gap: 8px;
549
+ flex: 1;
550
+ min-width: 0; /* Critical for truncation */
551
+ }
552
+
553
+ .command-icon {
554
+ font-size: 16px;
555
+ flex-shrink: 0;
556
+ width: 20px;
557
+ text-align: center;
558
+ }
559
+
560
+ .command-info {
561
+ display: flex;
562
+ flex-direction: column;
563
+ gap: 1px; /* Tighter gap */
564
+ min-width: 0;
565
+ flex: 1;
566
+ }
567
+
568
+ .command-name {
569
+ font-weight: 600;
570
+ font-size: 12px;
571
+ color: var(--text-primary);
572
+ white-space: nowrap;
573
+ overflow: hidden;
574
+ text-overflow: ellipsis;
575
+ line-height: 1.2;
576
+ }
577
+
578
+ .command-text {
579
+ font-family: monospace;
580
+ font-size: 10px;
581
+ color: var(--text-secondary);
582
+ white-space: nowrap;
583
+ overflow: hidden;
584
+ text-overflow: ellipsis;
585
+ line-height: 1.2;
586
+ }
587
+
588
+ .command-card-actions {
589
+ display: flex;
590
+ gap: 2px;
591
+ opacity: 0;
592
+ transition: opacity 0.2s;
593
+ margin-left: 4px;
594
+ flex-shrink: 0;
595
+ background: var(--ios-gray-light); /* Ensure visibility over background */
596
+ border-radius: 4px;
597
+ }
598
+
599
+ .command-card:hover .command-card-actions {
600
+ opacity: 1;
601
+ }
602
+
603
+ .command-action-btn {
604
+ width: 22px;
605
+ height: 22px;
606
+ border: none;
607
+ background: transparent;
608
+ border-radius: 4px;
609
+ cursor: pointer;
610
+ display: flex;
611
+ align-items: center;
612
+ justify-content: center;
613
+ font-size: 12px;
614
+ color: var(--text-secondary);
615
+ transition: all 0.2s;
616
+ }
617
+
618
+ .command-action-btn:hover {
619
+ background: rgba(0, 0, 0, 0.1);
620
+ color: var(--text-primary);
621
+ transform: scale(1.1);
622
+ }
623
+
624
+ /* Modal Styles */
625
+ .modal {
626
+ display: none;
627
+ position: fixed;
628
+ top: 0;
629
+ left: 0;
630
+ width: 100%;
631
+ height: 100%;
632
+ background: rgba(0, 0, 0, 0.5);
633
+ z-index: 10000;
634
+ align-items: center;
635
+ justify-content: center;
636
+ }
637
+
638
+ .modal-content {
639
+ background: var(--ios-card);
640
+ border-radius: 12px;
641
+ padding: 20px;
642
+ width: 90%;
643
+ max-width: 400px;
644
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
645
+ }
646
+
647
+ .modal-content h3 {
648
+ margin: 0 0 15px 0;
649
+ font-size: 16px;
650
+ color: var(--text-primary);
651
+ }
652
+
653
+ .modal-content .form-group {
654
+ margin-bottom: 15px;
655
+ }
656
+
657
+ .modal-content .form-group label {
658
+ display: block;
659
+ margin-bottom: 5px;
660
+ font-size: 12px;
661
+ font-weight: 600;
662
+ color: var(--text-secondary);
663
+ }
664
+
665
+ .modal-content .form-group input {
666
+ width: 100%;
667
+ padding: 8px 12px;
668
+ background: var(--ios-input-bg);
669
+ border: 1px solid var(--ios-separator);
670
+ border-radius: 8px;
671
+ font-size: 13px;
672
+ color: var(--text-primary);
673
+ }
674
+
675
+ .modal-content .form-group input:focus {
676
+ outline: none;
677
+ border-color: var(--ios-blue);
678
+ }
679
+
680
+ .modal-actions {
681
+ display: flex;
682
+ gap: 10px;
683
+ margin-top: 20px;
684
+ }
685
+
686
+ .modal-actions .btn {
687
+ flex: 1;
688
+ padding: 10px;
689
+ border: none;
690
+ border-radius: 8px;
691
+ font-size: 13px;
692
+ font-weight: 600;
693
+ cursor: pointer;
694
+ transition: all 0.2s;
695
+ }
696
+
697
+ .modal-actions .btn:first-child {
698
+ background: var(--ios-gray-light);
699
+ color: var(--text-primary);
700
+ }
701
+
702
+ .modal-actions .btn:first-child:hover {
703
+ background: var(--ios-separator);
704
+ }
705
+
706
+ .modal-actions .btn-primary {
707
+ background: var(--ios-blue);
708
+ color: white;
709
+ }
710
+
711
+ .modal-actions .btn-primary:hover {
712
+ opacity: 0.9;
713
+ }
714
+
715
+ .endpoint-title-group {
716
+ display: flex;
717
+ align-items: center;
718
+ gap: 8px;
719
+ }
720
+
721
+ .toggle-icon {
722
+ font-size: 12px;
723
+ color: var(--text-secondary);
724
+ transition: transform 0.2s;
725
+ }
@@ -60,30 +60,67 @@
60
60
  <!-- CỘT TRÁI: Giao diện VG Coder -->
61
61
  <div class="left-panel">
62
62
  <div class="container">
63
+ <!-- Header Layout Redesign -->
63
64
  <div class="header">
64
- <div class="header-content">
65
- <!-- Status Dot -->
66
- <span class="status" id="status" style="font-size: 14px;">●</span>
67
-
68
- <!-- NEW: Project Info Section -->
69
- <div class="project-info">
70
- <div class="project-name" id="project-name">Loading...</div>
71
- <div class="project-meta" id="project-meta">...</div>
65
+ <!-- Top Row: Status, Switcher (Title), Actions -->
66
+ <div class="header-top-row">
67
+ <div class="header-left-group">
68
+ <span class="status" id="status" style="font-size: 14px;">●</span>
69
+
70
+ <!-- Project Switcher takes primary spot -->
71
+ <div class="project-switcher">
72
+ <select id="project-selector" class="project-selector" onchange="window.switchProject(this.value)" title="Switch Project">
73
+ <option value="">Loading...</option>
74
+ </select>
75
+ <span class="project-count" id="project-count">1 project</span>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Right Actions -->
80
+ <div class="header-actions">
81
+ <button class="stop-server-btn" id="stop-server-btn" onclick="window.stopServer()" title="Stop Server">
82
+ 🛑
83
+ </button>
84
+ <button class="theme-toggle" id="theme-toggle" title="Toggle Dark Mode">
85
+ <span id="theme-icon">🌙</span>
86
+ </button>
72
87
  </div>
73
88
  </div>
74
- <button class="theme-toggle" id="theme-toggle" title="Toggle Dark Mode">
75
- <span id="theme-icon">🌙</span>
76
- </button>
89
+
90
+ <!-- Bottom Row: Meta Info (Path/Type) -->
91
+ <div class="header-bottom-row">
92
+ <div class="project-meta" id="project-meta">...</div>
93
+ <!-- Hidden element to keep JS happy -->
94
+ <div id="project-name" style="display: none;"></div>
95
+ </div>
77
96
  </div>
78
97
 
79
- <!-- Quick Actions -->
80
- <div class="endpoint-card"
81
- style="display: flex; gap: 10px; align-items: center; justify-content: space-between;">
82
- <span style="font-weight: 600;">Tools:</span>
83
- <button class="btn" onclick="createNewTerminal()"
84
- style="background: #252526; border: 1px solid #444;">
85
- <span>🖥️</span> New Terminal
86
- </button>
98
+ <!-- Saved Commands Panel -->
99
+ <div class="endpoint-card saved-commands-panel">
100
+ <div class="saved-commands-header">
101
+ <div class="saved-commands-title">
102
+ <span class="command-icon-header">💾</span>
103
+ <span>Saved Commands</span>
104
+ </div>
105
+ <div class="saved-commands-actions">
106
+ <button class="btn-new-terminal" onclick="createNewTerminal()" title="New Terminal">
107
+ 🖥️
108
+ </button>
109
+ <button class="btn-add-command" onclick="openAddCommandModal()" title="Add Command">
110
+
111
+ </button>
112
+ </div>
113
+ </div>
114
+ <div class="saved-commands-content" id="saved-commands-content">
115
+ <div id="commands-list" class="commands-list">
116
+ <!-- Commands will be rendered here -->
117
+ </div>
118
+ <div class="empty-state" id="commands-empty-state" style="display: none;">
119
+ <p style="color: #888; text-align: center; padding: 15px 10px; font-size: 12px; margin: 0;">
120
+ Click ➕ to add a command
121
+ </p>
122
+ </div>
123
+ </div>
87
124
  </div>
88
125
 
89
126
  <!-- System Prompt Section -->
@@ -280,6 +317,100 @@
280
317
 
281
318
  <div id="floating-terminals-layer"></div>
282
319
  <div class="toast" id="toast"></div>
320
+
321
+ <!-- Add/Edit Command Modal -->
322
+ <div id="command-modal" class="modal" style="display: none;">
323
+ <div class="modal-content">
324
+ <h3 id="modal-title">Add Command</h3>
325
+ <form id="command-form">
326
+ <div class="form-group">
327
+ <label>Icon (emoji)</label>
328
+ <input type="text" id="command-icon" placeholder="🚀" maxlength="2" required>
329
+ </div>
330
+ <div class="form-group">
331
+ <label>Name</label>
332
+ <input type="text" id="command-name" placeholder="Run Dev Server" required>
333
+ </div>
334
+ <div class="form-group">
335
+ <label>Command</label>
336
+ <input type="text" id="command-text" placeholder="npm run dev" required>
337
+ </div>
338
+ <div class="modal-actions">
339
+ <button type="button" class="btn" onclick="closeCommandModal()">Cancel</button>
340
+ <button type="submit" class="btn btn-primary">Save</button>
341
+ </div>
342
+ </form>
343
+ </div>
344
+ </div>
345
+
346
+ <!-- VG Coder Parent Context Detector -->
347
+ <script>
348
+ // Listener for nested iframe detection
349
+ // When extension's controller.ts sends VG_CODER_PING, we reply with VG_CODER_PARENT
350
+ window.addEventListener('message', (event) => {
351
+ if (event.data?.type === 'VG_CODER_PING') {
352
+ // Confirm this is VG Coder parent context
353
+ event.source.postMessage({ type: 'VG_CODER_PARENT' }, '*');
354
+ console.log('📡 Responded to VG_CODER_PING from iframe:', event.origin);
355
+ }
356
+ });
357
+ </script>
358
+
359
+ <!-- Embedded Mode Detection -->
360
+ <script>
361
+ // When dashboard is loaded with ?embedded=true (inside AI chat page),
362
+ // hide the AI tab and iframe to prevent nested structure
363
+ (function() {
364
+ const urlParams = new URLSearchParams(window.location.search);
365
+ const isEmbedded = urlParams.has('embedded');
366
+
367
+ if (isEmbedded) {
368
+ console.log('🎯 Embedded mode detected - hiding AI iframe tab');
369
+
370
+ // Wait for DOM to be ready
371
+ if (document.readyState === 'loading') {
372
+ document.addEventListener('DOMContentLoaded', hideAITab);
373
+ } else {
374
+ hideAITab();
375
+ }
376
+
377
+ function hideAITab() {
378
+ // Hide AI tab
379
+ const aiTab = document.getElementById('ai-tab');
380
+ if (aiTab) {
381
+ aiTab.style.display = 'none';
382
+ console.log('✅ AI tab hidden');
383
+ }
384
+
385
+ // Hide AI iframe container
386
+ const aiContainer = document.querySelector('.ai-iframe-container');
387
+ if (aiContainer) {
388
+ aiContainer.style.display = 'none';
389
+ console.log('✅ AI iframe container hidden');
390
+ }
391
+
392
+ // Switch to first editor tab if exists, or show monaco by default
393
+ const fileTabsContainer = document.getElementById('file-tabs-container');
394
+ if (fileTabsContainer && fileTabsContainer.children.length > 0) {
395
+ // Click first file tab
396
+ const firstTab = fileTabsContainer.children[0];
397
+ if (firstTab) firstTab.click();
398
+ } else {
399
+ // Show monaco editor as default
400
+ const monacoContainer = document.getElementById('monaco-container');
401
+ if (monacoContainer) {
402
+ monacoContainer.classList.remove('view-mode-hidden');
403
+ }
404
+ }
405
+ }
406
+ }
407
+ })();
408
+ </script>
409
+
410
+ <!-- Smart Log Copy Utilities -->
411
+ <script src="/js/utils/log-utils.js"></script>
412
+ <script src="/js/utils/smart-copy-engine.js"></script>
413
+
283
414
  <script type="module" src="/js/main.js"></script>
284
415
  </body>
285
416