coderfleet 0.1.0__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.
Files changed (45) hide show
  1. coderfleet/__init__.py +1 -0
  2. coderfleet/__main__.py +4 -0
  3. coderfleet/cli.py +212 -0
  4. coderfleet/compose.py +176 -0
  5. coderfleet/config.py +69 -0
  6. coderfleet/config_cmds.py +243 -0
  7. coderfleet/data/Dockerfile +92 -0
  8. coderfleet/data/__init__.py +0 -0
  9. coderfleet/data/accounts.conf.example +26 -0
  10. coderfleet/data/config.conf.example +31 -0
  11. coderfleet/data/entrypoint.sh +56 -0
  12. coderfleet/data/projects.conf.example +17 -0
  13. coderfleet/data/scripts/coderfleet_usage_status.py +138 -0
  14. coderfleet/docker_ops.py +385 -0
  15. coderfleet/init_wizard.py +227 -0
  16. coderfleet/login_cmd.py +168 -0
  17. coderfleet/server/__init__.py +0 -0
  18. coderfleet/server/docker_mgr.py +45 -0
  19. coderfleet/server/main.py +546 -0
  20. coderfleet/server/models.py +285 -0
  21. coderfleet/server/scheduler.py +1219 -0
  22. coderfleet/server/static/css/main.css +2906 -0
  23. coderfleet/server/static/index.html +378 -0
  24. coderfleet/server/static/js/accounts.js +85 -0
  25. coderfleet/server/static/js/app.js +28 -0
  26. coderfleet/server/static/js/chat.js +743 -0
  27. coderfleet/server/static/js/log.js +145 -0
  28. coderfleet/server/static/js/nav.js +46 -0
  29. coderfleet/server/static/js/projects.js +298 -0
  30. coderfleet/server/static/js/renderer.js +586 -0
  31. coderfleet/server/static/js/state.js +76 -0
  32. coderfleet/server/static/js/submit.js +200 -0
  33. coderfleet/server/static/js/tasks.js +92 -0
  34. coderfleet/server/static/js/terminal.js +347 -0
  35. coderfleet/server/static/js/utils.js +147 -0
  36. coderfleet/server/static/vendor/marked.min.js +6 -0
  37. coderfleet/server/static/vendor/xterm/addon-fit.js +2 -0
  38. coderfleet/server/static/vendor/xterm/xterm.css +218 -0
  39. coderfleet/server/static/vendor/xterm/xterm.js +2 -0
  40. coderfleet/server/terminal.py +129 -0
  41. coderfleet/task_cmds.py +311 -0
  42. coderfleet-0.1.0.dist-info/METADATA +492 -0
  43. coderfleet-0.1.0.dist-info/RECORD +45 -0
  44. coderfleet-0.1.0.dist-info/WHEEL +4 -0
  45. coderfleet-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,2906 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ margin: 0;
