agent-loft 0.2.28 → 0.2.30

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. package/package.json +1 -1
  2. package/src/channels/web/server.ts +1 -1
  3. package/web/app.js +8 -5555
  4. package/web/css/base.css +291 -0
  5. package/web/css/composer.css +506 -0
  6. package/web/css/loader.css +196 -0
  7. package/web/css/messages.css +734 -0
  8. package/web/css/mobile.css +100 -0
  9. package/web/css/overlay.css +437 -0
  10. package/web/css/schedule.css +93 -0
  11. package/web/css/settings.css +335 -0
  12. package/web/css/sidebar.css +593 -0
  13. package/web/css/topbar.css +205 -0
  14. package/web/index.html +11 -1
  15. package/web/lib/api.js +26 -0
  16. package/web/lib/dom.js +101 -0
  17. package/web/lib/markdown.js +52 -0
  18. package/web/lib/overlay.js +144 -0
  19. package/web/lib/push.js +70 -0
  20. package/web/lib/time.js +60 -0
  21. package/web/lib/ws.js +232 -0
  22. package/web/settings/agents.js +210 -0
  23. package/web/settings/commands.js +411 -0
  24. package/web/settings/common.js +42 -0
  25. package/web/settings/feishu.js +181 -0
  26. package/web/settings/general.js +184 -0
  27. package/web/settings/index.js +63 -0
  28. package/web/settings/memory.js +366 -0
  29. package/web/settings/notify.js +80 -0
  30. package/web/settings/security.js +188 -0
  31. package/web/settings/users.js +189 -0
  32. package/web/state.js +44 -0
  33. package/web/views/auth.js +61 -0
  34. package/web/views/composer.js +324 -0
  35. package/web/views/conv-actions.js +404 -0
  36. package/web/views/interaction.js +140 -0
  37. package/web/views/layout.js +186 -0
  38. package/web/views/messages.js +510 -0
  39. package/web/views/quota.js +145 -0
  40. package/web/views/schedule.js +120 -0
  41. package/web/views/sidebar.js +455 -0
  42. package/web/views/slash.js +185 -0
  43. package/web/views/topbar.js +394 -0
  44. package/web/views/voice.js +189 -0
  45. package/web/style.css +0 -3500
