agentgui 1.0.524 → 1.0.526

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.
@@ -5,10 +5,10 @@ import path from 'path';
5
5
 
6
6
  const isWindows = os.platform() === 'win32';
7
7
  const TOOLS = [
8
- { id: 'gm-oc', name: 'gm-oc', pkg: 'gm-oc', pluginId: 'gm-oc' },
9
- { id: 'gm-gc', name: 'gm-gc', pkg: 'gm-gc', pluginId: 'gm' },
10
- { id: 'gm-kilo', name: 'gm-kilo', pkg: 'gm-kilo', pluginId: 'gm-kilo' },
11
- { id: 'gm-cc', name: 'gm-cc', pkg: 'gm-cc', pluginId: 'gm-cc' },
8
+ { id: 'gm-cc', name: 'gm-cc', pkg: '@anthropic-ai/claude-code', pluginId: 'gm-cc' },
9
+ { id: 'gm-oc', name: 'gm-oc', pkg: 'opencode-ai', pluginId: 'gm-oc' },
10
+ { id: 'gm-gc', name: 'gm-gc', pkg: '@google/gemini-cli', pluginId: 'gm' },
11
+ { id: 'gm-kilo', name: 'gm-kilo', pkg: '@kilocode/cli', pluginId: 'gm-kilo' },
12
12
  ];
13
13
 
14
14
  const statusCache = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.524",
3
+ "version": "1.0.526",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -40,7 +40,7 @@
40
40
  background: var(--color-bg-secondary);
41
41
  border-radius: 1rem;
42
42
  width: 90%;
43
- max-width: 32rem;
43
+ max-width: 600px;
44
44
  max-height: 80vh;
45
45
  display: flex;
46
46
  flex-direction: column;
@@ -49,21 +49,91 @@
49
49
  font-family: system-ui, -apple-system, sans-serif;
50
50
  }
51
51
 
52
+ @media (max-width: 768px) {
53
+ .tools-popup-content {
54
+ max-width: 90vw;
55
+ width: 100%;
56
+ }
57
+ }
58
+
59
+ @media (max-width: 480px) {
60
+ .tools-popup-content {
61
+ max-width: 95vw;
62
+ width: 100%;
63
+ max-height: 85vh;
64
+ }
65
+
66
+ .tools-popup-header {
67
+ flex-direction: column;
68
+ align-items: flex-start;
69
+ gap: 0.5rem;
70
+ }
71
+
72
+ .tools-popup-header-controls {
73
+ width: 100%;
74
+ flex-wrap: wrap;
75
+ }
76
+ }
77
+
52
78
  .tools-popup-header {
53
79
  display: flex;
54
80
  justify-content: space-between;
55
81
  align-items: center;
56
- padding: 1.25rem 1.5rem;
82
+ padding: 0.875rem 1.25rem;
57
83
  flex-shrink: 0;
58
84
  border-bottom: 1px solid var(--color-border);
85
+ gap: 0.75rem;
59
86
  }
60
87
 
61
88
  .tools-popup-header h2 {
62
89
  margin: 0;
63
- font-size: 1.25rem;
90
+ font-size: 1rem;
64
91
  font-weight: 700;
65
92
  }
66
93
 
94
+ .tools-popup-header-controls {
95
+ display: flex;
96
+ align-items: center;
97
+ gap: 0.75rem;
98
+ flex-shrink: 0;
99
+ }
100
+
101
+ .tools-voice-toggle {
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 0.5rem;
105
+ font-size: 0.8rem;
106
+ cursor: pointer;
107
+ user-select: none;
108
+ }
109
+
110
+ .tools-voice-toggle input {
111
+ width: 0.875rem;
112
+ height: 0.875rem;
113
+ cursor: pointer;
114
+ }
115
+
116
+ .tools-voice-selector {
117
+ padding: 0.35rem 0.5rem;
118
+ font-size: 0.75rem;
119
+ border-radius: 0.3rem;
120
+ border: 1px solid var(--color-border);
121
+ background: var(--color-bg-primary);
122
+ color: var(--color-text-primary);
123
+ cursor: pointer;
124
+ transition: border-color 0.2s;
125
+ }
126
+
127
+ .tools-voice-selector:hover {
128
+ border-color: var(--color-primary);
129
+ }
130
+
131
+ .tools-voice-selector:focus {
132
+ outline: none;
133
+ border-color: var(--color-primary);
134
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
135
+ }
136
+
67
137
  .tools-popup-close {
68
138
  background: none;
69
139
  border: none;
@@ -83,9 +153,21 @@
83
153
  flex: 1;
84
154
  overflow-y: auto;
85
155
  padding: 1rem;
86
- display: flex;
87
- flex-direction: column;
88
- gap: 0.75rem;
156
+ display: grid;
157
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
158
+ gap: 1rem;
159
+ }
160
+
161
+ @media (max-width: 768px) {
162
+ .tools-popup-scroll {
163
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
164
+ }
165
+ }
166
+
167
+ @media (max-width: 480px) {
168
+ .tools-popup-scroll {
169
+ grid-template-columns: 1fr;
170
+ }
89
171
  }