6
+ padding: 0;
7
+ }
8
+
9
+ :root {
10
+ --bg: #eef7f5;
11
+ --surface: #ffffff;
12
+ --surface-2: #f7fbfa;
13
+ --border: rgba(19, 78, 74, 0.12);
14
+ --border-md: rgba(19, 78, 74, 0.24);
15
+ --text: #102a27;
16
+ --text-2: #45615d;
17
+ --text-3: #718783;
18
+ --accent: #0d9488;
19
+ --accent-2: #f97316;
20
+ --accent-bg: #ccfbf1;
21
+ --green: #15803d;
22
+ --green-bg: #dcfce7;
23
+ --red: #dc2626;
24
+ --red-bg: #fee2e2;
25
+ --amber: #b45309;
26
+ --amber-bg: #ffedd5;
27
+ --log-bg: #111827;
28
+ --log-panel: #0f1720;
29
+ --log-card: #17202b;
30
+ --log-card-soft: #141c27;
31
+ --log-line: rgba(148, 163, 184, .22);
32
+ --radius: 8px;
33
+ --radius-lg: 12px;
34
+ --mono: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
35
+
36
+ /* 聊天气泡自适应变量 (Light) */
37
+ --bubble-bg: var(--surface);
38
+ --bubble-color: var(--text);
39
+ --bubble-border: var(--border);
40
+ --bubble-think-bg: var(--surface-2);
41
+ --bubble-think-color: var(--text-3);
42
+ --bubble-code-bg: rgba(13, 148, 136, 0.06);
43
+ --bubble-code-color: var(--accent);
44
+ --bubble-pre-bg: var(--surface-2);
45
+ --bubble-pre-color: var(--text);
46
+ }
47
+
48
+ @media (prefers-color-scheme: dark) {
49
+ :root {
50
+ --bg: #0f172a;
51
+ --surface: #121d2d;
52
+ --surface-2: #172338;
53
+ --border: rgba(255, 255, 255, 0.09);
54
+ --border-md: rgba(255, 255, 255, 0.16);
55
+ --text: #f8fafc;
56
+ --text-2: #b6c4c1;
57
+ --text-3: #7b918d;
58
+ --accent: #2dd4bf;
59
+ --accent-2: #fb923c;
60
+ --accent-bg: #134e4a;
61
+ --green: #4ade80;
62
+ --green-bg: #14532d22;
63
+ --red: #f87171;
64
+ --red-bg: #7f1d1d22;
65
+ --amber: #fbbf24;
66
+ --amber-bg: #78350f22;
67
+
68
+ /* 聊天气泡自适应变量 (Dark) */
69
+ --bubble-bg: #1e293b;
70
+ --bubble-color: #f8fafc;
71
+ --bubble-border: rgba(255, 255, 255, 0.08);
72
+ --bubble-think-bg: #151f32;
73
+ --bubble-think-color: #94a3b8;
74
+ --bubble-code-bg: #0f172a;
75
+ --bubble-code-color: #2dd4bf;
76
+ --bubble-pre-bg: #0f172a;
77
+ --bubble-pre-color: #cbd5e1;
78
+ }
79
+ }
80
+
81
+ body {
82
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
83
+ font-size: 14px;
84
+ line-height: 1.5;
85
+ color: var(--text);
86
+ background:
87
+ linear-gradient(180deg, rgba(13, 148, 136, .10), transparent 260px),
88
+ var(--bg);
89
+ min-height: 100vh;
90
+ }
91
+
92
+ /* ── 布局 ─────────────────────────────────────────── */
93
+ .layout {
94
+ display: flex;
95
+ height: 100vh;
96
+ overflow: hidden;
97
+ }
98
+
99
+ .sidebar {
100
+ width: 248px;
101
+ flex-shrink: 0;
102
+ border-right: 1px solid var(--border);
103
+ background: color-mix(in srgb, var(--surface) 92%, transparent);
104
+ display: flex;
105
+ flex-direction: column;
106
+ padding: 18px 0;
107
+ transition: width .18s ease;
108
+ }
109
+
110
+ .layout.sidebar-collapsed .sidebar {
111
+ width: 72px;
112
+ }
113
+
114
+ .main {
115
+ flex: 1;
116
+ overflow: hidden;
117
+ display: flex;
118
+ flex-direction: column;
119
+ }
120
+
121
+ .topbar {
122
+ padding: 14px 22px;
123
+ border-bottom: 1px solid var(--border);
124
+ background: color-mix(in srgb, var(--surface) 92%, transparent);
125
+ display: flex;
126
+ align-items: center;
127
+ gap: 12px;
128
+ }
129
+
130
+ .content {
131
+ flex: 1;
132
+ overflow: auto;
133
+ padding: 22px;
134
+ }
135
+
136
+ /* ── 侧边栏 ───────────────────────────────────────── */
137
+ .logo {
138
+ padding: 0 14px 18px;
139
+ border-bottom: 1px solid var(--border);
140
+ margin-bottom: 10px;
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: space-between;
144
+ gap: 8px;
145
+ min-height: 46px;
146
+ }
147
+
148
+ .brand-mark {
149
+ width: 36px;
150
+ height: 36px;
151
+ border: 1px solid var(--border);
152
+ border-radius: var(--radius);
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ font-size: 14px;
157
+ font-weight: 800;
158
+ color: var(--text);
159
+ background: var(--surface-2);
160
+ flex-shrink: 0;
161
+ }
162
+
163
+ .brand-text {
164
+ min-width: 0;
165
+ flex: 1;
166
+ font-size: 18px;
167
+ font-weight: 750;
168
+ letter-spacing: 0;
169
+ overflow: hidden;
170
+ transition: opacity .12s ease;
171
+ }
172
+
173
+ .brand-text span {
174
+ color: var(--text-2);
175
+ font-weight: 400;
176
+ font-size: 12px;
177
+ display: block;
178
+ margin-top: 2px;
179
+ white-space: nowrap;
180
+ overflow: hidden;
181
+ text-overflow: ellipsis;
182
+ }
183
+
184
+ .sidebar-toggle {
185
+ width: 36px;
186
+ height: 36px;
187
+ padding: 0;
188
+ border-radius: var(--radius);
189
+ flex-shrink: 0;
190
+ }
191
+
192
+ .sidebar-toggle svg {
193
+ width: 16px;
194
+ height: 16px;
195
+ transition: transform .18s ease;
196
+ }
197
+
198
+ .layout.sidebar-collapsed .brand-text,
199
+ .layout.sidebar-collapsed .sidebar-label,
200
+ .layout.sidebar-collapsed .health-text {
201
+ opacity: 0;
202
+ width: 0;
203
+ overflow: hidden;
204
+ white-space: nowrap;
205
+ }
206
+
207
+ .layout.sidebar-collapsed .logo {
208
+ justify-content: center;
209
+ padding-left: 10px;
210
+ padding-right: 10px;
211
+ }
212
+
213
+ .layout.sidebar-collapsed .brand-mark {
214
+ display: none;
215
+ }
216
+
217
+ .layout.sidebar-collapsed .sidebar-toggle svg {
218
+ transform: rotate(180deg);
219
+ }
220
+
221
+ .nav-item {
222
+ display: flex;
223
+ align-items: center;
224
+ gap: 10px;
225
+ min-height: 44px;
226
+ margin: 2px 10px;
227
+ padding: 9px 12px;
228
+ border-radius: var(--radius);
229
+ cursor: pointer;
230
+ font-size: 13px;
231
+ color: var(--text-2);
232
+ transition: background .18s, color .18s, border-color .18s;
233
+ user-select: none;
234
+ border: 1px solid transparent;
235
+ }
236
+
237
+ .layout.sidebar-collapsed .nav-item {
238
+ justify-content: center;
239
+ padding: 9px;
240
+ }
241
+
242
+ .sidebar-label {
243
+ transition: opacity .12s ease;
244
+ }
245
+
246
+ .nav-item:hover {
247
+ background: var(--surface-2);
248
+ color: var(--text);
249
+ border-color: var(--border);
250
+ }
251
+
252
+ .nav-item.active {
253
+ background: var(--accent-bg);
254
+ color: var(--text);
255
+ font-weight: 650;
256
+ border-color: color-mix(in srgb, var(--accent) 28%, transparent);
257
+ }
258
+
259
+ .nav-item svg {
260
+ width: 16px;
261
+ height: 16px;
262
+ flex-shrink: 0;
263
+ opacity: .7;
264
+ }
265
+
266
+ .nav-item.active svg {
267
+ opacity: 1;
268
+ }
269
+
270
+ .sidebar-footer {
271
+ margin-top: auto;
272
+ padding: 12px 16px 0;
273
+ border-top: 1px solid var(--border);
274
+ }
275
+
276
+ .layout.sidebar-collapsed .sidebar-footer {
277
+ padding-left: 0;
278
+ padding-right: 0;
279
+ display: flex;
280
+ justify-content: center;
281
+ }
282
+
283
+ .layout.sidebar-collapsed .sidebar-footer .flex {
284
+ justify-content: center;
285
+ width: 100%;
286
+ }
287
+
288
+ .health-dot {
289
+ width: 7px;
290
+ height: 7px;
291
+ border-radius: 50%;
292
+ background: var(--text-3);
293
+ display: inline-block;
294
+ margin-right: 6px;
295
+ }
296
+
297
+ .layout.sidebar-collapsed .health-dot {
298
+ margin-right: 0;
299
+ }
300
+
301
+ .health-text {
302
+ transition: opacity .12s ease;
303
+ }
304
+
305
+ .health-dot.ok {
306
+ background: var(--green);
307
+ }
308
+
309
+ .health-dot.err {
310
+ background: var(--red);
311
+ }
312
+
313
+ /* ── 顶栏 ─────────────────────────────────────────── */
314
+ .page-title {
315
+ font-size: 16px;
316
+ font-weight: 700;
317
+ }
318
+
319
+ .btn {
320
+ min-height: 36px;
321
+ display: inline-flex;
322
+ align-items: center;
323
+ justify-content: center;
324
+ gap: 7px;
325
+ padding: 7px 12px;
326
+ border-radius: var(--radius);
327
+ border: 1px solid var(--border-md);
328
+ background: var(--surface);
329
+ color: var(--text);
330
+ font-size: 13px;
331
+ cursor: pointer;
332
+ transition: background .18s, border-color .18s, color .18s, opacity .18s;
333
+ white-space: nowrap;
334
+ }
335
+
336
+ .btn:hover {
337
+ background: var(--surface-2);
338
+ border-color: var(--accent);
339
+ }
340
+
341
+ .btn.primary {
342
+ background: var(--accent);
343
+ color: #fff;
344
+ border-color: var(--accent);
345
+ }
346
+
347
+ .btn.primary:hover {
348
+ opacity: .88;
349
+ }
350
+
351
+ .btn.danger {
352
+ color: var(--red);
353
+ border-color: var(--red);
354
+ }
355
+
356
+ .btn.danger:hover {
357
+ background: var(--red-bg);
358
+ }
359
+
360
+ .btn:disabled {
361
+ opacity: .45;
362
+ cursor: not-allowed;
363
+ }
364
+
365
+ .spacer {
366
+ flex: 1;
367
+ }
368
+
369
+ /* ── 卡片 ─────────────────────────────────────────── */
370
+ .card {
371
+ background: var(--surface);
372
+ border: 1px solid var(--border);
373
+ border-radius: var(--radius);
374
+ padding: 16px;
375
+ box-shadow: 0 10px 30px rgba(15, 23, 42, .05);
376
+ }
377
+
378
+ .card+.card {
379
+ margin-top: 12px;
380
+ }
381
+
382
+ /* ── 账号列表 ─────────────────────────────────────── */
383
+ .account-grid {
384
+ display: grid;
385
+ grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
386
+ gap: 12px;
387
+ }
388
+
389
+ .account-card {
390
+ background: var(--surface);
391
+ border: 1px solid var(--border);
392
+ border-radius: var(--radius);
393
+ padding: 14px;
394
+ transition: border-color .18s, background .18s, transform .18s;
395
+ min-width: 0;
396
+ }
397
+
398
+ .account-card:hover {
399
+ border-color: var(--accent);
400
+ background: var(--surface-2);
401
+ transform: translateY(-1px);
402
+ }
403
+
404
+ .account-card-head {
405
+ display: flex;
406
+ justify-content: space-between;
407
+ gap: 12px;
408
+ align-items: flex-start;
409
+ }
410
+
411
+ .account-identity {
412
+ min-width: 0;
413
+ flex: 1;
414
+ }
415
+
416
+ .account-badges {
417
+ display: flex;
418
+ flex-wrap: wrap;
419
+ gap: 6px;
420
+ align-items: center;
421
+ margin-bottom: 8px;
422
+ }
423
+
424
+ .account-name {
425
+ font-weight: 760;
426
+ font-size: 15px;
427
+ line-height: 1.25;
428
+ overflow-wrap: anywhere;
429
+ }
430
+
431
+ .account-status {
432
+ flex-shrink: 0;
433
+ }
434
+
435
+ .account-meta {
436
+ font-size: 12px;
437
+ color: var(--text-2);
438
+ overflow: hidden;
439
+ text-overflow: ellipsis;
440
+ display: -webkit-box;
441
+ -webkit-line-clamp: 2;
442
+ -webkit-box-orient: vertical;
443
+ word-break: break-all;
444
+ }
445
+
446
+ .account-stats {
447
+ display: grid;
448
+ grid-template-columns: repeat(3, minmax(0, 1fr));
449
+ gap: 8px;
450
+ margin-top: 12px;
451
+ }
452
+
453
+ .account-stat {
454
+ min-height: 52px;
455
+ border: 1px solid var(--border);
456
+ border-radius: var(--radius);
457
+ background: var(--surface-2);
458
+ padding: 8px;
459
+ }
460
+
461
+ .account-stat-label {
462
+ color: var(--text-3);
463
+ font-size: 11px;
464
+ font-weight: 700;
465
+ }
466
+
467
+ .account-stat-value {
468
+ margin-top: 3px;
469
+ color: var(--text);
470
+ font-size: 13px;
471
+ font-weight: 720;
472
+ overflow: hidden;
473
+ text-overflow: ellipsis;
474
+ white-space: nowrap;
475
+ }
476
+
477
+ .chip-list {
478
+ display: flex;
479
+ flex-wrap: wrap;
480
+ gap: 6px;
481
+ margin-top: 10px;
482
+ }
483
+
484
+ .chip {
485
+ display: inline-flex;
486
+ align-items: center;
487
+ min-height: 24px;
488
+ max-width: 100%;
489
+ padding: 3px 8px;
490
+ border-radius: 999px;
491
+ border: 1px solid var(--border);
492
+ background: var(--surface-2);
493
+ color: var(--text-2);
494
+ font-size: 12px;
495
+ overflow: hidden;
496
+ text-overflow: ellipsis;
497
+ white-space: nowrap;
498
+ }
499
+
500
+ .container-list {
501
+ margin-top: 10px;
502
+ display: grid;
503
+ gap: 4px;
504
+ }
505
+
506
+ .container-name {
507
+ font-family: var(--mono);
508
+ font-size: 11px;
509
+ color: var(--text-3);
510
+ overflow: hidden;
511
+ text-overflow: ellipsis;
512
+ white-space: nowrap;
513
+ }
514
+
515
+ .account-running-task {
516
+ margin-top: 10px;
517
+ padding: 8px 10px;
518
+ background: var(--green-bg);
519
+ border: 1px solid rgba(21, 128, 61, .3);
520
+ border-radius: var(--radius);
521
+ cursor: pointer;
522
+ transition: opacity .15s;
523
+ }
524
+ .account-running-task:hover { opacity: .75; }
525
+ .account-running-label {
526
+ font-size: 11px;
527
+ font-weight: 700;
528
+ color: var(--green);
529
+ margin-bottom: 4px;
530
+ }
531
+ .account-running-prompt {
532
+ font-size: 12px;
533
+ color: var(--text-2);
534
+ overflow: hidden;
535
+ display: -webkit-box;
536
+ -webkit-line-clamp: 2;
537
+ -webkit-box-orient: vertical;
538
+ }
539
+ .account-footer {
540
+ margin-top: 10px;
541
+ display: flex;
542
+ gap: 6px;
543
+ }
544
+ .duration-cell {
545
+ font-size: 12px;
546
+ color: var(--text-3);
547
+ white-space: nowrap;
548
+ font-family: var(--mono);
549
+ }
550
+ .duration-cell.running {
551
+ color: var(--accent);
552
+ }
553
+
554
+ .badge {
555
+ font-size: 11px;
556
+ padding: 2px 7px;
557
+ border-radius: 999px;
558
+ font-weight: 650;
559
+ display: inline-flex;
560
+ align-items: center;
561
+ gap: 3px;
562
+ }
563
+
564
+ .badge.codex {
565
+ background: var(--accent-bg);
566
+ color: var(--accent);
567
+ }
568
+
569
+ .badge.claude {
570
+ background: var(--amber-bg);
571
+ color: var(--amber);
572
+ }
573
+
574
+ .badge.busy {
575
+ background: var(--green-bg);
576
+ color: var(--green);
577
+ }
578
+
579
+ .badge.idle {
580
+ background: var(--bg);
581
+ color: var(--text-3);
582
+ border: 1px solid var(--border);
583
+ }
584
+
585
+ .badge.offline {
586
+ background: var(--red-bg);
587
+ color: var(--red);
588
+ }
589
+
590
+ .badge.proxy-off {
591
+ background: var(--red-bg);
592
+ color: var(--red);
593
+ }
594
+
595
+ .badge.proxy-relay {
596
+ background: var(--accent-bg);
597
+ color: var(--accent);
598
+ }
599
+
600
+ /* ── 任务链卡片 ───────────────────────────────────── */
601
+ .chain-panel {
602
+ margin-bottom: 14px;
603
+ }
604
+
605
+ .chain-grid {
606
+ display: grid;
607
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
608
+ gap: 12px;
609
+ }
610
+
611
+ .chain-card {
612
+ background: var(--surface);
613
+ border: 1px solid var(--border);
614
+ border-radius: var(--radius);
615
+ padding: 14px;
616
+ min-width: 0;
617
+ transition: border-color .18s, background .18s, transform .18s;
618
+ }
619
+
620
+ .chain-card:hover {
621
+ border-color: var(--accent);
622
+ background: var(--surface-2);
623
+ transform: translateY(-1px);
624
+ }
625
+
626
+ .chain-head {
627
+ display: flex;
628
+ justify-content: space-between;
629
+ gap: 10px;
630
+ align-items: flex-start;
631
+ }
632
+
633
+ .chain-title {
634
+ font-weight: 760;
635
+ font-size: 14px;
636
+ line-height: 1.3;
637
+ overflow-wrap: anywhere;
638
+ }
639
+
640
+ .chain-meta {
641
+ margin-top: 5px;
642
+ color: var(--text-2);
643
+ font-size: 12px;
644
+ overflow: hidden;
645
+ text-overflow: ellipsis;
646
+ white-space: nowrap;
647
+ }
648
+
649
+ .chain-counts {
650
+ display: flex;
651
+ flex-wrap: wrap;
652
+ gap: 6px;
653
+ margin-top: 10px;
654
+ }
655
+
656
+ .chain-task-list {
657
+ margin-top: 10px;
658
+ display: grid;
659
+ gap: 6px;
660
+ }
661
+
662
+ .chain-task {
663
+ width: 100%;
664
+ min-height: 36px;
665
+ border: 1px solid var(--border);
666
+ border-radius: var(--radius);
667
+ background: var(--surface-2);
668
+ color: var(--text);
669
+ padding: 7px 8px;
670
+ display: grid;
671
+ grid-template-columns: auto minmax(0, 1fr) auto;
672
+ gap: 8px;
673
+ align-items: center;
674
+ cursor: pointer;
675
+ text-align: left;
676
+ font: inherit;
677
+ }
678
+
679
+ .chain-task:hover {
680
+ border-color: var(--accent);
681
+ }
682
+
683
+ .chain-task-prompt {
684
+ overflow: hidden;
685
+ text-overflow: ellipsis;
686
+ white-space: nowrap;
687
+ font-size: 12px;
688
+ }
689
+
690
+ .chain-task-time {
691
+ color: var(--text-3);
692
+ font-size: 11px;
693
+ white-space: nowrap;
694
+ }
695
+
696
+ /* ── 项目工作台 ───────────────────────────────────── */
697
+ .project-grid {
698
+ display: grid;
699
+ grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
700
+ gap: 12px;
701
+ }
702
+
703
+ .project-card {
704
+ background: var(--surface);
705
+ border: 1px solid var(--border);
706
+ border-radius: var(--radius);
707
+ padding: 14px;
708
+ min-width: 0;
709
+ cursor: pointer;
710
+ transition: border-color .18s, background .18s, transform .18s;
711
+ }
712
+
713
+ .project-card:hover {
714
+ border-color: var(--accent);
715
+ background: var(--surface-2);
716
+ transform: translateY(-1px);
717
+ }
718
+
719
+ .project-head {
720
+ display: flex;
721
+ justify-content: space-between;
722
+ align-items: flex-start;
723
+ gap: 12px;
724
+ }
725
+
726
+ .project-title {
727
+ font-weight: 780;
728
+ font-size: 15px;
729
+ line-height: 1.25;
730
+ overflow-wrap: anywhere;
731
+ }
732
+
733
+ .project-path {
734
+ margin-top: 5px;
735
+ color: var(--text-2);
736
+ font-family: var(--mono);
737
+ font-size: 11px;
738
+ overflow: hidden;
739
+ text-overflow: ellipsis;
740
+ white-space: nowrap;
741
+ }
742
+
743
+ .project-stats {
744
+ display: grid;
745
+ grid-template-columns: repeat(4, minmax(0, 1fr));
746
+ gap: 8px;
747
+ margin-top: 12px;
748
+ }
749
+
750
+ .project-stat {
751
+ min-height: 50px;
752
+ border: 1px solid var(--border);
753
+ border-radius: var(--radius);
754
+ background: var(--surface-2);
755
+ padding: 8px;
756
+ }
757
+
758
+ .project-detail {
759
+ display: grid;
760
+ grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
761
+ gap: 12px;
762
+ align-items: start;
763
+ }
764
+
765
+ .project-side {
766
+ position: sticky;
767
+ top: 12px;
768
+ }
769
+
770
+ .project-toolbar {
771
+ display: flex;
772
+ align-items: center;
773
+ gap: 8px;
774
+ flex-wrap: wrap;
775
+ margin-bottom: 12px;
776
+ }
777
+
778
+ .terminal-card {
779
+ border: 1px solid var(--border);
780
+ border-radius: var(--radius);
781
+ background: var(--log-bg);
782
+ overflow: hidden;
783
+ min-height: 560px;
784
+ display: flex;
785
+ flex-direction: column;
786
+ }
787
+
788
+ .terminal-toolbar {
789
+ min-height: 44px;
790
+ display: flex;
791
+ align-items: center;
792
+ gap: 8px;
793
+ justify-content: space-between;
794
+ padding: 8px 10px;
795
+ border-bottom: 1px solid var(--log-line);
796
+ background: var(--log-panel);
797
+ color: #e5e7eb;
798
+ }
799
+
800
+ .terminal-status {
801
+ display: flex;
802
+ align-items: center;
803
+ gap: 8px;
804
+ min-width: 0;
805
+ color: #cbd5e1;
806
+ font-size: 12px;
807
+ }
808
+
809
+ .terminal-status-text {
810
+ overflow: hidden;
811
+ text-overflow: ellipsis;
812
+ white-space: nowrap;
813
+ }
814
+
815
+ .terminal-warning {
816
+ display: none;
817
+ padding: 8px 10px;
818
+ border-bottom: 1px solid rgba(251, 191, 36, .25);
819
+ background: rgba(251, 191, 36, .10);
820
+ color: #fde68a;
821
+ font-size: 12px;
822
+ }
823
+
824
+ .terminal-warning.active {
825
+ display: block;
826
+ }
827
+
828
+ .terminal-mount {
829
+ flex: 1;
830
+ min-height: 500px;
831
+ padding: 8px;
832
+ }
833
+
834
+ .terminal-mount .xterm {
835
+ height: 100%;
836
+ }
837
+
838
+
839
+ /* ── 任务表格 ─────────────────────────────────────── */
840
+ .table-wrap {
841
+ overflow-x: auto;
842
+ }
843
+
844
+ table {
845
+ width: 100%;
846
+ border-collapse: collapse;
847
+ font-size: 13px;
848
+ }
849
+
850
+ th {
851
+ text-align: left;
852
+ padding: 9px 10px;
853
+ font-size: 11px;
854
+ font-weight: 700;
855
+ color: var(--text-3);
856
+ text-transform: uppercase;
857
+ letter-spacing: .4px;
858
+ border-bottom: 1px solid var(--border);
859
+ }
860
+
861
+ td {
862
+ padding: 11px 10px;
863
+ border-bottom: 1px solid var(--border);
864
+ vertical-align: top;
865
+ }
866
+
867
+ tr:last-child td {
868
+ border-bottom: none;
869
+ }
870
+
871
+ tr:hover td {
872
+ background: var(--surface-2);
873
+ cursor: pointer;
874
+ }
875
+
876
+ .task-prompt {
877
+ max-width: 280px;
878
+ overflow: hidden;
879
+ text-overflow: ellipsis;
880
+ white-space: nowrap;
881
+ }
882
+
883
+ .task-project {
884
+ font-size: 12px;
885
+ color: var(--text-2);
886
+ max-width: 160px;
887
+ overflow: hidden;
888
+ text-overflow: ellipsis;
889
+ white-space: nowrap;
890
+ }
891
+
892
+ .status-dot {
893
+ display: inline-flex;
894
+ align-items: center;
895
+ gap: 5px;
896
+ font-size: 12px;
897
+ font-weight: 500;
898
+ }
899
+
900
+ .status-dot::before {
901
+ content: '';
902
+ width: 6px;
903
+ height: 6px;
904
+ border-radius: 50%;
905
+ flex-shrink: 0;
906
+ }
907
+
908
+ .status-dot.running::before {
909
+ background: var(--green);
910
+ box-shadow: 0 0 0 2px var(--green-bg);
911
+ animation: pulse 1.5s infinite;
912
+ }
913
+
914
+ .status-dot.done::before {
915
+ background: var(--accent);
916
+ }
917
+
918
+ .status-dot.failed::before {
919
+ background: var(--red);
920
+ }
921
+
922
+ .status-dot.killed::before {
923
+ background: var(--text-3);
924
+ }
925
+
926
+ @keyframes pulse {
927
+
928
+ 0%,
929
+ 100% {
930
+ opacity: 1
931
+ }
932
+
933
+ 50% {
934
+ opacity: .5
935
+ }
936
+ }
937
+
938
+ /* ── 提交任务表单 ──────────────────────────────────── */
939
+ .form-group {
940
+ margin-bottom: 14px;
941
+ }
942
+
943
+ .form-group label {
944
+ display: block;
945
+ font-size: 12px;
946
+ font-weight: 500;
947
+ color: var(--text-2);
948
+ margin-bottom: 5px;
949
+ }
950
+
951
+ .form-group input,
952
+ .form-group select,
953
+ .form-group textarea {
954
+ width: 100%;
955
+ min-height: 40px;
956
+ padding: 8px 10px;
957
+ border: 1px solid var(--border-md);
958
+ border-radius: var(--radius);
959
+ background: var(--surface-2);
960
+ color: var(--text);
961
+ font-size: 13px;
962
+ font-family: inherit;
963
+ outline: none;
964
+ transition: border-color .15s;
965
+ }
966
+
967
+ .filter-bar select {
968
+ min-height: 36px;
969
+ padding: 7px 32px 7px 10px;
970
+ border: 1px solid var(--border-md);
971
+ border-radius: var(--radius);
972
+ background: var(--surface);
973
+ color: var(--text);
974
+ font: inherit;
975
+ font-size: 13px;
976
+ }
977
+
978
+ .filter-bar select:focus-visible {
979
+ outline: 2px solid var(--accent-2);
980
+ outline-offset: 2px;
981
+ }
982
+
983
+ .pagination-bar {
984
+ display: flex;
985
+ align-items: center;
986
+ justify-content: space-between;
987
+ gap: 10px;
988
+ flex-wrap: wrap;
989
+ padding: 12px 2px 0;
990
+ color: var(--text-2);
991
+ font-size: 12px;
992
+ }
993
+
994
+ .pagination-actions {
995
+ display: flex;
996
+ align-items: center;
997
+ gap: 6px;
998
+ }
999
+
1000
+ .form-group input:focus,
1001
+ .form-group select:focus,
1002
+ .form-group textarea:focus {
1003
+ border-color: var(--accent);
1004
+ }
1005
+
1006
+ .btn:focus-visible,
1007
+ .nav-item:focus-visible,
1008
+ .tool-toggle:focus-visible,
1009
+ .form-group input:focus-visible,
1010
+ .form-group select:focus-visible,
1011
+ .form-group textarea:focus-visible {
1012
+ outline: 2px solid var(--accent-2);
1013
+ outline-offset: 2px;
1014
+ }
1015
+
1016
+ .form-group textarea {
1017
+ resize: vertical;
1018
+ min-height: 72px;
1019
+ }
1020
+
1021
+ .form-row {
1022
+ display: flex;
1023
+ gap: 10px;
1024
+ }
1025
+
1026
+ .form-row .form-group {
1027
+ flex: 1;
1028
+ }
1029
+
1030
+ .toggle-row {
1031
+ display: flex;
1032
+ align-items: center;
1033
+ gap: 8px;
1034
+ font-size: 13px;
1035
+ }
1036
+
1037
+ .toggle-row input[type=checkbox] {
1038
+ width: 16px;
1039
+ height: 16px;
1040
+ accent-color: var(--accent);
1041
+ cursor: pointer;
1042
+ }
1043
+
1044
+ /* ── 空状态 ───────────────────────────────────────── */
1045
+ .empty {
1046
+ text-align: center;
1047
+ padding: 48px 0;
1048
+ color: var(--text-3);
1049
+ }
1050
+
1051
+ /* ── 页面切换 ─────────────────────────────────────── */
1052
+ .page {
1053
+ display: none;
1054
+ }
1055
+
1056
+ .page.active {
1057
+ display: block;
1058
+ }
1059
+
1060
+ /* ── 工具 ─────────────────────────────────────────── */
1061
+ .flex {
1062
+ display: flex;
1063
+ align-items: center;
1064
+ }
1065
+
1066
+ .gap-8 {
1067
+ gap: 8px;
1068
+ }
1069
+
1070
+ .gap-12 {
1071
+ gap: 12px;
1072
+ }
1073
+
1074
+ .text-sm {
1075
+ font-size: 12px;
1076
+ }
1077
+
1078
+ .text-muted {
1079
+ color: var(--text-2);
1080
+ }
1081
+
1082
+ .mt-16 {
1083
+ margin-top: 16px;
1084
+ }
1085
+
1086
+ .filter-bar {
1087
+ display: flex;
1088
+ gap: 8px;
1089
+ flex-wrap: wrap;
1090
+ align-items: center;
1091
+ margin-bottom: 14px;
1092
+ }
1093
+
1094
+ .metric-grid {
1095
+ display: grid;
1096
+ grid-template-columns: repeat(4, minmax(140px, 1fr));
1097
+ gap: 12px;
1098
+ margin-bottom: 14px;
1099
+ }
1100
+
1101
+ .metric-card {
1102
+ background: var(--surface);
1103
+ border: 1px solid var(--border);
1104
+ border-radius: var(--radius);
1105
+ padding: 14px;
1106
+ min-height: 88px;
1107
+ }
1108
+
1109
+ .metric-label {
1110
+ color: var(--text-2);
1111
+ font-size: 12px;
1112
+ font-weight: 650;
1113
+ }
1114
+
1115
+ .metric-value {
1116
+ margin-top: 7px;
1117
+ font-size: 28px;
1118
+ line-height: 1;
1119
+ font-weight: 780;
1120
+ letter-spacing: 0;
1121
+ }
1122
+
1123
+ .metric-note {
1124
+ margin-top: 6px;
1125
+ color: var(--text-3);
1126
+ font-size: 12px;
1127
+ }
1128
+
1129
+ .section-head {
1130
+ display: flex;
1131
+ align-items: flex-end;
1132
+ justify-content: space-between;
1133
+ gap: 12px;
1134
+ margin-bottom: 12px;
1135
+ }
1136
+
1137
+ .section-title {
1138
+ font-size: 14px;
1139
+ font-weight: 720;
1140
+ }
1141
+
1142
+ .section-subtitle {
1143
+ font-size: 12px;
1144
+ color: var(--text-2);
1145
+ margin-top: 2px;
1146
+ }
1147
+
1148
+ .mode-grid {
1149
+ display: grid;
1150
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1151
+ gap: 8px;
1152
+ margin-bottom: 12px;
1153
+ }
1154
+
1155
+ .mode-option {
1156
+ min-height: 44px;
1157
+ display: flex;
1158
+ align-items: center;
1159
+ gap: 8px;
1160
+ padding: 9px 10px;
1161
+ border: 1px solid var(--border);
1162
+ border-radius: var(--radius);
1163
+ cursor: pointer;
1164
+ background: var(--surface-2);
1165
+ transition: border-color .18s, background .18s;
1166
+ }
1167
+
1168
+ .mode-option:hover {
1169
+ border-color: var(--accent);
1170
+ }
1171
+
1172
+ .mode-option input {
1173
+ width: 16px;
1174
+ height: 16px;
1175
+ accent-color: var(--accent);
1176
+ }
1177
+
1178
+ .submit-card {
1179
+ max-width: 760px;
1180
+ }
1181
+
1182
+ .icon {
1183
+ width: 16px;
1184
+ height: 16px;
1185
+ flex-shrink: 0;
1186
+ }
1187
+
1188
+ .sr-only {
1189
+ position: absolute;
1190
+ width: 1px;
1191
+ height: 1px;
1192
+ padding: 0;
1193
+ margin: -1px;
1194
+ overflow: hidden;
1195
+ clip: rect(0, 0, 0, 0);
1196
+ white-space: nowrap;
1197
+ border: 0;
1198
+ }
1199
+
1200
+ .chain-badge {
1201
+ background: var(--surface-2);
1202
+ color: var(--text-2);
1203
+ padding: 2px 7px;
1204
+ border-radius: 999px;
1205
+ font-size: 11px;
1206
+ margin-right: 6px;
1207
+ border: 1px solid var(--border);
1208
+ }
1209
+
1210
+ .inline-alert {
1211
+ color: var(--red);
1212
+ font-size: 12px;
1213
+ margin-top: 4px;
1214
+ }
1215
+
1216
+ /* ══════════════════════════════════════════════════
1217
+ 日志模态框 — 大面板
1218
+ ══════════════════════════════════════════════════ */
1219
+ .modal-backdrop {
1220
+ position: fixed;
1221
+ inset: 0;
1222
+ background: rgba(4, 12, 20, .68);
1223
+ display: flex;
1224
+ align-items: center;
1225
+ justify-content: center;
1226
+ z-index: 100;
1227
+ padding: 18px;
1228
+ }
1229
+
1230
+ .modal-lg {
1231
+ background: var(--log-bg);
1232
+ border: 1px solid var(--border-md);
1233
+ border-radius: var(--radius);
1234
+ width: min(1120px, 96vw);
1235
+ height: min(920px, 92vh);
1236
+ display: flex;
1237
+ flex-direction: column;
1238
+ overflow: hidden;
1239
+ box-shadow: 0 24px 80px rgba(0, 0, 0, .42);
1240
+ }
1241
+
1242
+ .modal-header {
1243
+ padding: 16px 18px 12px;
1244
+ border-bottom: 1px solid rgba(148, 163, 184, .16);
1245
+ display: flex;
1246
+ align-items: flex-start;
1247
+ justify-content: space-between;
1248
+ gap: 16px;
1249
+ flex-shrink: 0;
1250
+ background: linear-gradient(180deg, #182231, var(--log-bg));
1251
+ }
1252
+
1253
+ .modal-title {
1254
+ font-size: 16px;
1255
+ font-weight: 750;
1256
+ color: #f8fafc;
1257
+ }
1258
+
1259
+ .log-meta {
1260
+ display: flex;
1261
+ gap: 8px;
1262
+ align-items: center;
1263
+ flex-wrap: wrap;
1264
+ font-size: 12px;
1265
+ color: #9fb2ae;
1266
+ margin-top: 6px;
1267
+ }
1268
+
1269
+ .log-shell {
1270
+ display: flex;
1271
+ flex-direction: column;
1272
+ min-height: 0;
1273
+ flex: 1;
1274
+ background: var(--log-panel);
1275
+ }
1276
+
1277
+ .log-summary {
1278
+ display: grid;
1279
+ grid-template-columns: repeat(4, minmax(120px, 1fr));
1280
+ gap: 10px;
1281
+ padding: 12px 18px;
1282
+ border-bottom: 1px solid rgba(148, 163, 184, .14);
1283
+ background: var(--log-panel);
1284
+ }
1285
+
1286
+ .log-summary-item {
1287
+ min-height: 58px;
1288
+ border: 1px solid rgba(148, 163, 184, .15);
1289
+ border-radius: var(--radius);
1290
+ background: var(--log-card);
1291
+ padding: 10px 12px;
1292
+ }
1293
+
1294
+ .log-summary-label {
1295
+ font-size: 11px;
1296
+ color: #7f948f;
1297
+ font-weight: 700;
1298
+ }
1299
+
1300
+ .log-summary-value {
1301
+ margin-top: 5px;
1302
+ font-size: 13px;
1303
+ color: #f8fafc;
1304
+ font-weight: 720;
1305
+ overflow: hidden;
1306
+ text-overflow: ellipsis;
1307
+ white-space: nowrap;
1308
+ }
1309
+
1310
+ /* 聊天视口 */
1311
+ .chat-viewport {
1312
+ flex: 1;
1313
+ overflow-y: auto;
1314
+ background:
1315
+ linear-gradient(180deg, rgba(148, 163, 184, .045), transparent 220px),
1316
+ var(--log-panel);
1317
+ padding: 18px 22px 26px;
1318
+ scroll-behavior: smooth;
1319
+ }
1320
+
1321
+ /* ══════════════════════════════════════════════════
1322
+ 聊天日志 UI
1323
+ ══════════════════════════════════════════════════ */
1324
+ .chat-log {
1325
+ display: flex;
1326
+ flex-direction: column;
1327
+ gap: 12px;
1328
+ }
1329
+
1330
+ .chat-log.timeline {
1331
+ position: relative;
1332
+ max-width: 920px;
1333
+ margin: 0 auto;
1334
+ padding-left: 18px;
1335
+ }
1336
+
1337
+ .chat-log.timeline::before {
1338
+ content: '';
1339
+ position: absolute;
1340
+ left: 5px;
1341
+ top: 8px;
1342
+ bottom: 8px;
1343
+ width: 1px;
1344
+ background: linear-gradient(180deg, rgba(45, 212, 191, .42), var(--log-line));
1345
+ }
1346
+
1347
+ .timeline-node {
1348
+ position: relative;
1349
+ }
1350
+
1351
+ .timeline-node::before {
1352
+ content: '';
1353
+ position: absolute;
1354
+ left: -18px;
1355
+ top: 14px;
1356
+ width: 9px;
1357
+ height: 9px;
1358
+ border-radius: 50%;
1359
+ background: #2dd4bf;
1360
+ box-shadow: 0 0 0 4px rgba(45, 212, 191, .12);
1361
+ }
1362
+
1363
+ .timeline-node.is-muted::before {
1364
+ background: #64748b;
1365
+ box-shadow: 0 0 0 4px rgba(100, 116, 139, .13);
1366
+ }
1367
+
1368
+ .timeline-node.is-error::before {
1369
+ background: #f87171;
1370
+ box-shadow: 0 0 0 4px rgba(248, 113, 113, .14);
1371
+ }
1372
+
1373
+ /* 中间执行步骤折叠面板 */
1374
+ .intermediate-process-wrapper {
1375
+ margin: 12px 0 16px 0;
1376
+ border: 1px solid var(--border);
1377
+ border-radius: var(--radius);
1378
+ background: color-mix(in srgb, var(--surface) 35%, transparent);
1379
+ backdrop-filter: blur(8px);
1380
+ overflow: hidden;
1381
+ }
1382
+
1383
+ .intermediate-process-header {
1384
+ padding: 10px 14px;
1385
+ background: color-mix(in srgb, var(--surface) 90%, transparent);
1386
+ display: flex;
1387
+ justify-content: space-between;
1388
+ align-items: center;
1389
+ cursor: pointer;
1390
+ user-select: none;
1391
+ font-size: 13px;
1392
+ transition: background 0.2s;
1393
+ }
1394
+
1395
+ .intermediate-process-header:hover {
1396
+ background: color-mix(in srgb, var(--surface) 98%, transparent);
1397
+ }
1398
+
1399
+ .process-title-area {
1400
+ display: flex;
1401
+ align-items: center;
1402
+ gap: 8px;
1403
+ }
1404
+
1405
+ .process-icon {
1406
+ font-size: 13px;
1407
+ }
1408
+
1409
+ .process-title-text {
1410
+ font-weight: 600;
1411
+ color: var(--text-2);
1412
+ }
1413
+
1414
+ .process-stats-badge {
1415
+ background: var(--border);
1416
+ color: var(--text-3);
1417
+ padding: 1px 6px;
1418
+ border-radius: 10px;
1419
+ font-size: 10.5px;
1420
+ font-family: var(--mono);
1421
+ }
1422
+
1423
+ .process-toggle-btn {
1424
+ background: none;
1425
+ border: none;
1426
+ color: var(--accent);
1427
+ font-size: 12px;
1428
+ font-weight: 600;
1429
+ cursor: pointer;
1430
+ }
1431
+
1432
+ .intermediate-process-body {
1433
+ padding: 14px;
1434
+ display: flex;
1435
+ flex-direction: column;
1436
+ gap: 14px;
1437
+ border-top: 1px solid var(--border);
1438
+ }
1439
+
1440
+ .intermediate-process-body.collapsed {
1441
+ display: none;
1442
+ }
1443
+
1444
+ /* 隐藏折叠体内部所有节点的左侧时间轴圆点 */
1445
+ .intermediate-process-body .timeline-node::before {
1446
+ display: none;
1447
+ }
1448
+
1449
+
1450
+
1451
+ /* 元数据头部块 */
1452
+ .chat-meta-block {
1453
+ padding: 12px 14px;
1454
+ border-radius: var(--radius);
1455
+ background: var(--log-card-soft);
1456
+ border: 1px solid rgba(148, 163, 184, .16);
1457
+ }
1458
+
1459
+ .meta-row {
1460
+ font-size: 11px;
1461
+ color: #81938f;
1462
+ font-family: var(--mono);
1463
+ line-height: 1.8;
1464
+ }
1465
+
1466
+ .meta-key {
1467
+ color: #64748b;
1468
+ }
1469
+
1470
+ .meta-val {
1471
+ color: #93c5fd;
1472
+ white-space: pre-wrap;
1473
+ word-break: break-all;
1474
+ }
1475
+
1476
+ /* 系统小药丸 */
1477
+ .chat-sys-event {
1478
+ text-align: left;
1479
+ padding: 2px 0;
1480
+ }
1481
+
1482
+ .chat-sys-pill {
1483
+ display: inline-flex;
1484
+ align-items: center;
1485
+ gap: 5px;
1486
+ font-size: 11px;
1487
+ color: #99f6e4;
1488
+ border: 1px solid rgba(45, 212, 191, .22);
1489
+ border-radius: 999px;
1490
+ padding: 4px 12px;
1491
+ background: rgba(20, 184, 166, .08);
1492
+ }
1493
+
1494
+ .chat-sys-pill .pill-detail {
1495
+ color: #7dd3fc;
1496
+ }
1497
+
1498
+ /* AI 气泡 */
1499
+ .chat-bubble-wrap {
1500
+ display: flex;
1501
+ align-items: flex-start;
1502
+ gap: 12px;
1503
+ }
1504
+
1505
+ .chat-avatar {
1506
+ width: 30px;
1507
+ height: 30px;
1508
+ border-radius: 50%;
1509
+ display: flex;
1510
+ align-items: center;
1511
+ justify-content: center;
1512
+ font-size: 10px;
1513
+ font-weight: 800;
1514
+ flex-shrink: 0;
1515
+ margin-top: 2px;
1516
+ color: #ecfeff;
1517
+ }
1518
+
1519
+ .chat-avatar.ai {
1520
+ background: linear-gradient(135deg, #0d9488, #2563eb);
1521
+ }
1522
+
1523
+ .chat-avatar.think {
1524
+ background: linear-gradient(135deg, #334155, #475569);
1525
+ }
1526
+
1527
+ .bubble-body {
1528
+ flex: 1;
1529
+ min-width: 0;
1530
+ }
1531
+
1532
+ .bubble-label-row {
1533
+ display: flex;
1534
+ align-items: center;
1535
+ justify-content: space-between;
1536
+ margin-bottom: 5px;
1537
+ }
1538
+
1539
+ .bubble-label {
1540
+ font-size: 10px;
1541
+ font-weight: 750;
1542
+ letter-spacing: .5px;
1543
+ text-transform: uppercase;
1544
+ color: #5eead4;
1545
+ }
1546
+
1547
+ .bubble-copy-btn {
1548
+ opacity: 0;
1549
+ transition: opacity 0.15s, background 0.1s;
1550
+ background: none;
1551
+ border: none;
1552
+ cursor: pointer;
1553
+ padding: 2px 5px;
1554
+ border-radius: 4px;
1555
+ color: var(--text-3);
1556
+ display: flex;
1557
+ align-items: center;
1558
+ line-height: 1;
1559
+ }
1560
+
1561
+ .chat-bubble-wrap:hover .bubble-copy-btn {
1562
+ opacity: 1;
1563
+ }
1564
+
1565
+ .bubble-copy-btn:hover {
1566
+ background: var(--surface-2);
1567
+ color: var(--text);
1568
+ }
1569
+
1570
+ .bubble-copy-btn.copied {
1571
+ color: var(--green);
1572
+ opacity: 1;
1573
+ }
1574
+
1575
+ .bubble-label.think-label {
1576
+ color: #94a3b8;
1577
+ }
1578
+
1579
+ .bubble {
1580
+ background: var(--bubble-bg);
1581
+ border: 1px solid var(--bubble-border);
1582
+ border-radius: 4px 8px 8px 8px;
1583
+ padding: 12px 14px;
1584
+ color: var(--bubble-color);
1585
+ font-size: 13px;
1586
+ line-height: 1.7;
1587
+ word-break: break-word;
1588
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
1589
+ }
1590
+
1591
+ .bubble.think-bubble {
1592
+ background: var(--bubble-think-bg);
1593
+ border-color: var(--bubble-border);
1594
+ color: var(--bubble-think-color);
1595
+ font-style: italic;
1596
+ box-shadow: none;
1597
+ }
1598
+
1599
+ .bubble code {
1600
+ background: var(--bubble-code-bg);
1601
+ padding: 1px 5px;
1602
+ border-radius: 3px;
1603
+ font-family: var(--mono);
1604
+ font-size: 11.5px;
1605
+ color: var(--bubble-code-color);
1606
+ }
1607
+
1608
+ .bubble pre {
1609
+ background: var(--bubble-pre-bg);
1610
+ border: 1px solid var(--bubble-border);
1611
+ border-radius: 6px;
1612
+ padding: 10px 12px;
1613
+ margin: 8px 0;
1614
+ overflow-x: auto;
1615
+ font-family: var(--mono);
1616
+ font-size: 11.5px;
1617
+ color: var(--bubble-pre-color);
1618
+ white-space: pre;
1619
+ }
1620
+
1621
+ .bubble ul,
1622
+ .bubble ol {
1623
+ padding-left: 20px;
1624
+ margin: 6px 0;
1625
+ }
1626
+
1627
+ .bubble li {
1628
+ margin: 2px 0;
1629
+ }
1630
+
1631
+ .bubble p {
1632
+ margin: 0 0 8px 0;
1633
+ }
1634
+
1635
+ .bubble p:last-child {
1636
+ margin-bottom: 0;
1637
+ }
1638
+
1639
+ /* 工具调用卡片 */
1640
+ .chat-tool-wrap {
1641
+ margin: 0;
1642
+ }
1643
+
1644
+ .chat-tool-card {
1645
+ border-radius: var(--radius);
1646
+ overflow: hidden;
1647
+ border: 1px solid rgba(148, 163, 184, .16);
1648
+ background: var(--log-card);
1649
+ }
1650
+
1651
+ .chat-tool-header {
1652
+ display: flex;
1653
+ align-items: center;
1654
+ gap: 8px;
1655
+ min-height: 44px;
1656
+ padding: 9px 12px;
1657
+ background: var(--log-card-soft);
1658
+ cursor: pointer;
1659
+ user-select: none;
1660
+ transition: background .18s, border-color .18s;
1661
+ }
1662
+
1663
+ .chat-tool-header:hover {
1664
+ background: #1b2634;
1665
+ }
1666
+
1667
+ .tool-status {
1668
+ font-size: 14px;
1669
+ flex-shrink: 0;
1670
+ line-height: 1;
1671
+ }
1672
+
1673
+ .tool-badge {
1674
+ font-size: 10px;
1675
+ font-weight: 700;
1676
+ letter-spacing: .3px;
1677
+ padding: 3px 8px;
1678
+ border-radius: 999px;
1679
+ flex-shrink: 0;
1680
+ font-family: var(--mono);
1681
+ }
1682
+
1683
+ .tool-badge.pending {
1684
+ background: rgba(37, 99, 235, .14);
1685
+ color: #93c5fd;
1686
+ }
1687
+
1688
+ .tool-badge.ok {
1689
+ background: rgba(21, 128, 61, .18);
1690
+ color: #86efac;
1691
+ }
1692
+
1693
+ .tool-badge.fail {
1694
+ background: rgba(220, 38, 38, .16);
1695
+ color: #fca5a5;
1696
+ }
1697
+
1698
+ .tool-cmd {
1699
+ flex: 1;
1700
+ font-family: var(--mono);
1701
+ font-size: 11.5px;
1702
+ color: #bfdbfe;
1703
+ overflow: hidden;
1704
+ text-overflow: ellipsis;
1705
+ white-space: nowrap;
1706
+ }
1707
+
1708
+ .tool-toggle {
1709
+ min-height: 28px;
1710
+ font-size: 11px;
1711
+ color: #cbd5e1;
1712
+ padding: 3px 9px;
1713
+ border-radius: 6px;
1714
+ border: 1px solid rgba(148, 163, 184, .2);
1715
+ background: transparent;
1716
+ cursor: pointer;
1717
+ flex-shrink: 0;
1718
+ transition: color .18s, border-color .18s, background .18s;
1719
+ }
1720
+
1721
+ .tool-toggle:hover {
1722
+ color: #f8fafc;
1723
+ border-color: #2dd4bf;
1724
+ background: rgba(45, 212, 191, .08);
1725
+ }
1726
+
1727
+ .tool-body {
1728
+ border-top: 1px solid rgba(148, 163, 184, .12);
1729
+ }
1730
+
1731
+ .tool-body.collapsed {
1732
+ display: none;
1733
+ }
1734
+
1735
+ .tool-input {
1736
+ padding: 8px 12px;
1737
+ font-family: var(--mono);
1738
+ font-size: 11.5px;
1739
+ color: #93c5fd;
1740
+ background: #101722;
1741
+ white-space: pre-wrap;
1742
+ word-break: break-all;
1743
+ border-bottom: 1px solid rgba(148, 163, 184, .12);
1744
+ max-height: 120px;
1745
+ overflow-y: auto;
1746
+ }
1747
+
1748
+ .tool-output {
1749
+ padding: 9px 12px;
1750
+ font-family: var(--mono);
1751
+ font-size: 11.5px;
1752
+ line-height: 1.55;
1753
+ color: #dbeafe;
1754
+ background: #0b111a;
1755
+ white-space: pre-wrap;
1756
+ word-break: break-all;
1757
+ max-height: 340px;
1758
+ overflow-y: auto;
1759
+ }
1760
+
1761
+ .tool-output.is-error {
1762
+ color: #f87171;
1763
+ }
1764
+
1765
+ .tool-exit {
1766
+ padding: 4px 12px 5px;
1767
+ background: #0b111a;
1768
+ font-size: 10px;
1769
+ font-family: var(--mono);
1770
+ border-top: 1px solid rgba(148, 163, 184, .1);
1771
+ }
1772
+
1773
+ .tool-exit.ok-exit {
1774
+ color: #86efac;
1775
+ }
1776
+
1777
+ .tool-exit.fail-exit {
1778
+ color: #fca5a5;
1779
+ }
1780
+
1781
+ /* 文件变更 */
1782
+ .chat-file-card {
1783
+ background: var(--log-card);
1784
+ border: 1px solid rgba(148, 163, 184, .16);
1785
+ border-radius: var(--radius);
1786
+ padding: 9px 12px;
1787
+ display: flex;
1788
+ align-items: center;
1789
+ gap: 8px;
1790
+ margin-top: 4px;
1791
+ }
1792
+
1793
+ .file-op-badge {
1794
+ font-size: 9px;
1795
+ font-weight: 700;
1796
+ letter-spacing: .5px;
1797
+ padding: 1px 7px;
1798
+ border-radius: 20px;
1799
+ flex-shrink: 0;
1800
+ }
1801
+
1802
+ .file-op-badge.create {
1803
+ background: #0e2a1a;
1804
+ color: #4ade80;
1805
+ }
1806
+
1807
+ .file-op-badge.edit {
1808
+ background: #1e2a3a;
1809
+ color: #60a5fa;
1810
+ }
1811
+
1812
+ .file-op-badge.delete {
1813
+ background: #2a0e0e;
1814
+ color: #f87171;
1815
+ }
1816
+
1817
+ .file-path {
1818
+ font-family: var(--mono);
1819
+ font-size: 11.5px;
1820
+ color: #bfdbfe;
1821
+ overflow: hidden;
1822
+ text-overflow: ellipsis;
1823
+ white-space: nowrap;
1824
+ }
1825
+
1826
+ /* 用量统计 */
1827
+ .chat-usage {
1828
+ display: flex;
1829
+ gap: 16px;
1830
+ flex-wrap: wrap;
1831
+ padding: 7px 12px;
1832
+ background: var(--log-card);
1833
+ border: 1px solid rgba(148, 163, 184, .16);
1834
+ border-radius: var(--radius);
1835
+ margin-top: 4px;
1836
+ }
1837
+
1838
+ .usage-item {
1839
+ font-size: 11px;
1840
+ color: #94a3b8;
1841
+ font-family: var(--mono);
1842
+ }
1843
+
1844
+ .usage-item span {
1845
+ color: #93c5fd;
1846
+ }
1847
+
1848
+ /* 页脚完成状态 */
1849
+ .chat-footer {
1850
+ text-align: center;
1851
+ padding: 10px 0 4px;
1852
+ }
1853
+
1854
+ .footer-pill {
1855
+ display: inline-flex;
1856
+ align-items: center;
1857
+ gap: 6px;
1858
+ font-size: 12px;
1859
+ padding: 5px 16px;
1860
+ border-radius: 20px;
1861
+ font-family: var(--mono);
1862
+ }
1863
+
1864
+ .footer-pill.done {
1865
+ background: rgba(21, 128, 61, .18);
1866
+ color: #86efac;
1867
+ border: 1px solid rgba(134, 239, 172, .24);
1868
+ }
1869
+
1870
+ .footer-pill.failed {
1871
+ background: rgba(220, 38, 38, .16);
1872
+ color: #fca5a5;
1873
+ border: 1px solid rgba(252, 165, 165, .24);
1874
+ }
1875
+
1876
+ .footer-pill.killed {
1877
+ background: rgba(100, 116, 139, .18);
1878
+ color: #cbd5e1;
1879
+ border: 1px solid rgba(148, 163, 184, .2);
1880
+ }
1881
+
1882
+ /* 非 JSON 错误行 */
1883
+ .chat-raw-line {
1884
+ padding: 8px 10px;
1885
+ background: rgba(127, 29, 29, .14);
1886
+ border-left: 2px solid #f87171;
1887
+ border-radius: 0 6px 6px 0;
1888
+ font-family: var(--mono);
1889
+ font-size: 11.5px;
1890
+ color: #c87070;
1891
+ white-space: pre-wrap;
1892
+ word-break: break-all;
1893
+ }
1894
+
1895
+ /* 流式光标 */
1896
+ .stream-cursor {
1897
+ display: inline-block;
1898
+ width: 8px;
1899
+ height: 13px;
1900
+ background: #60a5fa;
1901
+ animation: blink .9s step-end infinite;
1902
+ vertical-align: text-bottom;
1903
+ margin-left: 2px;
1904
+ border-radius: 1px;
1905
+ }
1906
+
1907
+ @keyframes blink {
1908
+
1909
+ 0%,
1910
+ 100% {
1911
+ opacity: 1
1912
+ }
1913
+
1914
+ 50% {
1915
+ opacity: 0
1916
+ }
1917
+ }
1918
+
1919
+ /* 小模态(通用) */
1920
+ .modal-sm {
1921
+ background: var(--surface);
1922
+ border: 1px solid var(--border-md);
1923
+ border-radius: var(--radius-lg);
1924
+ padding: 20px;
1925
+ width: 520px;
1926
+ max-width: 90vw;
1927
+ max-height: 90vh;
1928
+ overflow: auto;
1929
+ }
1930
+
1931
+ .modal-sm .modal-title {
1932
+ font-size: 15px;
1933
+ font-weight: 600;
1934
+ margin-bottom: 16px;
1935
+ }
1936
+
1937
+ .modal-footer {
1938
+ display: flex;
1939
+ justify-content: flex-end;
1940
+ gap: 8px;
1941
+ margin-top: 16px;
1942
+ }
1943
+
1944
+ @media (prefers-reduced-motion: reduce) {
1945
+
1946
+ *,
1947
+ *::before,
1948
+ *::after {
1949
+ animation-duration: .01ms !important;
1950
+ animation-iteration-count: 1 !important;
1951
+ scroll-behavior: auto !important;
1952
+ transition-duration: .01ms !important;
1953
+ }
1954
+ }
1955
+
1956
+ @media (max-width: 880px) {
1957
+ .layout {
1958
+ flex-direction: column;
1959
+ height: auto;
1960
+ min-height: 100vh;
1961
+ overflow: visible;
1962
+ }
1963
+
1964
+ .layout.sidebar-collapsed .sidebar,
1965
+ .sidebar {
1966
+ width: 100%;
1967
+ border-right: 0;
1968
+ border-bottom: 1px solid var(--border);
1969
+ padding: 12px;
1970
+ }
1971
+
1972
+ .layout.sidebar-collapsed .brand-mark {
1973
+ display: flex;
1974
+ }
1975
+
1976
+ .layout.sidebar-collapsed .brand-text,
1977
+ .layout.sidebar-collapsed .sidebar-label,
1978
+ .layout.sidebar-collapsed .health-text {
1979
+ opacity: 1;
1980
+ width: auto;
1981
+ }
1982
+
1983
+ .layout.sidebar-collapsed .logo {
1984
+ justify-content: space-between;
1985
+ padding: 0 6px 12px;
1986
+ }
1987
+
1988
+ .layout.sidebar-collapsed .nav-item {
1989
+ justify-content: center;
1990
+ padding: 9px 12px;
1991
+ }
1992
+
1993
+ .sidebar nav {
1994
+ display: grid;
1995
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1996
+ gap: 6px;
1997
+ }
1998
+
1999
+ .nav-item {
2000
+ margin: 0;
2001
+ justify-content: center;
2002
+ }
2003
+
2004
+ .sidebar-footer {
2005
+ padding: 10px 6px 0;
2006
+ }
2007
+
2008
+ .main {
2009
+ min-height: 0;
2010
+ overflow: visible;
2011
+ }
2012
+
2013
+ .content {
2014
+ padding: 14px;
2015
+ }
2016
+
2017
+ .topbar {
2018
+ position: sticky;
2019
+ top: 0;
2020
+ z-index: 20;
2021
+ padding: 12px 14px;
2022
+ }
2023
+
2024
+ .metric-grid {
2025
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2026
+ }
2027
+
2028
+ .account-grid,
2029
+ .chain-grid,
2030
+ .project-grid {
2031
+ grid-template-columns: 1fr;
2032
+ }
2033
+
2034
+ .project-detail {
2035
+ grid-template-columns: 1fr;
2036
+ }
2037
+
2038
+ .project-side {
2039
+ position: static;
2040
+ }
2041
+
2042
+ .terminal-card {
2043
+ min-height: 460px;
2044
+ }
2045
+
2046
+ .terminal-mount {
2047
+ min-height: 400px;
2048
+ }
2049
+
2050
+ .account-stats {
2051
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2052
+ }
2053
+
2054
+ .mode-grid {
2055
+ grid-template-columns: 1fr;
2056
+ }
2057
+
2058
+ .form-row {
2059
+ flex-direction: column;
2060
+ gap: 0;
2061
+ }
2062
+
2063
+ .log-summary {
2064
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2065
+ }
2066
+
2067
+ .modal-backdrop {
2068
+ padding: 0;
2069
+ }
2070
+ }
2071
+
2072
+ @media (max-width: 560px) {
2073
+ body {
2074
+ font-size: 16px;
2075
+ }
2076
+
2077
+ .logo span {
2078
+ display: inline;
2079
+ margin-left: 6px;
2080
+ }
2081
+
2082
+ .topbar .btn span:not(.sr-only) {
2083
+ display: none;
2084
+ }
2085
+
2086
+ .metric-grid {
2087
+ grid-template-columns: 1fr;
2088
+ }
2089
+
2090
+ .project-stats {
2091
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2092
+ }
2093
+
2094
+ .account-stats {
2095
+ grid-template-columns: 1fr;
2096
+ }
2097
+
2098
+ .account-card-head {
2099
+ flex-direction: column;
2100
+ }
2101
+
2102
+ .modal-lg {
2103
+ width: 100vw;
2104
+ height: 100vh;
2105
+ border-radius: 0;
2106
+ }
2107
+
2108
+ .modal-header {
2109
+ flex-direction: column;
2110
+ }
2111
+
2112
+ .log-summary {
2113
+ grid-template-columns: 1fr;
2114
+ padding: 10px 12px;
2115
+ }
2116
+
2117
+ .chat-viewport {
2118
+ padding: 14px 12px 22px;
2119
+ }
2120
+
2121
+ .chat-log.timeline {
2122
+ padding-left: 14px;
2123
+ }
2124
+
2125
+ .chat-log.timeline::before {
2126
+ left: 4px;
2127
+ }
2128
+
2129
+ .timeline-node::before {
2130
+ left: -14px;
2131
+ }
2132
+ }
2133
+
2134
+ /* ── AI 对话(聊天室) ─────────────────────────────────── */
2135
+ .timeline-node-wrapper {
2136
+ margin-bottom: 20px;
2137
+ }
2138
+
2139
+ .user-wrapper {
2140
+ display: flex;
2141
+ justify-content: flex-end;
2142
+ margin-bottom: 24px;
2143
+ }
2144
+
2145
+ .user-bubble {
2146
+ max-width: 85%;
2147
+ background: var(--accent);
2148
+ color: #ffffff;
2149
+ padding: 12px 16px;
2150
+ border-radius: var(--radius-lg);
2151
+ border-top-right-radius: 2px;
2152
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);
2153
+ font-size: 14px;
2154
+ line-height: 1.5;
2155
+ }
2156
+
2157
+ .user-bubble-title-row {
2158
+ display: flex;
2159
+ align-items: center;
2160
+ justify-content: space-between;
2161
+ margin-bottom: 4px;
2162
+ }
2163
+
2164
+ .user-bubble-title {
2165
+ font-weight: 700;
2166
+ font-size: 11px;
2167
+ opacity: 0.85;
2168
+ text-transform: uppercase;
2169
+ letter-spacing: 0.5px;
2170
+ }
2171
+
2172
+ .user-copy-btn {
2173
+ opacity: 0;
2174
+ transition: opacity 0.15s, background 0.1s;
2175
+ background: none;
2176
+ border: none;
2177
+ cursor: pointer;
2178
+ padding: 2px 5px;
2179
+ border-radius: 4px;
2180
+ color: rgba(255, 255, 255, 0.7);
2181
+ display: flex;
2182
+ align-items: center;
2183
+ line-height: 1;
2184
+ }
2185
+
2186
+ .user-bubble:hover .user-copy-btn {
2187
+ opacity: 1;
2188
+ }
2189
+
2190
+ .user-copy-btn:hover {
2191
+ background: rgba(255, 255, 255, 0.15);
2192
+ color: #fff;
2193
+ }
2194
+
2195
+ .user-copy-btn.copied {
2196
+ color: #fff;
2197
+ opacity: 1;
2198
+ }
2199
+
2200
+ .user-bubble-content {
2201
+ white-space: pre-wrap;
2202
+ word-break: break-all;
2203
+ }
2204
+
2205
+ /* 当显示 AI 对话页时,让主 content 区域也无 padding 并隐藏溢出,使聊天界面无缝贴合自适应 */
2206
+ .main:has(#page-chat.active) .content {
2207
+ padding: 0;
2208
+ overflow: hidden;
2209
+ }
2210
+
2211
+ #page-chat.active {
2212
+ height: 100%;
2213
+ width: 100%;
2214
+ }
2215
+
2216
+ .chat-layout {
2217
+ display: flex;
2218
+ height: 100%;
2219
+ overflow: hidden;
2220
+ }
2221
+
2222
+ .chat-sidebar {
2223
+ width: 280px;
2224
+ flex-shrink: 0;
2225
+ border-right: 1px solid var(--border);
2226
+ background: color-mix(in srgb, var(--surface) 96%, transparent);
2227
+ display: flex;
2228
+ flex-direction: column;
2229
+ padding: 14px;
2230
+ }
2231
+
2232
+ .new-chat-btn {
2233
+ width: 100%;
2234
+ margin-bottom: 12px;
2235
+ font-weight: 600;
2236
+ }
2237
+
2238
+ .chat-history-list {
2239
+ flex: 1;
2240
+ overflow-y: auto;
2241
+ display: flex;
2242
+ flex-direction: column;
2243
+ gap: 12px;
2244
+ }
2245
+
2246
+ .chat-project-group {
2247
+ display: flex;
2248
+ flex-direction: column;
2249
+ gap: 4px;
2250
+ }
2251
+
2252
+ .chat-project-header {
2253
+ display: flex;
2254
+ align-items: center;
2255
+ justify-content: space-between;
2256
+ gap: 8px;
2257
+ padding: 6px 8px 6px 4px;
2258
+ font-size: 13px;
2259
+ font-weight: 600;
2260
+ color: var(--text-2);
2261
+ user-select: none;
2262
+ position: relative;
2263
+ }
2264
+
2265
+ .proj-header-title {
2266
+ display: flex;
2267
+ align-items: center;
2268
+ gap: 8px;
2269
+ overflow: hidden;
2270
+ text-overflow: ellipsis;
2271
+ white-space: nowrap;
2272
+ }
2273
+
2274
+ .chat-project-header svg.proj-folder-icon {
2275
+ width: 14px;
2276
+ height: 14px;
2277
+ color: var(--text-3);
2278
+ flex-shrink: 0;
2279
+ }
2280
+
2281
+ .proj-new-chat-btn {
2282
+ display: flex;
2283
+ align-items: center;
2284
+ justify-content: center;
2285
+ width: 20px;
2286
+ height: 20px;
2287
+ padding: 0;
2288
+ border: none;
2289
+ background: transparent;
2290
+ color: var(--text-3);
2291
+ cursor: pointer;
2292
+ border-radius: var(--radius);
2293
+ opacity: 0;
2294
+ transition: opacity 0.15s, color 0.15s, background 0.15s;
2295
+ flex-shrink: 0;
2296
+ }
2297
+
2298
+ .chat-project-header:hover .proj-new-chat-btn {
2299
+ opacity: 1;
2300
+ }
2301
+
2302
+ .proj-new-chat-btn:hover {
2303
+ color: var(--accent);
2304
+ background: var(--bg);
2305
+ }
2306
+
2307
+ .chat-project-items {
2308
+ display: flex;
2309
+ flex-direction: column;
2310
+ gap: 2px;
2311
+ padding-left: 12px;
2312
+ }
2313
+
2314
+ .chat-project-empty {
2315
+ padding: 4px 8px 4px 20px;
2316
+ font-size: 12px;
2317
+ color: var(--text-3);
2318
+ user-select: none;
2319
+ }
2320
+
2321
+ .chat-session-item {
2322
+ display: flex;
2323
+ justify-content: space-between;
2324
+ align-items: center;
2325
+ width: 100%;
2326
+ padding: 8px 12px;
2327
+ border: none;
2328
+ border-radius: var(--radius);
2329
+ background: transparent;
2330
+ text-align: left;
2331
+ cursor: pointer;
2332
+ transition: background 0.15s, color 0.15s;
2333
+ color: var(--text-2);
2334
+ }
2335
+
2336
+ .chat-session-item:hover {
2337
+ background: var(--surface-2);
2338
+ color: var(--text);
2339
+ }
2340
+
2341
+ .chat-session-item.active {
2342
+ background: var(--accent-bg);
2343
+ color: var(--text);
2344
+ }
2345
+
2346
+ @media (prefers-color-scheme: dark) {
2347
+ .chat-session-item.active {
2348
+ background: rgba(255, 255, 255, 0.08);
2349
+ color: var(--text);
2350
+ }
2351
+ }
2352
+
2353
+ .chat-session-item .session-name {
2354
+ font-size: 13px;
2355
+ font-weight: 500;
2356
+ white-space: nowrap;
2357
+ overflow: hidden;
2358
+ text-overflow: ellipsis;
2359
+ flex: 1;
2360
+ margin-right: 8px;
2361
+ }
2362
+
2363
+ .chat-session-item .session-time {
2364
+ font-size: 11px;
2365
+ color: var(--text-3);
2366
+ white-space: nowrap;
2367
+ }
2368
+
2369
+ .chat-session-item .session-actions {
2370
+ display: none;
2371
+ align-items: center;
2372
+ gap: 2px;
2373
+ flex-shrink: 0;
2374
+ }
2375
+
2376
+ .chat-session-item:hover .session-actions {
2377
+ display: flex;
2378
+ }
2379
+
2380
+ .chat-session-item:hover .session-time {
2381
+ display: none;
2382
+ }
2383
+
2384
+ .session-action-btn {
2385
+ display: flex;
2386
+ align-items: center;
2387
+ justify-content: center;
2388
+ width: 22px;
2389
+ height: 22px;
2390
+ padding: 0;
2391
+ border: none;
2392
+ border-radius: 4px;
2393
+ background: transparent;
2394
+ color: var(--text-3);
2395
+ cursor: pointer;
2396
+ transition: background 0.1s, color 0.1s;
2397
+ }
2398
+
2399
+ .session-action-btn:hover {
2400
+ background: var(--surface-3);
2401
+ color: var(--text);
2402
+ }
2403
+
2404
+ .session-action-btn.danger:hover {
2405
+ background: rgba(239, 68, 68, 0.15);
2406
+ color: var(--red);
2407
+ }
2408
+
2409
+ .chat-main {
2410
+ flex: 1;
2411
+ display: flex;
2412
+ flex-direction: column;
2413
+ background: var(--bg);
2414
+ min-width: 0;
2415
+ position: relative;
2416
+ }
2417
+
2418
+ .chat-main-header {
2419
+ padding: 12px 20px;
2420
+ border-bottom: 1px solid var(--border);
2421
+ background: var(--surface);
2422
+ display: flex;
2423
+ justify-content: space-between;
2424
+ align-items: center;
2425
+ }
2426
+
2427
+ .chat-main-title-area {
2428
+ min-width: 0;
2429
+ }
2430
+
2431
+ .chat-main-title {
2432
+ font-size: 15px;
2433
+ font-weight: 700;
2434
+ color: var(--text);
2435
+ white-space: nowrap;
2436
+ overflow: hidden;
2437
+ text-overflow: ellipsis;
2438
+ }
2439
+
2440
+ .chat-main-subtitle {
2441
+ font-size: 12px;
2442
+ color: var(--text-3);
2443
+ margin-top: 2px;
2444
+ }
2445
+
2446
+ .chat-main-viewport {
2447
+ flex: 1;
2448
+ overflow-y: auto;
2449
+ padding: 24px 20px;
2450
+ background: var(--bg);
2451
+ }
2452
+
2453
+ .chat-input-container {
2454
+ padding: 16px 20px 20px;
2455
+ background: var(--surface);
2456
+ border-top: 1px solid var(--border);
2457
+ }
2458
+
2459
+ .chat-input-row {
2460
+ display: flex;
2461
+ gap: 12px;
2462
+ align-items: flex-end;
2463
+ }
2464
+
2465
+ .chat-input-textarea {
2466
+ flex: 1;
2467
+ border: 1px solid var(--border-md);
2468
+ border-radius: var(--radius);
2469
+ padding: 10px 14px;
2470
+ font-family: inherit;
2471
+ font-size: 14px;
2472
+ background: var(--bg);
2473
+ color: var(--text);
2474
+ resize: none;
2475
+ min-height: 40px;
2476
+ max-height: 200px;
2477
+ transition: border-color 0.15s;
2478
+ }
2479
+
2480
+ .chat-input-textarea:focus {
2481
+ outline: none;
2482
+ border-color: var(--accent);
2483
+ }
2484
+
2485
+ .chat-input-actions {
2486
+ display: flex;
2487
+ justify-content: space-between;
2488
+ align-items: center;
2489
+ margin-top: 10px;
2490
+ }
2491
+
2492
+ .chat-input-options {
2493
+ display: flex;
2494
+ align-items: center;
2495
+ gap: 12px;
2496
+ font-size: 12px;
2497
+ color: var(--text-2);
2498
+ }
2499
+
2500
+ .chat-upload-btn {
2501
+ background: none;
2502
+ border: 1px solid var(--border-md);
2503
+ border-radius: var(--radius);
2504
+ padding: 0 10px;
2505
+ min-height: 40px;
2506
+ cursor: pointer;
2507
+ color: var(--text-2);
2508
+ display: flex;
2509
+ align-items: center;
2510
+ justify-content: center;
2511
+ flex-shrink: 0;
2512
+ transition: border-color 0.15s, color 0.15s;
2513
+ }
2514
+
2515
+ .chat-upload-btn:hover {
2516
+ border-color: var(--accent);
2517
+ color: var(--accent);
2518
+ }
2519
+
2520
+ .chat-image-preview-row {
2521
+ display: flex;
2522
+ flex-wrap: wrap;
2523
+ gap: 8px;
2524
+ padding: 8px 0 4px;
2525
+ }
2526
+
2527
+ .chat-image-thumb {
2528
+ position: relative;
2529
+ width: 64px;
2530
+ height: 64px;
2531
+ border-radius: 6px;
2532
+ overflow: hidden;
2533
+ border: 1px solid var(--border-md);
2534
+ flex-shrink: 0;
2535
+ }
2536
+
2537
+ .chat-image-thumb img {
2538
+ width: 100%;
2539
+ height: 100%;
2540
+ object-fit: cover;
2541
+ }
2542
+
2543
+ .chat-image-thumb-remove {
2544
+ position: absolute;
2545
+ top: 2px;
2546
+ right: 2px;
2547
+ width: 18px;
2548
+ height: 18px;
2549
+ background: rgba(0, 0, 0, 0.6);
2550
+ border: none;
2551
+ border-radius: 50%;
2552
+ color: white;
2553
+ font-size: 12px;
2554
+ cursor: pointer;
2555
+ display: flex;
2556
+ align-items: center;
2557
+ justify-content: center;
2558
+ padding: 0;
2559
+ line-height: 1;
2560
+ }
2561
+
2562
+ .chat-image-thumb-remove:hover {
2563
+ background: rgba(200, 30, 30, 0.85);
2564
+ }
2565
+
2566
+ .welcome-container {
2567
+ max-width: 600px;
2568
+ width: 90%;
2569
+ padding: 40px 30px;
2570
+ background: var(--surface);
2571
+ border: 1px solid var(--border);
2572
+ border-radius: var(--radius-lg);
2573
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05);
2574
+ text-align: center;
2575
+ }
2576
+
2577
+ .welcome-logo {
2578
+ font-size: 48px;
2579
+ margin-bottom: 16px;
2580
+ }
2581
+
2582
+ .welcome-title {
2583
+ font-size: 22px;
2584
+ font-weight: 800;
2585
+ color: var(--text);
2586
+ margin-bottom: 8px;
2587
+ }
2588
+
2589
+ .welcome-subtitle {
2590
+ font-size: 14px;
2591
+ color: var(--text-3);
2592
+ margin-bottom: 30px;
2593
+ line-height: 1.5;
2594
+ }
2595
+
2596
+ .welcome-form {
2597
+ text-align: left;
2598
+ display: flex;
2599
+ flex-direction: column;
2600
+ gap: 16px;
2601
+ margin-bottom: 24px;
2602
+ }
2603
+
2604
+ .welcome-form select,
2605
+ .welcome-form input {
2606
+ width: 100%;
2607
+ padding: 10px 12px;
2608
+ border: 1px solid var(--border-md);
2609
+ border-radius: var(--radius);
2610
+ background: var(--bg);
2611
+ color: var(--text);
2612
+ }
2613
+
2614
+ .welcome-form label {
2615
+ font-size: 12px;
2616
+ font-weight: 600;
2617
+ color: var(--text-2);
2618
+ margin-bottom: 6px;
2619
+ display: block;
2620
+ }
2621
+
2622
+ .welcome-suggestions {
2623
+ text-align: left;
2624
+ }
2625
+
2626
+ .welcome-suggestions-title {
2627
+ font-size: 12px;
2628
+ font-weight: 700;
2629
+ color: var(--text-3);
2630
+ margin-bottom: 10px;
2631
+ }
2632
+
2633
+ .welcome-suggestions-grid {
2634
+ display: grid;
2635
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2636
+ gap: 10px;
2637
+ }
2638
+
2639
+ .welcome-suggestion-card {
2640
+ padding: 10px 12px;
2641
+ background: var(--bg);
2642
+ border: 1px solid var(--border);
2643
+ border-radius: var(--radius);
2644
+ font-size: 12px;
2645
+ color: var(--text-2);
2646
+ cursor: pointer;
2647
+ text-align: left;
2648
+ transition: border-color 0.15s, background 0.15s;
2649
+ }
2650
+
2651
+ .welcome-suggestion-card:hover {
2652
+ border-color: var(--accent);
2653
+ background: var(--surface-2);
2654
+ color: var(--text);
2655
+ }
2656
+
2657
+ /* ── 欢迎页自定义输入框 ── */
2658
+ .welcome-input-box {
2659
+ width: 100%;
2660
+ min-height: 80px;
2661
+ max-height: 200px;
2662
+ padding: 12px;
2663
+ border: 1px solid var(--border-md);
2664
+ border-radius: var(--radius);
2665
+ background: var(--bg);
2666
+ color: var(--text);
2667
+ font-family: inherit;
2668
+ font-size: 14px;
2669
+ line-height: 1.5;
2670
+ resize: none;
2671
+ outline: none;
2672
+ transition: border-color 0.2s, box-shadow 0.2s;
2673
+ }
2674
+ .welcome-input-box:focus {
2675
+ border-color: var(--accent);
2676
+ box-shadow: 0 0 0 2px rgba(13, 148, 136, 0.15);
2677
+ background: var(--surface);
2678
+ }
2679
+ .welcome-submit-btn {
2680
+ padding: 8px 20px;
2681
+ background: var(--accent);
2682
+ color: #ffffff;
2683
+ border: none;
2684
+ border-radius: var(--radius);
2685
+ font-size: 14px;
2686
+ font-weight: 600;
2687
+ cursor: pointer;
2688
+ display: flex;
2689
+ align-items: center;
2690
+ gap: 6px;
2691
+ transition: background 0.15s, transform 0.1s;
2692
+ }
2693
+ .welcome-submit-btn:hover {
2694
+ background: #0f766e;
2695
+ }
2696
+ .welcome-submit-btn:active {
2697
+ transform: scale(0.98);
2698
+ }
2699
+
2700
+ /* ── 顶部多 Tab 系统 ── */
2701
+ .topbar-tabs {
2702
+ display: flex;
2703
+ align-items: center;
2704
+ gap: 6px;
2705
+ overflow-x: auto;
2706
+ flex: 1;
2707
+ margin-left: 20px;
2708
+ scrollbar-width: none;
2709
+ /* 隐藏滚动条 */
2710
+ }
2711
+
2712
+ .topbar-tabs::-webkit-scrollbar {
2713
+ display: none;
2714
+ }
2715
+
2716
+ .tab-item {
2717
+ display: inline-flex;
2718
+ align-items: center;
2719
+ gap: 6px;
2720
+ height: 32px;
2721
+ padding: 0 12px;
2722
+ border-radius: 6px;
2723
+ font-size: 13px;
2724
+ font-weight: 500;
2725
+ color: var(--text-3);
2726
+ background: transparent;
2727
+ border: 1px solid transparent;
2728
+ cursor: pointer;
2729
+ user-select: none;
2730
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
2731
+ position: relative;
2732
+ }
2733
+
2734
+ .tab-item:hover {
2735
+ color: var(--text-2);
2736
+ background: var(--surface-2);
2737
+ border-color: rgba(148, 163, 184, 0.12);
2738
+ }
2739
+
2740
+ .tab-item.active {
2741
+ color: var(--accent);
2742
+ background: color-mix(in srgb, var(--accent) 8%, var(--surface-2));
2743
+ border-color: color-mix(in srgb, var(--accent) 25%, transparent);
2744
+ box-shadow: 0 2px 8px -2px rgba(45, 212, 191, 0.12);
2745
+ }
2746
+
2747
+ .tab-close {
2748
+ display: inline-flex;
2749
+ align-items: center;
2750
+ justify-content: center;
2751
+ width: 14px;
2752
+ height: 14px;
2753
+ border-radius: 50%;
2754
+ font-size: 10px;
2755
+ color: var(--text-3);
2756
+ margin-left: 2px;
2757
+ margin-right: -4px;
2758
+ opacity: 0.4;
2759
+ transition: all 0.15s;
2760
+ }
2761
+
2762
+ .tab-close:hover {
2763
+ opacity: 1;
2764
+ background: rgba(239, 68, 68, 0.2);
2765
+ color: #ef4444;
2766
+ }
2767
+
2768
+ .add-tab-btn {
2769
+ display: inline-flex;
2770
+ align-items: center;
2771
+ justify-content: center;
2772
+ width: 32px;
2773
+ height: 32px;
2774
+ border-radius: 6px;
2775
+ border: 1px dashed rgba(148, 163, 184, 0.25);
2776
+ background: transparent;
2777
+ color: var(--text-3);
2778
+ cursor: pointer;
2779
+ transition: all 0.2s;
2780
+ flex-shrink: 0;
2781
+ margin-right: auto;
2782
+ /* 保证靠左侧排列 */
2783
+ }
2784
+
2785
+ .add-tab-btn:hover {
2786
+ color: var(--accent);
2787
+ border-color: var(--accent);
2788
+ background: var(--surface-2);
2789
+ transform: scale(1.05);
2790
+ }
2791
+
2792
+ .add-tab-btn svg {
2793
+ width: 16px;
2794
+ height: 16px;
2795
+ }
2796
+
2797
+ /* ── Tab 添加浮动菜单 ── */
2798
+ .add-tab-menu {
2799
+ position: absolute;
2800
+ top: 50px;
2801
+ background: color-mix(in srgb, var(--surface) 95%, transparent);
2802
+ backdrop-filter: blur(12px);
2803
+ border: 1px solid var(--border);
2804
+ border-radius: 8px;
2805
+ box-shadow: var(--shadow);
2806
+ padding: 6px;
2807
+ min-width: 160px;
2808
+ z-index: 1000;
2809
+ display: flex;
2810
+ flex-direction: column;
2811
+ gap: 2px;
2812
+ animation: tabMenuFade 0.15s ease-out;
2813
+ }
2814
+
2815
+ @keyframes tabMenuFade {
2816
+ from {
2817
+ opacity: 0;
2818
+ transform: translateY(-4px);
2819
+ }
2820
+
2821
+ to {
2822
+ opacity: 1;
2823
+ transform: translateY(0);
2824
+ }
2825
+ }
2826
+
2827
+ .add-tab-menu-item {
2828
+ display: flex;
2829
+ align-items: center;
2830
+ gap: 8px;
2831
+ padding: 8px 10px;
2832
+ border-radius: 6px;
2833
+ font-size: 12px;
2834
+ color: var(--text-2);
2835
+ background: transparent;
2836
+ border: none;
2837
+ cursor: pointer;
2838
+ text-align: left;
2839
+ width: 100%;
2840
+ transition: background 0.15s, color 0.15s;
2841
+ }
2842
+
2843
+ .add-tab-menu-item:hover {
2844
+ background: var(--surface-2);
2845
+ color: var(--text);
2846
+ }
2847
+
2848
+ .add-tab-menu-header {
2849
+ font-size: 11px;
2850
+ color: var(--text-3);
2851
+ padding: 6px 10px 4px 10px;
2852
+ font-weight: 600;
2853
+ text-transform: uppercase;
2854
+ letter-spacing: 0.5px;
2855
+ }
2856
+
2857
+ /* ── 顶级独立的多终端显示页面 ── */
2858
+ #page-tab-terminal {
2859
+ display: none;
2860
+ flex-direction: column;
2861
+ height: 100%;
2862
+ background: #111827;
2863
+ border-radius: var(--radius);
2864
+ overflow: hidden;
2865
+ border: 1px solid var(--border);
2866
+ }
2867
+
2868
+ #page-tab-terminal.active {
2869
+ display: flex;
2870
+ }
2871
+
2872
+ .multi-term-container {
2873
+ width: 100%;
2874
+ height: 100%;
2875
+ display: none;
2876
+ }
2877
+
2878
+ .multi-term-container.active {
2879
+ display: flex;
2880
+ flex-direction: column;
2881
+ }
2882
+
2883
+ .multi-term-mount {
2884
+ flex: 1;
2885
+ width: 100%;
2886
+ height: 100%;
2887
+ padding: 10px;
2888
+ background: #111827;
2889
+ overflow: hidden;
2890
+ }
2891
+
2892
+ .chat-raw-line {
2893
+ font-family: var(--mono);
2894
+ font-size: 12px;
2895
+ line-height: 1.5;
2896
+ padding: 4px 8px;
2897
+ border-radius: 4px;
2898
+ margin-bottom: 4px;
2899
+ white-space: pre-wrap;
2900
+ word-break: break-all;
2901
+ }
2902
+
2903
+ @keyframes spin {
2904
+ from { transform: rotate(0deg); }
2905
+ to { transform: rotate(360deg); }
2906
+ }