@@ -0,0 +1,593 @@
1
+ /* ---------- 布局 ---------- */
2
+
3
+ .layout {
4
+ display: flex;
5
+ height: 100%;
6
+ overflow: hidden;
7
+ position: relative;
8
+ }
9
+
10
+ .sidebar {
11
+ width: var(--side-w);
12
+ flex-shrink: 0;
13
+ position: relative;
14
+ background: var(--bg-side);
15
+ display: flex;
16
+ flex-direction: column;
17
+ border-right: 1px solid var(--border);
18
+ padding-top: env(safe-area-inset-top);
19
+ }
20
+
21
+ /* 侧栏右边缘的拖动条:hover 时显示一条细线 */
22
+ .side-resizer {
23
+ position: absolute;
24
+ top: 0;
25
+ bottom: 0;
26
+ right: -4px;
27
+ width: 8px;
28
+ cursor: col-resize;
29
+ z-index: 10;
30
+ touch-action: none;
31
+ }
32
+
33
+ .side-resizer::after {
34
+ content: "";
35
+ position: absolute;
36
+ top: 0;
37
+ bottom: 0;
38
+ left: 3px;
39
+ width: 2px;
40
+ background: var(--accent);
41
+ opacity: 0;
42
+ transition: opacity 0.15s;
43
+ }
44
+
45
+ .side-resizer:hover::after,
46
+ .side-resizing .side-resizer::after {
47
+ opacity: 0.6;
48
+ transition-delay: 0.1s;
49
+ }
50
+
51
+ body.side-resizing {
52
+ cursor: col-resize;
53
+ user-select: none;
54
+ }
55
+
56
+ @media (max-width: 768px) {
57
+ .side-resizer {
58
+ display: none;
59
+ }
60
+ }
61
+
62
+ .side-top {
63
+ padding: 10px 10px 0;
64
+ display: flex;
65
+ gap: 8px;
66
+ }
67
+
68
+ .side-top .new-chat {
69
+ flex: 1;
70
+ justify-content: flex-start;
71
+ background: transparent;
72
+ border: none;
73
+ /* 和下面的会话行同字号、同字重 */
74
+ padding: 7px 10px;
75
+ gap: 8px;
76
+ font-size: 14px;
77
+ font-weight: 400;
78
+ }
79
+
80
+ .side-top .new-chat svg {
81
+ width: 16px;
82
+ height: 16px;
83
+ }
84
+
85
+ .side-top .new-chat:hover {
86
+ background: var(--bg-hover);
87
+ }
88
+
89
+ .conv-list {
90
+ flex: 1;
91
+ overflow-y: auto;
92
+ padding: 0 8px 8px;
93
+ }
94
+
95
+ .conv-group {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 4px;
99
+ width: 100%;
100
+ font-size: 13px;
101
+ color: var(--fg-faint);
102
+ padding: 14px 10px 6px;
103
+ text-align: left;
104
+ }
105
+
106
+ .conv-list > .conv-group:first-child {
107
+ padding-top: 8px;
108
+ }
109
+
110
+ /* 分组标题 hover 时显示折叠箭头 */
111
+ .conv-group .chev {
112
+ display: inline-grid;
113
+ visibility: hidden;
114
+ transition: transform 0.15s;
115
+ }
116
+
117
+ .conv-group .chev svg {
118
+ width: 12px;
119
+ height: 12px;
120
+ }
121
+
122
+ .conv-group:hover .chev {
123
+ visibility: visible;
124
+ }
125
+
126
+ .conv-group.collapsed .chev {
127
+ transform: rotate(-90deg);
128
+ }
129
+
130
+ button.conv-group:hover {
131
+ color: var(--fg-soft);
132
+ }
133
+
134
+ .conv-empty {
135
+ font-size: 13px;
136
+ color: var(--fg-faint);
137
+ padding: 4px 10px;
138
+ }
139
+
140
+ .conv-more {
141
+ display: block;
142
+ width: 100%;
143
+ text-align: left;
144
+ padding: 6px 10px;
145
+ border-radius: 8px;
146
+ font-size: 13px;
147
+ color: var(--fg-faint);
148
+ }
149
+
150
+ .conv-more:hover {
151
+ color: var(--fg);
152
+ }
153
+
154
+ .sub-more .conv-more {
155
+ padding-left: 36px;
156
+ }
157
+
158
+ .conv-item .lead {
159
+ width: 14px;
160
+ height: 14px;
161
+ opacity: 0.85;
162
+ }
163
+
164
+ .conv-item.sub {
165
+ padding-left: 36px;
166
+ }
167
+
168
+ .proj-row {
169
+ position: relative;
170
+ margin-top: 2px;
171
+ }
172
+
173
+ .conv-item.proj {
174
+ gap: 10px;
175
+ }
176
+
177
+ /* 拖动目录排序:被拖的行变淡,落点处画一条横线 */
178
+ .proj-row.dragging {
179
+ opacity: 0.4;
180
+ }
181
+
182
+ .proj-row.drop-before::before,
183
+ .proj-row.drop-after::after {
184
+ content: "";
185
+ position: absolute;
186
+ left: 8px;
187
+ right: 8px;
188
+ height: 2px;
189
+ border-radius: 1px;
190
+ background: var(--accent, #3b82f6);
191
+ pointer-events: none;
192
+ z-index: 1;
193
+ }
194
+
195
+ .proj-row.drop-before::before {
196
+ top: -2px;
197
+ }
198
+
199
+ .proj-row.drop-after::after {
200
+ bottom: -2px;
201
+ }
202
+
203
+ .proj-icon {
204
+ display: inline-grid;
205
+ color: var(--fg-soft);
206
+ flex-shrink: 0;
207
+ }
208
+
209
+ .proj-icon svg {
210
+ width: 18px;
211
+ height: 18px;
212
+ }
213
+
214
+ /* 目录行 hover 时右侧出现「在此目录开新对话」 */
215
+ .proj-new {
216
+ position: absolute;
217
+ right: 4px;
218
+ top: 50%;
219
+ transform: translateY(-50%);
220
+ width: 28px;
221
+ height: 28px;
222
+ display: none;
223
+ place-items: center;
224
+ border-radius: 50%;
225
+ color: var(--fg-soft);
226
+ }
227
+
228
+ .proj-new svg {
229
+ width: 15px;
230
+ height: 15px;
231
+ }
232
+
233
+ .proj-new:hover {
234
+ background: var(--bg-soft);
235
+ color: var(--fg);
236
+ }
237
+
238
+ .proj-row:hover .proj-new {
239
+ display: grid;
240
+ }
241
+
242
+ .proj-row:hover .conv-item.proj {
243
+ padding-right: 36px;
244
+ }
245
+
246
+ @media (pointer: coarse) {
247
+ .proj-new {
248
+ display: grid;
249
+ }
250
+ }
251
+
252
+ .conv-item {
253
+ display: flex;
254
+ align-items: center;
255
+ gap: 8px;
256
+ width: 100%;
257
+ text-align: left;
258
+ padding: 7px 10px;
259
+ border-radius: 8px;
260
+ font-size: 14px;
261
+ position: relative;
262
+ }
263
+
264
+ .conv-item:hover {
265
+ background: var(--bg-hover);
266
+ }
267
+
268
+ .conv-item.active {
269
+ background: var(--bg-hover);
270
+ }
271
+
272
+ .conv-item .title {
273
+ flex: 1;
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ white-space: nowrap;
277
+ }
278
+
279
+ /* 跑马灯滚动时去掉省略号 */
280
+ .conv-item .title.marquee {
281
+ text-overflow: clip;
282
+ }
283
+
284
+ .conv-item .badge {
285
+ font-size: 11px;
286
+ color: var(--fg-faint);
287
+ flex-shrink: 0;
288
+ }
289
+
290
+ .dot {
291
+ width: 8px;
292
+ height: 8px;
293
+ border-radius: 50%;
294
+ flex-shrink: 0;
295
+ }
296
+
297
+ /* 进行中:Codex 那种细圈转圈,一段弧在淡色圆环上转 */
298
+ .conv-spin {
299
+ width: 13px;
300
+ height: 13px;
301
+ flex-shrink: 0;
302
+ border-radius: 50%;
303
+ border: 1.5px solid color-mix(in srgb, var(--fg-faint) 28%, transparent);
304
+ border-top-color: var(--fg-soft);
305
+ animation: spin 0.75s linear infinite;
306
+ }
307
+
308
+ .dot.ask {
309
+ background: #f59f00;
310
+ }
311
+
312
+ @keyframes pulse {
313
+ 50% {
314
+ opacity: 0.3;
315
+ }
316
+ }
317
+
318
+ .side-bottom {
319
+ border-top: 1px solid var(--border);
320
+ padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
321
+ display: flex;
322
+ align-items: center;
323
+ gap: 6px;
324
+ min-height: 48px;
325
+ }
326
+
327
+ .side-gear {
328
+ margin-left: auto;
329
+ }
330
+
331
+ /* 桌面端里:设置在顶栏「更多」里,侧栏底部只留额度(额度由桌面端统一查好推过来) */
332
+ .desktop-settings .side-gear {
333
+ display: none;
334
+ }
335
+
336
+ /* ---- 侧栏底部的额度 ---- */
337
+ .quota {
338
+ position: relative;
339
+ flex: 1;
340
+ min-width: 0;
341
+ }
342
+
343
+ .quota-btn {
344
+ display: flex;
345
+ flex-direction: column;
346
+ gap: 4px;
347
+ width: 100%;
348
+ padding: 5px 6px;
349
+ border-radius: 8px;
350
+ text-align: left;
351
+ }
352
+
353
+ .quota-btn:hover {
354
+ background: var(--bg-hover);
355
+ }
356
+
357
+ .quota.loading .quota-btn {
358
+ opacity: 0.6;
359
+ }
360
+
361
+ .quota-row {
362
+ display: flex;
363
+ align-items: center;
364
+ gap: 8px;
365
+ font-size: 11px;
366
+ color: var(--fg-soft);
367
+ font-variant-numeric: tabular-nums;
368
+ }
369
+
370
+ .quota-icon svg {
371
+ width: 13px;
372
+ height: 13px;
373
+ }
374
+
375
+ .quota-icon {
376
+ display: inline-grid;
377
+ color: var(--fg-soft);
378
+ flex-shrink: 0;
379
+ }
380
+
381
+ .quota-cell {
382
+ display: flex;
383
+ align-items: center;
384
+ gap: 4px;
385
+ flex: 1;
386
+ min-width: 0;
387
+ }
388
+
389
+ .q-label {
390
+ color: var(--fg-faint);
391
+ flex-shrink: 0;
392
+ }
393
+
394
+ .q-bar {
395
+ flex: 1;
396
+ min-width: 14px;
397
+ height: 4px;
398
+ border-radius: 2px;
399
+ background: color-mix(in srgb, var(--fg-faint) 22%, transparent);
400
+ overflow: hidden;
401
+ }
402
+
403
+ .q-bar i {
404
+ display: block;
405
+ height: 100%;
406
+ border-radius: 2px;
407
+ background: var(--fg-soft);
408
+ }
409
+
410
+ .q-pct {
411
+ flex-shrink: 0;
412
+ min-width: 26px;
413
+ text-align: right;
414
+ }
415
+
416
+ .quota-cell.warn .q-bar i {
417
+ background: #f59f00;
418
+ }
419
+
420
+ .quota-cell.danger .q-bar i {
421
+ background: var(--danger);
422
+ }
423
+
424
+ .quota-cell.danger .q-pct {
425
+ color: var(--danger);
426
+ }
427
+
428
+ /* hover 详情:从底部向上弹出 */
429
+ .quota-tip {
430
+ position: absolute;
431
+ left: 0;
432
+ bottom: calc(100% + 8px);
433
+ width: 310px;
434
+ max-width: calc(100vw - 24px);
435
+ padding: 10px 12px;
436
+ border-radius: 12px;
437
+ background: var(--bg);
438
+ border: 1px solid var(--border);
439
+ box-shadow: var(--shadow);
440
+ font-size: 12px;
441
+ color: var(--fg-soft);
442
+ display: flex;
443
+ flex-direction: column;
444
+ gap: 10px;
445
+ opacity: 0;
446
+ visibility: hidden;
447
+ transform: translateY(4px);
448
+ transition: opacity 0.12s, transform 0.12s, visibility 0.12s;
449
+ pointer-events: none;
450
+ z-index: 20;
451
+ }
452
+
453
+ .quota:hover .quota-tip {
454
+ opacity: 1;
455
+ visibility: visible;
456
+ transform: none;
457
+ transition-delay: 0.25s;
458
+ }
459
+
460
+ .qt-head {
461
+ display: flex;
462
+ align-items: center;
463
+ gap: 6px;
464
+ color: var(--fg);
465
+ margin-bottom: 4px;
466
+ }
467
+
468
+ .qt-head .agent-icon {
469
+ display: inline-grid;
470
+ }
471
+
472
+ .qt-head .agent-icon svg {
473
+ width: 14px;
474
+ height: 14px;
475
+ }
476
+
477
+ .qt-plan {
478
+ margin-left: auto;
479
+ font-size: 11px;
480
+ color: var(--fg-faint);
481
+ text-transform: capitalize;
482
+ }
483
+
484
+ .qt-row {
485
+ display: grid;
486
+ grid-template-columns: auto auto 1fr;
487
+ gap: 8px;
488
+ padding: 2px 0 2px 20px;
489
+ }
490
+
491
+ .qt-name {
492
+ color: var(--fg);
493
+ white-space: nowrap;
494
+ }
495
+
496
+ .qt-pct.warn {
497
+ color: #d98200;
498
+ }
499
+
500
+ .qt-pct.danger {
501
+ color: var(--danger);
502
+ }
503
+
504
+ .qt-reset {
505
+ text-align: right;
506
+ white-space: nowrap;
507
+ color: var(--fg-faint);
508
+ }
509
+
510
+ .qt-extra {
511
+ padding-left: 20px;
512
+ color: var(--fg-faint);
513
+ }
514
+
515
+ .qt-extra.danger {
516
+ color: var(--danger);
517
+ }
518
+
519
+ .qt-foot {
520
+ border-top: 1px solid var(--border);
521
+ padding-top: 8px;
522
+ font-size: 11px;
523
+ color: var(--fg-faint);
524
+ }
525
+
526
+ .conv-item .fork-mark {
527
+ color: var(--fg-soft);
528
+ }
529
+
530
+ /*
531
+ * 分叉树:分叉对话缩进挂在主对话下面,虚线连起来。
532
+ * 竖线从主对话标题下方往下走,每个分叉一个拐角;最后一个分叉的竖线只画到它的拐角为止。
533
+ * 行高约 34px(.conv-item 上下 7px + 一行字),拐角在 17px 处。
534
+ */
535
+ .fork-children {
536
+ margin-left: 16px;
537
+ }
538
+
539
+ /* 「项目」里的会话行本身缩进 36px,竖线跟着右移 */
540
+ .fork-children.in-proj {
541
+ margin-left: 42px;
542
+ }
543
+
544
+ /* 分叉的分叉:竖线对齐上一层分叉的标题 */
545
+ .fork-node .fork-children {
546
+ margin-left: 14px;
547
+ }
548
+
549
+ .fork-children .conv-item,
550
+ .fork-children .conv-item.sub {
551
+ padding-left: 8px;
552
+ }
553
+
554
+ .fork-node {
555
+ position: relative;
556
+ padding-left: 14px;
557
+ }
558
+
559
+ .fork-node::before,
560
+ .fork-node::after {
561
+ content: "";
562
+ position: absolute;
563
+ left: 0;
564
+ border: 0 dashed var(--fg-faint);
565
+ opacity: 0.7;
566
+ pointer-events: none;
567
+ }
568
+
569
+ .fork-node::before {
570
+ top: 0;
571
+ bottom: 0;
572
+ border-left-width: 1px;
573
+ }
574
+
575
+ /* 第一个分叉的竖线往上接到主对话那一行 */
576
+ .fork-node:first-child::before {
577
+ top: -6px;
578
+ }
579
+
580
+ .fork-node:last-child::before {
581
+ bottom: auto;
582
+ height: 17px;
583
+ }
584
+
585
+ .fork-node:first-child:last-child::before {
586
+ height: 23px;
587
+ }
588
+
589
+ .fork-node::after {
590
+ top: 17px;
591
+ width: 10px;
592
+ border-top-width: 1px;
593
+ }