claude-relay 2.1.2 → 2.2.0

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.
@@ -323,6 +323,89 @@
323
323
 
324
324
  /* --- Web Terminal --- */
325
325
 
326
+ /* Terminal header with tabs */
327
+ .terminal-header {
328
+ display: flex;
329
+ align-items: center;
330
+ border-bottom: 1px solid var(--border-subtle);
331
+ flex-shrink: 0;
332
+ min-height: 40px;
333
+ background: var(--bg);
334
+ }
335
+
336
+ .terminal-tabs {
337
+ display: flex;
338
+ flex: 1;
339
+ overflow-x: auto;
340
+ -webkit-overflow-scrolling: touch;
341
+ gap: 0;
342
+ min-width: 0;
343
+ padding-left: 4px;
344
+ }
345
+
346
+ .terminal-tabs::-webkit-scrollbar { display: none; }
347
+
348
+ .terminal-tab {
349
+ display: flex;
350
+ align-items: center;
351
+ gap: 4px;
352
+ padding: 8px 10px;
353
+ font-size: 12px;
354
+ font-family: "SF Mono", Menlo, Monaco, monospace;
355
+ color: var(--text-muted);
356
+ cursor: pointer;
357
+ white-space: nowrap;
358
+ border-bottom: 2px solid transparent;
359
+ transition: color 0.15s, border-color 0.15s;
360
+ flex-shrink: 0;
361
+ user-select: none;
362
+ }
363
+
364
+ .terminal-tab:hover { color: var(--text-secondary); }
365
+ .terminal-tab.active { color: var(--text); border-color: var(--accent); }
366
+ .terminal-tab.exited { opacity: 0.5; }
367
+
368
+ .terminal-tab-close {
369
+ display: none;
370
+ align-items: center;
371
+ justify-content: center;
372
+ width: 16px;
373
+ height: 16px;
374
+ border-radius: 3px;
375
+ border: none;
376
+ background: transparent;
377
+ color: var(--text-dimmer);
378
+ cursor: pointer;
379
+ padding: 0;
380
+ line-height: 1;
381
+ }
382
+
383
+ .terminal-tab:hover .terminal-tab-close,
384
+ .terminal-tab.active .terminal-tab-close { display: flex; }
385
+ .terminal-tab-close:hover { background: rgba(255,255,255,0.1); color: var(--text); }
386
+
387
+ .terminal-tab-label { cursor: default; }
388
+
389
+ .terminal-tab-rename {
390
+ background: var(--bg);
391
+ border: 1px solid var(--accent);
392
+ border-radius: 3px;
393
+ color: var(--text);
394
+ font-size: 12px;
395
+ font-family: "SF Mono", Menlo, Monaco, monospace;
396
+ padding: 1px 4px;
397
+ outline: none;
398
+ width: 100px;
399
+ }
400
+
401
+ .terminal-header-actions {
402
+ display: flex;
403
+ align-items: center;
404
+ gap: 2px;
405
+ padding: 0 8px;
406
+ flex-shrink: 0;
407
+ }
408
+
326
409
  /* Wide screens: split panel beside #app */
327
410
  @media (min-width: 1024px) {
328
411
  #terminal-container {
@@ -355,16 +438,80 @@
355
438
 
356
439
  #terminal-body {
357
440
  flex: 1;
358
- padding: 4px;
359
441
  background: #1a1a1a;
360
442
  min-height: 0;
361
443
  overflow: hidden;
444
+ position: relative;
445
+ }
446
+
447
+ .terminal-tab-body {
448
+ position: absolute;
449
+ inset: 0;
450
+ padding: 4px;
362
451
  }
363
452
 
364
- #terminal-body .xterm {
453
+ .terminal-tab-body .xterm {
365
454
  height: 100%;
366
455
  }
367
456
 