90
172
 
91
173
  .tools-popup-scroll::-webkit-scrollbar {
@@ -106,43 +188,50 @@
106
188
  }
107
189
 
108
190
  .tool-item {
109
- padding: 1rem;
191
+ padding: 0.75rem;
110
192
  border: 1px solid var(--color-border);
111
193
  border-radius: 0.5rem;
112
194
  background: var(--color-bg-primary);
113
195
  display: flex;
114
196
  flex-direction: column;
115
- gap: 0.5rem;
197
+ gap: 0.375rem;
116
198
  transition: border-color 0.2s, background-color 0.2s;
199
+ min-height: 120px;
200
+ justify-content: space-between;
117
201
  }
118
202
 
119
203
  .tool-item:hover {
120
204
  border-color: var(--color-primary);
121
205
  background: var(--color-bg-secondary);
206
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
122
207
  }
123
208
 
124
209
  .tool-header {
125
210
  display: flex;
126
- align-items: center;
127
- gap: 0.75rem;
211
+ align-items: flex-start;
212
+ gap: 0.5rem;
128
213
  justify-content: space-between;
214
+ flex-wrap: wrap;
129
215
  }
130
216
 
131
217
  .tool-name {
132
218
  font-weight: 600;
133
- font-size: 0.95rem;
219
+ font-size: 0.9rem;
134
220
  flex: 1;
221
+ word-break: break-word;
135
222
  }
136
223
 
137
224
  .tool-status-indicator {
138
225
  display: inline-flex;
139
226
  align-items: center;
140
- gap: 0.375rem;
141
- font-size: 0.8rem;
142
- padding: 0.25rem 0.5rem;
227
+ gap: 0.25rem;
228
+ font-size: 0.7rem;
229
+ padding: 0.2rem 0.4rem;
143
230
  border-radius: 0.25rem;
144
231
  background: var(--color-bg-tertiary);
145
232
  color: var(--color-text-secondary);
233
+ white-space: nowrap;
234
+ flex-shrink: 0;
146
235
  }
147
236
 
148
237
  .tool-status-indicator.installed {
@@ -179,24 +268,28 @@
179
268
  }
180
269
 
181
270
  .tool-details {
182
- font-size: 0.8rem;
271
+ font-size: 0.7rem;
183
272
  color: var(--color-text-secondary);
184
- display: flex;
273
+ display: none;
185
274
  align-items: center;
186
275
  gap: 0.5rem;
276
+ line-height: 1.3;
277
+ max-height: 2.6em;
278
+ overflow: hidden;
187
279
  }
188
280
 
189
281
  .tool-progress-container {
190
282
  display: flex;
191
283
  flex-direction: column;
192
- gap: 0.25rem;
284
+ gap: 0.15rem;
285
+ margin-top: 0.25rem;
193
286
  }
194
287
 
195
288
  .tool-progress-bar {
196
289
  width: 100%;
197
- height: 0.375rem;
290
+ height: 0.25rem;
198
291
  background: var(--color-bg-tertiary);
199
- border-radius: 0.1875rem;
292
+ border-radius: 0.125rem;
200
293
  overflow: hidden;
201
294
  }
202
295
 
@@ -205,30 +298,31 @@
205
298
  background: linear-gradient(90deg, #3b82f6, #2563eb);
206
299
  width: 0%;
207
300
  transition: width 0.3s ease;
208
- border-radius: 0.1875rem;
301
+ border-radius: 0.125rem;
209
302
  }
210
303
 
211
304
  .tool-progress-text {
212
- font-size: 0.75rem;
305
+ font-size: 0.65rem;
213
306
  color: var(--color-text-secondary);
214
307
  }
215
308
 
216
309
  .tool-actions {
217
310
  display: flex;
218
- gap: 0.5rem;
311
+ gap: 0.4rem;
219
312
  flex-wrap: wrap;
313
+ margin-top: 0.25rem;
220
314
  }
221
315
 
222
316
  .tool-btn {
223
- padding: 0.5rem 0.875rem;
317
+ padding: 0.35rem 0.65rem;
224
318
  border: none;
225
- border-radius: 0.375rem;
319
+ border-radius: 0.3rem;
226
320
  cursor: pointer;
227
- font-size: 0.8rem;
321
+ font-size: 0.7rem;
228
322
  font-weight: 600;
229
323
  transition: all 0.2s;
230
324
  flex: 1;
231
- min-width: fit-content;
325
+ min-width: 60px;
232
326
  white-space: nowrap;
233
327
  }
234
328
 
@@ -259,12 +353,15 @@
259
353
  }
260
354
 
261
355
  .tool-error-message {
262
- font-size: 0.75rem;
356
+ font-size: 0.65rem;
263
357
  color: #ef4444;
264
358
  background: rgba(239, 68, 68, 0.1);
265
- padding: 0.5rem;
359
+ padding: 0.375rem;
266
360
  border-radius: 0.25rem;
267
361
  border-left: 2px solid #ef4444;
362
+ overflow: hidden;
363
+ text-overflow: ellipsis;
364
+ max-height: 1.5em;
268
365
  }