457
+ /* --- Terminal key toolbar (mobile) --- */
458
+ #terminal-toolbar {
459
+ display: flex;
460
+ align-items: center;
461
+ gap: 6px;
462
+ padding: 6px 8px;
463
+ background: #252525;
464
+ border-bottom: 1px solid #333;
465
+ flex-shrink: 0;
466
+ overflow-x: auto;
467
+ -webkit-overflow-scrolling: touch;
468
+ }
469
+
470
+ #terminal-toolbar.hidden { display: none; }
471
+
472
+ .term-key {
473
+ display: flex;
474
+ align-items: center;
475
+ justify-content: center;
476
+ height: 32px;
477
+ min-width: 40px;
478
+ padding: 0 10px;
479
+ border-radius: 6px;
480
+ border: 1px solid #444;
481
+ background: #333;
482
+ color: #d4d4d4;
483
+ font-family: "SF Mono", Menlo, Monaco, monospace;
484
+ font-size: 12px;
485
+ font-weight: 500;
486
+ cursor: pointer;
487
+ flex-shrink: 0;
488
+ -webkit-tap-highlight-color: transparent;
489
+ user-select: none;
490
+ transition: background 0.1s, border-color 0.1s;
491
+ }
492
+
493
+ .term-key:active {
494
+ background: #555;
495
+ border-color: #666;
496
+ }
497
+
498
+ .term-key-toggle.active {
499
+ background: var(--accent);
500
+ border-color: var(--accent);
501
+ color: #fff;
502
+ }
503
+
504
+ .term-key-arrow {
505
+ min-width: 34px;
506
+ padding: 0 6px;
507
+ font-size: 10px;
508
+ }
509
+
510
+ .term-key-spacer {
511
+ flex: 1;
512
+ min-width: 4px;
513
+ }
514
+
368
515
  .terminal-hint {
369
516
  padding: 16px;
370
517
  font-size: 13px;
@@ -152,7 +152,7 @@
152
152
  #image-preview-bar {
153
153
  display: none;
154
154
  width: 100%;
155
- padding: 6px 0 4px;
155
+ padding: 6px 4px 4px 14px;
156
156
  }
157
157
 
158
158
  #image-preview-bar.visible {
@@ -220,41 +220,114 @@
220
220
  background: var(--input-bg);
221
221
  border: 1px solid var(--border);
222
222
  border-radius: 24px;
223
- padding: 6px 6px 6px 20px;
223
+ padding: 6px;
224
224
  transition: border-color 0.2s, box-shadow 0.2s;
225
225
  }
226
226
 
227
- #input-inner {
228
- display: flex;
229
- align-items: flex-end;
230
- width: 100%;
231
- }
232
-
233
227
  #input-row:focus-within {
234
228
  border-color: var(--text-dimmer);
235
229
  box-shadow: 0 0 0 1px rgba(109, 104, 96, 0.15);
236
230
  }
237
231
 
238
232
  #input {
239
- flex: 1;
233
+ width: 100%;
240
234
  background: transparent;
241
235
  border: none;
242
236
  color: var(--text);
243
237
  font-size: 16px;
244
238
  font-family: inherit;
245
239
  line-height: 1.4;
246
- padding: 8px 0;
240
+ padding: 8px 10px 4px;
247
241
  resize: none;
248
242
  outline: none;
249
243
  min-height: 24px;
250
244
  max-height: 120px;
251
245
  overflow-y: auto;
246
+ box-sizing: border-box;
252
247
  }
253
248
 
254
249
  #input::placeholder {
255
250
  color: var(--text-muted);
256
251
  }
257
252
 