269
366
 
270
367
  .tools-popup-footer {
@@ -318,18 +415,21 @@
318
415
  .tool-versions {
319
416
  display: flex;
320
417
  flex-direction: column;
321
- gap: 0.25rem;
322
- font-size: 0.75rem;
418
+ gap: 0.15rem;
419
+ font-size: 0.65rem;
323
420
  color: var(--color-text-secondary);
324
- background: var(--color-bg-secondary);
325
- padding: 0.5rem;
421
+ background: transparent;
422
+ padding: 0;
326
423
  border-radius: 0.25rem;
424
+ line-height: 1.3;
327
425
  }
328
426
 
329
427
  .tool-version-item {
330
428
  display: flex;
331
429
  align-items: center;
332
- gap: 0.375rem;
430
+ gap: 0.25rem;
431
+ overflow: hidden;
432
+ text-overflow: ellipsis;
333
433
  }
334
434
 
335
435
  .tool-version-item strong {
package/static/index.html CHANGED
@@ -3125,8 +3125,19 @@
3125
3125
  <div class="tools-popup" id="toolsPopup">
3126
3126
  <div class="tools-popup-content" onclick="event.stopPropagation()">
3127
3127
  <div class="tools-popup-header">
3128
- <h2>Tools & Extensions</h2>
3129
- <button class="tools-popup-close" onclick="document.getElementById('toolsPopup').classList.remove('open')">×</button>
3128
+ <div style="display: flex; align-items: center; gap: 0.75rem; flex: 1;">
3129
+ <h2 style="margin: 0; font-size: 1rem;">Tools & Extensions</h2>
3130
+ </div>
3131
+ <div class="tools-popup-header-controls" style="display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0;">
3132
+ <label class="tools-voice-toggle" style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; cursor: pointer; user-select: none;">
3133
+ <input type="checkbox" id="toolsAutoSpeakToggle" style="width: 1rem; height: 1rem; cursor: pointer;">
3134
+ <span>Auto-speak</span>
3135
+ </label>
3136
+ <select class="tools-voice-selector" id="toolsVoiceSelector" style="padding: 0.4rem 0.6rem; font-size: 0.8rem; border-radius: 0.3rem; border: 1px solid var(--color-border); background: var(--color-bg-primary); color: var(--color-text-primary); cursor: pointer;">
3137
+ <option value="default">Voice</option>
3138
+ </select>
3139
+ <button class="tools-popup-close" onclick="document.getElementById('toolsPopup').classList.remove('open')" style="background: none; border: none; color: var(--color-text-secondary); font-size: 1.5rem; cursor: pointer; padding: 0; line-height: 1; transition: color 0.2s;">×</button>
3140
+ </div>
3130
3141
  </div>
3131
3142
  <div class="tools-popup-scroll"></div>
3132
3143
  <div class="tools-popup-footer">
@@ -13,9 +13,62 @@
13
13
  if (!btn.contains(e.target) && !popup.contains(e.target)) closePopup();
14
14
  });
15
15
  window.addEventListener('ws-message', onWsMessage);
16
+
17
+ // Initialize voice controls
18
+ initVoiceControls();
16
19
  refresh();
17
20
  }
18
21
 
22
+ function initVoiceControls() {
23
+ var autoSpeakToggle = document.getElementById('toolsAutoSpeakToggle');
24
+ var voiceSelector = document.getElementById('toolsVoiceSelector');
25
+
26
+ if (!autoSpeakToggle || !voiceSelector) return;
27
+
28
+ // Load saved preferences
29
+ var savedAutoSpeak = localStorage.getItem('toolsAutoSpeak') === 'true';
30
+ var savedVoice = localStorage.getItem('toolsVoice') || 'default';
31
+
32
+ autoSpeakToggle.checked = savedAutoSpeak;
33
+ voiceSelector.value = savedVoice;
34
+
35
+ // Listen for voice list updates
36
+ window.addEventListener('ws-message', function(e) {
37
+ var data = e.detail;
38
+ if (data && data.type === 'voice_list') {
39
+ updateVoiceSelector(data.voices);
40
+ }
41
+ });
42
+
43
+ // Save preferences on change
44
+ autoSpeakToggle.addEventListener('change', function() {
45
+ localStorage.setItem('toolsAutoSpeak', this.checked);
46
+ });
47
+
48
+ voiceSelector.addEventListener('change', function() {
49
+ localStorage.setItem('toolsVoice', this.value);
50
+ });
51
+ }
52
+
53
+ function updateVoiceSelector(voices) {
54
+ var voiceSelector = document.getElementById('toolsVoiceSelector');
55
+ if (!voiceSelector || !voices || !Array.isArray(voices)) return;
56
+
57
+ var currentValue = voiceSelector.value;
58
+ voiceSelector.innerHTML = '<option value="default">Voice</option>';
59
+
60
+ voices.forEach(function(voice) {
61
+ var option = document.createElement('option');
62
+ option.value = voice;
63
+ option.textContent = voice;
64
+ voiceSelector.appendChild(option);
65
+ });
66
+
67
+ if (voices.includes(currentValue)) {
68
+ voiceSelector.value = currentValue;
69
+ }
70
+ }
71
+
19
72
  function refresh() {
20
73
  fetchTools();
21
74
  }
@@ -200,42 +253,41 @@
200
253
  if (!scroll) return;
201
254
 
202
255
  if (tools.length === 0) {
203
- scroll.innerHTML = '<div class="tool-empty-state"><div class="tool-empty-state-icon">⚙️</div><div class="tool-empty-state-text">No tools available</div></div>';
256
+ scroll.innerHTML = '<div class="tool-empty-state" style="grid-column: 1 / -1;"><div class="tool-empty-state-icon">⚙️</div><div class="tool-empty-state-text">No tools available</div></div>';
204
257
  return;
205
258
  }
206
259
 
207
260
  scroll.innerHTML = tools.map(function(tool) {
208
261
  var statusClass = getStatusClass(tool);
209
262
  var isInstalling = tool.status === 'installing' || tool.status === 'updating';
210
- var hasAction = !tool.installed || tool.hasUpdate || tool.status === 'failed';
211
263
  var versionInfo = '';
212
264
  if (tool.installedVersion || tool.publishedVersion) {
213
265
  versionInfo = '<div class="tool-versions">';
214
266
  if (tool.installedVersion) {
215
- versionInfo += '<span class="tool-version-item">Installed: <strong>' + esc(tool.installedVersion) + '</strong></span>';
267
+ versionInfo += '<span class="tool-version-item">v' + esc(tool.installedVersion) + '</span>';
216
268
  }
217
- if (tool.publishedVersion) {
218
- versionInfo += '<span class="tool-version-item">Published: <strong>' + esc(tool.publishedVersion) + '</strong></span>';
269
+ if (tool.publishedVersion && tool.installedVersion !== tool.publishedVersion) {
270
+ versionInfo += '<span class="tool-version-item">(v' + esc(tool.publishedVersion) + ' available)</span>';
219
271
  }
220
272
  versionInfo += '</div>';
221
273
  }
222
274
 
223
275
  return '<div class="tool-item">' +
276
+ '<div style="display: flex; flex-direction: column; gap: 0.3rem;">' +
224
277
  '<div class="tool-header">' +
225
278
  '<span class="tool-name">' + esc(tool.id) + '</span>' +
226
- '<span class="tool-status-indicator ' + statusClass + '">' +
279
+ '</div>' +
280
+ '<div class="tool-status-indicator ' + statusClass + '">' +
227
281
  '<span class="tool-status-dot"></span>' +
228
282
  '<span>' + getStatusText(tool) + '</span>' +
229
- '</span>' +
230
283
  '</div>' +
231
284
  versionInfo +
232
- (tool.description ? '<div class="tool-details">' + esc(tool.description) + '</div>' : '') +
233
285
  (isInstalling && tool.progress !== undefined ?
234
286
  '<div class="tool-progress-container">' +
235
287
  '<div class="tool-progress-bar"><div class="tool-progress-fill" style="width:' + Math.min(tool.progress, 100) + '%"></div></div>' +
236
- '<div class="tool-progress-text">' + Math.floor(tool.progress) + '%</div>' +
237
288
  '</div>' : '') +
238
- (tool.error_message ? '<div class="tool-error-message">Error: ' + esc(tool.error_message.substring(0, 60)) + '</div>' : '') +
289
+ (tool.error_message ? '<div class="tool-error-message">Error: ' + esc(tool.error_message.substring(0, 40)) + '</div>' : '') +
290
+ '</div>' +
239
291
  '<div class="tool-actions">' +
240
292
  (tool.status === 'not_installed' ?
241
293
  '<button class="tool-btn tool-btn-primary" onclick="window.toolsManager.install(\'' + tool.id + '\')" ' + (operationInProgress.has(tool.id) ? 'disabled' : '') + '>Install</button>' :
@@ -243,7 +295,7 @@
243
295
  '<button class="tool-btn tool-btn-primary" onclick="window.toolsManager.update(\'' + tool.id + '\')" ' + (operationInProgress.has(tool.id) ? 'disabled' : '') + '>Update</button>' :
244
296
  tool.status === 'failed' ?
245
297
  '<button class="tool-btn tool-btn-primary" onclick="window.toolsManager.install(\'' + tool.id + '\')" ' + (operationInProgress.has(tool.id) ? 'disabled' : '') + '>Retry</button>' :
246
- '<button class="tool-btn tool-btn-secondary" onclick="window.toolsManager.refresh()" ' + (isRefreshing ? 'disabled' : '') + '>Refresh</button>'
298
+ '<button class="tool-btn tool-btn-secondary" onclick="window.toolsManager.refresh()" ' + (isRefreshing ? 'disabled' : '') + '>✓</button>'
247
299
  ) +
248
300
  '</div>' +
249
301
  '</div>';
@@ -306,6 +358,28 @@
306
358
  },
307
359
  install: function(toolId) { install(toolId); },
308
360
  update: function(toolId) { update(toolId); },
309
- updateAll: function() { updateAll(); }
361
+ updateAll: function() { updateAll(); },
362
+ getAutoSpeak: function() {
363
+ var toggle = document.getElementById('toolsAutoSpeakToggle');
364
+ return toggle ? toggle.checked : false;
365
+ },
366
+ getVoice: function() {
367
+ var selector = document.getElementById('toolsVoiceSelector');
368
+ return selector ? selector.value : 'default';
369
+ },
370
+ setAutoSpeak: function(value) {
371
+ var toggle = document.getElementById('toolsAutoSpeakToggle');
372
+ if (toggle) {
373
+ toggle.checked = value;
374
+ localStorage.setItem('toolsAutoSpeak', value);
375
+ }
376
+ },
377
+ setVoice: function(value) {
378
+ var selector = document.getElementById('toolsVoiceSelector');
379
+ if (selector && Array.from(selector.options).some(opt => opt.value === value)) {
380
+ selector.value = value;
381
+ localStorage.setItem('toolsVoice', value);
382
+ }
383
+ }
310
384
  };
311
385
  })();