253
+ /* --- Bottom toolbar (attach left, model+send right) --- */
254
+ #input-bottom {
255
+ display: flex;
256
+ align-items: center;
257
+ justify-content: space-between;
258
+ }
259
+
260
+ #input-bottom-right {
261
+ display: flex;
262
+ align-items: center;
263
+ gap: 4px;
264
+ }
265
+
266
+ /* --- Attach button & menu --- */
267
+ #attach-wrap {
268
+ position: relative;
269
+ flex-shrink: 0;
270
+ }
271
+
272
+ #attach-btn {
273
+ width: 36px;
274
+ height: 36px;
275
+ border-radius: 50%;
276
+ border: none;
277
+ background: transparent;
278
+ color: var(--text-muted);
279
+ cursor: pointer;
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: center;
283
+ transition: background 0.15s, color 0.15s;
284
+ touch-action: manipulation;
285
+ }
286
+
287
+ #attach-btn .lucide { width: 20px; height: 20px; }
288
+ #attach-btn:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
289
+
290
+ #attach-menu {
291
+ position: absolute;
292
+ bottom: calc(100% + 8px);
293
+ left: 0;
294
+ min-width: 170px;
295
+ background: var(--bg-alt);
296
+ border: 1px solid var(--border);
297
+ border-radius: 14px;
298
+ box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.4);
299
+ z-index: 10;
300
+ overflow: hidden;
301
+ }
302
+
303
+ #attach-menu.hidden { display: none; }
304
+
305
+ .attach-menu-item {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 10px;
309
+ width: 100%;
310
+ padding: 12px 16px;
311
+ border: none;
312
+ background: none;
313
+ color: var(--text-secondary);
314
+ font-family: inherit;
315
+ font-size: 14px;
316
+ cursor: pointer;
317
+ transition: background 0.15s, color 0.15s;
318
+ }
319
+
320
+ .attach-menu-item:not(:last-child) {
321
+ border-bottom: 1px solid var(--border-subtle);
322
+ }
323
+
324
+ .attach-menu-item:hover {
325
+ background: rgba(255, 255, 255, 0.05);
326
+ color: var(--text);
327
+ }
328
+
329
+ .attach-menu-item .lucide { width: 18px; height: 18px; flex-shrink: 0; }
330
+
258
331
  #send-btn {
259
332
  flex-shrink: 0;
260
333
  width: 36px;
@@ -85,6 +85,24 @@
85
85
  flex-shrink: 0;
86
86
  }
87
87
 
88
+ /* --- Usage header button (mobile only) --- */
89
+ #usage-header-btn {
90
+ display: none;
91
+ align-items: center;
92
+ justify-content: center;
93
+ background: none;
94
+ border: 1px solid transparent;
95
+ border-radius: 8px;
96
+ color: var(--text-dimmer);
97
+ cursor: pointer;
98
+ padding: 4px;
99
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
100
+ }
101
+ #usage-header-btn .lucide { width: 15px; height: 15px; }
102
+ #usage-header-btn:hover { color: var(--text-secondary); background: rgba(255,255,255,0.04); border-color: var(--border); }
103
+ #usage-header-btn.active { color: var(--accent); border-color: var(--accent); }
104
+ #usage-header-btn.hidden { display: none !important; }
105
+
88
106
  /* --- Terminal toggle button --- */
89
107
  #terminal-toggle-btn {
90
108
  display: flex;
@@ -100,6 +118,25 @@
100
118
  }
101
119
  #terminal-toggle-btn .lucide { width: 15px; height: 15px; }
102
120
  #terminal-toggle-btn:hover { color: var(--text-secondary); background: rgba(255,255,255,0.04); border-color: var(--border); }
121
+ #terminal-toggle-btn { position: relative; }
122
+ #terminal-count {
123
+ position: absolute;
124
+ top: -4px;
125
+ right: -4px;
126
+ background: var(--success);
127
+ color: #fff;
128
+ font-size: 9px;
129
+ font-weight: 700;
130
+ min-width: 14px;
131
+ height: 14px;
132
+ border-radius: 7px;
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ padding: 0 3px;
137
+ font-family: "SF Mono", Menlo, Monaco, monospace;
138
+ }
139
+ #terminal-count.hidden { display: none; }
103
140
 
104
141
  /* --- QR code button & overlay --- */
105
142
  #qr-btn {
@@ -322,7 +359,6 @@
322
359
 