@@ -0,0 +1,551 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Tools UI Redesign Test - Compact Grid Layout</title>
8
+ <style>
9
+ * { box-sizing: border-box; }
10
+
11
+ :root {
12
+ --color-primary: #3b82f6;
13
+ --color-primary-dark: #1e40af;
14
+ --color-bg-primary: #ffffff;
15
+ --color-bg-secondary: #f9fafb;
16
+ --color-bg-tertiary: #f3f4f6;
17
+ --color-text-primary: #111827;
18
+ --color-text-secondary: #6b7280;
19
+ --color-border: #e5e7eb;
20
+ --color-success: #10b981;
21
+ }
22
+
23
+ html.dark {
24
+ --color-bg-primary: #111827;
25
+ --color-bg-secondary: #1f2937;
26
+ --color-bg-tertiary: #374151;
27
+ --color-text-primary: #f9fafb;
28
+ --color-text-secondary: #d1d5db;
29
+ --color-border: #374151;
30
+ }
31
+
32
+ body {
33
+ margin: 0;
34
+ padding: 20px;
35
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
36
+ background: var(--color-bg-secondary);
37
+ color: var(--color-text-primary);
38
+ }
39
+
40
+ .test-container {
41
+ max-width: 1000px;
42
+ margin: 0 auto;
43
+ }
44
+
45
+ h1 {
46
+ font-size: 2rem;
47
+ margin-bottom: 10px;
48
+ }
49
+
50
+ .description {
51
+ color: var(--color-text-secondary);
52
+ margin-bottom: 30px;
53
+ font-size: 0.95rem;
54
+ line-height: 1.5;
55
+ }
56
+
57
+ .demo-section {
58
+ margin-bottom: 40px;
59
+ }
60
+
61
+ .section-title {
62
+ font-size: 1.25rem;
63
+ font-weight: 600;
64
+ margin-bottom: 15px;
65
+ border-bottom: 2px solid var(--color-primary);
66
+ padding-bottom: 8px;
67
+ }
68
+
69
+ /* Tools popup styles */
70
+ .tools-popup-content {
71
+ background: var(--color-bg-secondary);
72
+ border-radius: 1rem;
73
+ width: 100%;
74
+ max-width: 600px;
75
+ display: flex;
76
+ flex-direction: column;
77
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.1);
78
+ color: var(--color-text-primary);
79
+ font-family: system-ui, -apple-system, sans-serif;
80
+ overflow: hidden;
81
+ }
82
+
83
+ .tools-popup-header {
84
+ display: flex;
85
+ justify-content: space-between;
86
+ align-items: center;
87
+ padding: 0.875rem 1.25rem;
88
+ flex-shrink: 0;
89
+ border-bottom: 1px solid var(--color-border);
90
+ gap: 0.75rem;
91
+ }
92
+
93
+ .tools-popup-header h2 {
94
+ margin: 0;
95
+ font-size: 1rem;
96
+ font-weight: 700;
97
+ flex: 1;
98
+ }
99
+
100
+ .tools-popup-header-controls {
101
+ display: flex;
102
+ align-items: center;
103
+ gap: 0.75rem;
104
+ flex-shrink: 0;
105
+ }
106
+
107
+ .tools-voice-toggle {
108
+ display: flex;
109
+ align-items: center;
110
+ gap: 0.5rem;
111
+ font-size: 0.8rem;
112
+ cursor: pointer;
113
+ user-select: none;
114
+ }
115
+
116
+ .tools-voice-toggle input {
117
+ width: 0.875rem;
118
+ height: 0.875rem;
119
+ cursor: pointer;
120
+ }
121
+
122
+ .tools-voice-selector {
123
+ padding: 0.35rem 0.5rem;
124
+ font-size: 0.75rem;
125
+ border-radius: 0.3rem;
126
+ border: 1px solid var(--color-border);
127
+ background: var(--color-bg-primary);
128
+ color: var(--color-text-primary);
129
+ cursor: pointer;
130
+ }
131
+
132
+ .tools-popup-scroll {
133
+ flex: 1;
134
+ overflow-y: auto;
135
+ padding: 1rem;
136
+ display: grid;
137
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
138
+ gap: 1rem;
139
+ }
140
+
141
+ @media (max-width: 768px) {
142
+ .tools-popup-scroll {
143
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
144
+ }
145
+ }
146
+
147
+ @media (max-width: 480px) {
148
+ .tools-popup-scroll {
149
+ grid-template-columns: 1fr;
150
+ }
151
+
152
+ .tools-popup-header {
153
+ flex-direction: column;
154
+ align-items: flex-start;
155
+ }
156
+
157
+ .tools-popup-header-controls {
158
+ width: 100%;
159
+ flex-wrap: wrap;
160
+ }
161
+ }
162
+
163
+ .tool-item {
164
+ padding: 0.75rem;
165
+ border: 1px solid var(--color-border);
166
+ border-radius: 0.5rem;
167
+ background: var(--color-bg-primary);
168
+ display: flex;
169
+ flex-direction: column;
170
+ gap: 0.375rem;
171
+ transition: border-color 0.2s, background-color 0.2s;
172
+ min-height: 120px;
173
+ justify-content: space-between;
174
+ }
175
+
176
+ .tool-item:hover {
177
+ border-color: var(--color-primary);
178
+ background: var(--color-bg-secondary);
179
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
180
+ }
181
+
182
+ .tool-header {
183
+ display: flex;
184
+ align-items: flex-start;
185
+ gap: 0.5rem;
186
+ justify-content: space-between;
187
+ flex-wrap: wrap;
188
+ }
189
+
190
+ .tool-name {
191
+ font-weight: 600;
192
+ font-size: 0.9rem;
193
+ flex: 1;
194
+ word-break: break-word;
195
+ }
196
+
197
+ .tool-status-indicator {
198
+ display: inline-flex;
199
+ align-items: center;
200
+ gap: 0.25rem;
201
+ font-size: 0.7rem;
202
+ padding: 0.2rem 0.4rem;
203
+ border-radius: 0.25rem;
204
+ background: var(--color-bg-tertiary);
205
+ color: var(--color-text-secondary);
206
+ white-space: nowrap;
207
+ flex-shrink: 0;
208
+ }
209
+
210
+ .tool-status-indicator.installed {
211
+ background: rgba(16, 185, 129, 0.15);
212
+ color: #10b981;
213
+ }
214
+
215
+ .tool-status-indicator.needs_update {
216
+ background: rgba(245, 158, 11, 0.15);
217
+ color: #f59e0b;
218
+ }
219
+
220
+ .tool-status-indicator.not_installed {
221
+ background: rgba(107, 114, 128, 0.15);
222
+ color: #9ca3af;
223
+ }
224
+
225
+ .tool-status-dot {
226
+ width: 0.375rem;
227
+ height: 0.375rem;
228
+ border-radius: 50%;
229
+ background: currentColor;
230
+ display: inline-block;
231
+ }
232
+
233
+ .tool-versions {
234
+ display: flex;
235
+ flex-direction: column;
236
+ gap: 0.15rem;
237
+ font-size: 0.65rem;
238
+ color: var(--color-text-secondary);
239
+ line-height: 1.3;
240
+ }
241
+
242
+ .tool-version-item {
243
+ display: flex;
244
+ align-items: center;
245
+ gap: 0.25rem;
246
+ overflow: hidden;
247
+ text-overflow: ellipsis;
248
+ }
249
+
250
+ .tool-actions {
251
+ display: flex;
252
+ gap: 0.4rem;
253
+ flex-wrap: wrap;
254
+ margin-top: 0.25rem;
255
+ }
256
+
257
+ .tool-btn {
258
+ padding: 0.35rem 0.65rem;
259
+ border: none;
260
+ border-radius: 0.3rem;
261
+ cursor: pointer;
262
+ font-size: 0.7rem;
263
+ font-weight: 600;
264
+ transition: all 0.2s;
265
+ flex: 1;
266
+ min-width: 60px;
267
+ white-space: nowrap;
268
+ }
269
+
270
+ .tool-btn-primary {
271
+ background: var(--color-primary);
272
+ color: white;
273
+ }
274
+
275
+ .tool-btn-primary:hover {
276
+ background: var(--color-primary-dark);
277
+ }
278
+
279
+ .tool-progress-bar {
280
+ width: 100%;
281
+ height: 0.25rem;
282
+ background: var(--color-bg-tertiary);
283
+ border-radius: 0.125rem;
284
+ overflow: hidden;
285
+ margin-top: 0.25rem;
286
+ }
287
+
288
+ .tool-progress-fill {
289
+ height: 100%;
290
+ background: linear-gradient(90deg, #3b82f6, #2563eb);
291
+ width: 60%;
292
+ border-radius: 0.125rem;
293
+ }
294
+
295
+ .feature-list {
296
+ display: grid;
297
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
298
+ gap: 15px;
299
+ margin: 20px 0;
300
+ }
301
+
302
+ .feature-item {
303
+ padding: 12px;
304
+ background: var(--color-bg-primary);
305
+ border-radius: 0.5rem;
306
+ border-left: 3px solid var(--color-primary);
307
+ }
308
+
309
+ .feature-item strong {
310
+ color: var(--color-primary);
311
+ }
312
+
313
+ .size-demo {
314
+ display: flex;
315
+ gap: 10px;
316
+ margin: 20px 0;
317
+ flex-wrap: wrap;
318
+ }
319
+
320
+ .size-demo-item {
321
+ text-align: center;
322
+ padding: 10px;
323
+ background: var(--color-bg-primary);
324
+ border-radius: 0.5rem;
325
+ border: 1px solid var(--color-border);
326
+ }
327
+
328
+ .size-label {
329
+ font-size: 0.8rem;
330
+ color: var(--color-text-secondary);
331
+ margin-bottom: 5px;
332
+ }
333
+
334
+ .toggle-dark {
335
+ position: fixed;
336
+ top: 20px;
337
+ right: 20px;
338
+ padding: 0.5rem 1rem;
339
+ background: var(--color-primary);
340
+ color: white;
341
+ border: none;
342
+ border-radius: 0.5rem;
343
+ cursor: pointer;
344
+ font-weight: 600;
345
+ }
346
+ </style>
347
+ </head>
348
+ <body>
349
+ <button class="toggle-dark" onclick="document.documentElement.classList.toggle('dark')">Toggle Dark</button>
350
+
351
+ <div class="test-container">
352
+ <h1>Tools UI Redesign - Compact Grid Layout</h1>
353
+ <div class="description">
354
+ This test page demonstrates the new compact single-card tools UI with integrated voice controls.
355
+ The tools are arranged in a responsive 2x2 grid that adapts to smaller screens.
356
+ </div>
357
+
358
+ <div class="demo-section">
359
+ <div class="section-title">New Features</div>
360
+ <div class="feature-list">
361
+ <div class="feature-item">
362
+ <strong>Compact Grid</strong><br>
363
+ All 4 tools fit in a 2x2 grid that's responsive
364
+ </div>
365
+ <div class="feature-item">
366
+ <strong>Integrated Voice</strong><br>
367
+ Auto-speak toggle and voice selector in header
368
+ </div>
369
+ <div class="feature-item">
370
+ <strong>Efficient Sizing</strong><br>
371
+ Tool cards ~120px height, optimized buttons
372
+ </div>
373
+ <div class="feature-item">
374
+ <strong>Responsive Design</strong><br>
375
+ Adapts from 2 columns to 1 on mobile
376
+ </div>
377
+ </div>
378
+ </div>
379
+
380
+ <div class="demo-section">
381
+ <div class="section-title">Live Preview</div>
382
+ <div style="display: flex; gap: 20px; margin-bottom: 30px; flex-wrap: wrap;">
383
+ <div>
384
+ <div class="size-label">Desktop (600px)</div>
385
+ <div class="tools-popup-content">
386
+ <div class="tools-popup-header">
387
+ <div style="display: flex; align-items: center; gap: 0.75rem; flex: 1;">
388
+ <h2 style="margin: 0; font-size: 1rem;">Tools & Extensions</h2>
389
+ </div>
390
+ <div class="tools-popup-header-controls">
391
+ <label class="tools-voice-toggle">
392
+ <input type="checkbox" checked>
393
+ <span>Auto-speak</span>
394
+ </label>
395
+ <select class="tools-voice-selector">
396
+ <option>Voice</option>
397
+ <option>en-US</option>
398
+ </select>
399
+ <button style="background: none; border: none; color: var(--color-text-secondary); font-size: 1.5rem; cursor: pointer; padding: 0; line-height: 1;">×</button>
400
+ </div>
401
+ </div>
402
+ <div class="tools-popup-scroll">
403
+ <div class="tool-item">
404
+ <div style="display: flex; flex-direction: column; gap: 0.3rem;">
405
+ <div class="tool-header">
406
+ <span class="tool-name">gm-cc</span>
407
+ </div>
408
+ <div class="tool-status-indicator installed">
409
+ <span class="tool-status-dot"></span>
410
+ <span>Up-to-date</span>
411
+ </div>
412
+ <div class="tool-versions">
413
+ <span class="tool-version-item">v1.2.5</span>
414
+ </div>
415
+ </div>
416
+ <div class="tool-actions">
417
+ <button class="tool-btn tool-btn-primary">✓</button>
418
+ </div>
419
+ </div>
420
+
421
+ <div class="tool-item">
422
+ <div style="display: flex; flex-direction: column; gap: 0.3rem;">
423
+ <div class="tool-header">
424
+ <span class="tool-name">gm-oc</span>
425
+ </div>
426
+ <div class="tool-status-indicator needs_update">
427
+ <span class="tool-status-dot"></span>
428
+ <span>Update avail</span>
429
+ </div>
430
+ <div class="tool-versions">
431
+ <span class="tool-version-item">v1.0.2</span>
432
+ <span class="tool-version-item">(v1.0.3 available)</span>
433
+ </div>
434
+ </div>
435
+ <div class="tool-actions">
436
+ <button class="tool-btn tool-btn-primary">Update</button>
437
+ </div>
438
+ </div>
439
+
440
+ <div class="tool-item">
441
+ <div style="display: flex; flex-direction: column; gap: 0.3rem;">
442
+ <div class="tool-header">
443
+ <span class="tool-name">gm-gc</span>
444
+ </div>
445
+ <div class="tool-status-indicator installed">
446
+ <span class="tool-status-dot"></span>
447
+ <span>Up-to-date</span>
448
+ </div>
449
+ <div class="tool-versions">
450
+ <span class="tool-version-item">v2.1.0</span>
451
+ </div>
452
+ </div>
453
+ <div class="tool-actions">
454
+ <button class="tool-btn tool-btn-primary">✓</button>
455
+ </div>
456
+ </div>
457
+
458
+ <div class="tool-item">
459
+ <div style="display: flex; flex-direction: column; gap: 0.3rem;">
460
+ <div class="tool-header">
461
+ <span class="tool-name">gm-kilo</span>
462
+ </div>
463
+ <div class="tool-status-indicator not_installed">
464
+ <span class="tool-status-dot"></span>
465
+ <span>Not instal</span>
466
+ </div>
467
+ <div class="tool-versions">
468
+ </div>
469
+ </div>
470
+ <div class="tool-actions">
471
+ <button class="tool-btn tool-btn-primary">Install</button>
472
+ </div>
473
+ </div>
474
+ </div>
475
+ </div>
476
+ </div>
477
+
478
+ <div>
479
+ <div class="size-label">Installing State</div>
480
+ <div class="tools-popup-content" style="max-width: 300px;">
481
+ <div class="tools-popup-header">
482
+ <h2 style="margin: 0; font-size: 1rem;">Tools & Extensions</h2>
483
+ <button style="background: none; border: none; color: var(--color-text-secondary); font-size: 1.5rem; cursor: pointer; padding: 0; line-height: 1;">×</button>
484
+ </div>
485
+ <div class="tools-popup-scroll">
486
+ <div class="tool-item">
487
+ <div style="display: flex; flex-direction: column; gap: 0.3rem;">
488
+ <div class="tool-header">
489
+ <span class="tool-name">gm-kilo</span>
490
+ </div>
491
+ <div class="tool-status-indicator" style="background: rgba(59, 130, 246, 0.15); color: #3b82f6;">
492
+ <span class="tool-status-dot"></span>
493
+ <span>Installing</span>
494
+ </div>
495
+ </div>
496
+ <div class="tool-actions">
497
+ <button class="tool-btn tool-btn-primary" disabled>Installing</button>
498
+ </div>
499
+ </div>
500
+ </div>
501
+ </div>
502
+ </div>
503
+ </div>
504
+ </div>
505
+
506
+ <div class="demo-section">
507
+ <div class="section-title">Size Comparison</div>
508
+ <div class="size-demo">
509
+ <div class="size-demo-item">
510
+ <div class="size-label">Tool Card Height</div>
511
+ <div style="font-size: 0.9rem; font-weight: 600; color: var(--color-primary);">120px min</div>
512
+ </div>
513
+ <div class="size-demo-item">
514
+ <div class="size-label">Tool Item Padding</div>
515
+ <div style="font-size: 0.9rem; font-weight: 600; color: var(--color-primary);">0.75rem</div>
516
+ </div>
517
+ <div class="size-demo-item">
518
+ <div class="size-label">Button Height</div>
519
+ <div style="font-size: 0.9rem; font-weight: 600; color: var(--color-primary);">28px</div>
520
+ </div>
521
+ <div class="size-demo-item">
522
+ <div class="size-label">Grid Gap</div>
523
+ <div style="font-size: 0.9rem; font-weight: 600; color: var(--color-primary);">1rem</div>
524
+ </div>
525
+ </div>
526
+ </div>
527
+
528
+ <div class="demo-section">
529
+ <div class="section-title">Responsive Behavior</div>
530
+ <div class="feature-list">
531
+ <div class="feature-item">
532
+ <strong>Desktop (&gt;768px)</strong><br>
533
+ 2x2 grid with 200px min-width per column
534
+ </div>
535
+ <div class="feature-item">
536
+ <strong>Tablet (481-768px)</strong><br>
537
+ Auto-fit with 150px min-width columns
538
+ </div>
539
+ <div class="feature-item">
540
+ <strong>Mobile (&lt;480px)</strong><br>
541
+ Single column layout, full width
542
+ </div>
543
+ <div class="feature-item">
544
+ <strong>Header on Mobile</strong><br>
545
+ Flex-direction column for better spacing
546
+ </div>
547
+ </div>
548
+ </div>
549
+ </div>
550
+ </body>
551
+ </html>