323
360
  .tooltip {
324
361
  position: fixed;
325
- transform: translateX(-50%);
326
362
  background: var(--code-bg);
327
363
  border: 1px solid var(--border);
328
364
  border-radius: 8px;
@@ -338,6 +374,250 @@
338
374
 
339
375
  .tooltip.visible { opacity: 1; }
340
376
 
377
+ /* --- Model selector (inline in input bottom bar) --- */
378
+ #model-menu-wrap {
379
+ position: relative;
380
+ }
381
+
382
+ #model-menu-wrap.hidden { display: none; }
383
+
384
+ #model-btn {
385
+ display: inline-flex;
386
+ align-items: center;
387
+ gap: 2px;
388
+ height: 36px;
389
+ padding: 0 8px;
390
+ border-radius: 10px;
391
+ border: none;
392
+ background: none;
393
+ color: var(--text-muted);
394
+ font-family: inherit;
395
+ font-size: 12px;
396
+ font-weight: 500;
397
+ cursor: pointer;
398
+ transition: color 0.15s, background 0.15s;
399
+ white-space: nowrap;
400
+ }
401
+
402
+ #model-btn .lucide { width: 10px; height: 10px; }
403
+ #model-btn:hover { color: var(--text-secondary); background: rgba(255,255,255,0.06); }
404
+ #model-btn.active { color: var(--text-secondary); background: rgba(255,255,255,0.06); }
405
+
406
+ #model-menu {
407
+ position: absolute;
408
+ bottom: calc(100% + 4px);
409
+ right: 0;
410
+ background: var(--bg-alt);
411
+ border: 1px solid var(--border);
412
+ border-radius: 12px;
413
+ padding: 4px 0;
414
+ min-width: 200px;
415
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
416
+ z-index: 200;
417
+ }
418
+
419
+ #model-menu.hidden { display: none; }
420
+
421
+ .model-menu-item {
422
+ display: flex;
423
+ align-items: center;
424
+ gap: 8px;
425
+ width: 100%;
426
+ padding: 8px 14px;
427
+ border: none;
428
+ background: none;
429
+ color: var(--text-secondary);
430
+ font-family: inherit;
431
+ font-size: 13px;
432
+ cursor: pointer;
433
+ transition: background 0.15s, color 0.15s;
434
+ white-space: nowrap;
435
+ }
436
+
437
+ .model-menu-item:hover { background: rgba(255,255,255,0.05); color: var(--text); }
438
+ .model-menu-item.active { color: var(--accent); font-weight: 600; }
439
+
440
+ /* --- Usage panel --- */
441
+ #usage-panel {
442
+ position: fixed;
443
+ top: 80px;
444
+ right: 16px;
445
+ width: 280px;
446
+ max-height: calc(100vh - 160px);
447
+ overflow-y: auto;
448
+ background: var(--bg-alt);
449
+ border: 1px solid var(--border);
450
+ border-radius: 12px;
451
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
452
+ z-index: 50;
453
+ font-size: 12px;
454
+ }
455
+
456
+ #usage-panel.hidden { display: none; }
457
+
458
+ .usage-panel-header {
459
+ display: flex;
460
+ align-items: center;
461
+ justify-content: space-between;
462
+ padding: 10px 14px;
463
+ border-bottom: 1px solid var(--border-subtle);
464
+ font-weight: 600;
465
+ font-size: 13px;
466
+ color: var(--text);
467
+ }
468
+
469
+ .usage-panel-header button {
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: center;
473
+ background: none;
474
+ border: none;
475
+ color: var(--text-muted);
476
+ cursor: pointer;
477
+ padding: 2px;
478
+ border-radius: 4px;
479
+ }
480
+
481
+ .usage-panel-header button:hover { color: var(--text); background: rgba(255,255,255,0.06); }
482
+ .usage-panel-header button .lucide { width: 14px; height: 14px; }
483
+
484
+ .usage-panel-body {
485
+ padding: 8px 14px 12px;
486
+ }
487
+
488
+ /* --- Rate limit bars --- */
489
+ .usage-loading {
490
+ color: var(--text-muted);
491
+ padding: 8px 0;
492
+ text-align: center;
493
+ }
494
+
495
+ .usage-error {
496
+ color: var(--error);
497
+ padding: 6px 0;
498
+ font-size: 11px;
499
+ line-height: 1.4;
500
+ }
501
+
502
+ .usage-error.hidden { display: none; }
503
+
504
+ .usage-bar-group {
505
+ margin-bottom: 10px;
506
+ }
507
+
508
+ .usage-bar-group:last-child { margin-bottom: 0; }
509
+ .usage-bar-group.hidden { display: none; }
510
+
511
+ .usage-bar-label {
512
+ display: flex;
513
+ justify-content: space-between;
514
+ align-items: center;
515
+ margin-bottom: 4px;
516
+ color: var(--text-secondary);
517
+ font-size: 11px;
518
+ }
519
+
520
+ .usage-bar-pct {
521
+ font-family: "SF Mono", Menlo, Monaco, monospace;
522
+ font-weight: 600;
523
+ font-size: 11px;
524
+ }
525
+
526
+ .usage-bar-track {
527
+ height: 6px;
528
+ background: var(--input-bg);
529
+ border: 1px solid var(--border-subtle);
530
+ border-radius: 3px;
531
+ overflow: hidden;
532
+ }
533
+
534
+ .usage-bar-fill {
535
+ height: 100%;
536
+ border-radius: 3px;
537
+ background: var(--accent);
538
+ transition: width 0.4s ease;
539
+ min-width: 0;
540
+ }
541
+
542
+ .usage-bar-fill.warn { background: var(--warning, #E5A84B); }
543
+ .usage-bar-fill.critical { background: var(--error); }
544
+ .usage-bar-fill-extra { background: var(--text-dimmer); }
545
+
546
+ .usage-bar-reset {
547
+ font-size: 10px;
548
+ color: var(--text-muted);
549
+ margin-top: 2px;
550
+ }
551
+
552
+ .usage-divider {
553
+ height: 1px;
554
+ background: var(--border-subtle);
555
+ margin: 8px 0;
556
+ }
557
+
558
+ .usage-section-label {
559
+ font-size: 10px;
560
+ font-weight: 600;
561
+ color: var(--text-muted);
562
+ text-transform: uppercase;
563
+ letter-spacing: 0.05em;
564
+ margin-bottom: 4px;
565
+ }
566
+
567
+ .usage-row {
568
+ display: flex;
569
+ justify-content: space-between;
570
+ padding: 3px 0;
571
+ color: var(--text-secondary);
572
+ }
573
+
574
+ .usage-label {
575
+ color: var(--text-muted);
576
+ }
577
+
578
+ .usage-value {
579
+ font-family: "SF Mono", Menlo, Monaco, monospace;
580
+ font-weight: 500;
581
+ }
582
+
583
+ /* --- Usage FAB --- */
584
+ #usage-fab {
585
+ position: fixed;
586
+ bottom: calc(var(--safe-bottom, 0px) + 16px);
587
+ right: 16px;
588
+ width: 40px;
589
+ height: 40px;
590
+ border-radius: 50%;
591
+ border: 1px solid var(--border);
592
+ background: var(--bg-alt);
593
+ color: var(--text-muted);
594
+ cursor: pointer;
595
+ display: flex;
596
+ align-items: center;
597
+ justify-content: center;
598
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
599
+ z-index: 90;
600
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
601
+ }
602
+
603
+ #usage-fab.hidden { display: none; }
604
+ #usage-fab .lucide { width: 18px; height: 18px; }
605
+ #usage-fab:hover { color: var(--text); border-color: var(--text-dimmer); }
606
+ #usage-fab.active { color: var(--accent); border-color: var(--accent); }
607
+
608
+ @media (max-width: 768px) {
609
+ #usage-panel {
610
+ top: auto;
611
+ bottom: calc(var(--safe-bottom, 0px) + 64px);
612
+ right: 12px;
613
+ left: 12px;
614
+ width: auto;
615
+ max-height: 60vh;
616
+ }
617
+ #usage-fab { display: none !important; }
618
+ #usage-header-btn:not(.hidden) { display: flex; }
619
+ }
620
+
341
621
  .status-dot.connected { background: var(--success); }
342
622
  .status-dot.processing { background: var(--success); }
343
623
  .status-dot.io { opacity: 0.15; }