@lelouchhe/webagent 0.3.0 → 0.4.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.
Files changed (57) hide show
  1. package/README.md +58 -23
  2. package/bin/webagent.mjs +119 -8
  3. package/config.toml +96 -3
  4. package/dist/index.html +64 -41
  5. package/dist/js/app.GSAIYHML.js +4 -0
  6. package/dist/js/chunk.AJZBJBMO.js +1 -0
  7. package/dist/js/chunk.CGWFHJI2.js +76 -0
  8. package/dist/js/chunk.D4ZYHJAM.js +1 -0
  9. package/dist/js/chunk.VZXGXFNN.js +5 -0
  10. package/dist/js/login.PYIK52HN.js +1 -0
  11. package/dist/js/viewer.6DT53STL.js +1 -0
  12. package/dist/login.html +49 -0
  13. package/dist/share-viewer.00gubshk.css +114 -0
  14. package/dist/share-viewer.html +53 -0
  15. package/dist/styles.012p32dz.css +1443 -0
  16. package/dist/sw.js +79 -27
  17. package/dist/theme-init.js +6 -0
  18. package/lib/agent-detect.js +110 -0
  19. package/lib/atomic-write.js +50 -0
  20. package/lib/attachment-dispatch.js +86 -0
  21. package/lib/attachment-interceptor.js +130 -0
  22. package/lib/attachment-labels.js +139 -0
  23. package/lib/attachments.js +154 -0
  24. package/lib/auth-middleware.js +102 -0
  25. package/lib/auth-store.js +269 -0
  26. package/lib/auth.js +89 -0
  27. package/lib/bootstrap.js +70 -0
  28. package/lib/bridge.js +244 -93
  29. package/lib/client-registry.js +60 -0
  30. package/lib/config.js +123 -9
  31. package/lib/daemon.js +175 -41
  32. package/lib/event-handler.js +209 -91
  33. package/lib/log-fmt.js +67 -0
  34. package/lib/log.js +83 -0
  35. package/lib/message-cleanup.js +48 -0
  36. package/lib/mode-bucket.js +62 -0
  37. package/lib/preflight.js +195 -0
  38. package/lib/push-service.js +338 -45
  39. package/lib/routes.js +1202 -144
  40. package/lib/server.js +149 -33
  41. package/lib/session-manager.js +164 -18
  42. package/lib/session-state.js +160 -0
  43. package/lib/sessions-anchor.js +28 -0
  44. package/lib/share/cleanup.js +45 -0
  45. package/lib/share/routes.js +972 -0
  46. package/lib/share/sanitize.js +179 -0
  47. package/lib/sse-manager.js +94 -8
  48. package/lib/sse-ticket.js +45 -0
  49. package/lib/startup-checks.js +94 -0
  50. package/lib/store.js +624 -30
  51. package/lib/title-service.js +42 -9
  52. package/lib/tokens.js +50 -0
  53. package/lib/types.js +23 -0
  54. package/package.json +38 -4
  55. package/dist/js/app.2562YGRO.js +0 -10
  56. package/dist/styles.008ve1hx.css +0 -669
  57. package/lib/shared/constants.js +0 -17
@@ -0,0 +1,1443 @@
1
+ :root {
2
+ --bg: #0d1117;
3
+ --surface: #161b22;
4
+ --border: #30363d;
5
+ --text: #c9d1d9;
6
+ --text-dim: #6e7681;
7
+ --accent: #58a6ff;
8
+ --green: #3fb950;
9
+ --yellow: #d29922;
10
+ --red: #f85149;
11
+ --blue: #58a6ff;
12
+ --radius: 4px;
13
+ --user-bg: #1e3a5f;
14
+ --code-bg: #0d2818;
15
+ --permission-bg: #1c1305;
16
+ --permission-title: #d29922;
17
+ --accent-soft: rgba(88, 166, 255, 0.18);
18
+ }
19
+ [data-theme="light"] {
20
+ --bg: #ffffff;
21
+ --surface: #f6f8fa;
22
+ --border: #d0d7de;
23
+ --text: #1f2328;
24
+ --text-dim: #656d76;
25
+ --accent: #0969da;
26
+ --green: #1a7f37;
27
+ --yellow: #9a6700;
28
+ --red: #cf222e;
29
+ --blue: #0969da;
30
+ --user-bg: #ddf4ff;
31
+ --code-bg: #f0faf0;
32
+ --permission-bg: #fff4cc;
33
+ --permission-title: #7a4f00;
34
+ --accent-soft: rgba(9, 105, 218, 0.14);
35
+ }
36
+ @media (prefers-color-scheme: light) {
37
+ [data-theme="auto"] {
38
+ --bg: #ffffff;
39
+ --surface: #f6f8fa;
40
+ --border: #d0d7de;
41
+ --text: #1f2328;
42
+ --text-dim: #656d76;
43
+ --accent: #0969da;
44
+ --green: #1a7f37;
45
+ --yellow: #9a6700;
46
+ --red: #cf222e;
47
+ --blue: #0969da;
48
+ --user-bg: #ddf4ff;
49
+ --code-bg: #f0faf0;
50
+ --permission-bg: #fff4cc;
51
+ --permission-title: #7a4f00;
52
+ --accent-soft: rgba(9, 105, 218, 0.14);
53
+ }
54
+ }
55
+ * {
56
+ box-sizing: border-box;
57
+ margin: 0;
58
+ padding: 0;
59
+ }
60
+ body {
61
+ font-family: "SF Mono", "Fira Code", "Cascadia Code", "Consolas", monospace;
62
+ background: var(--bg);
63
+ color: var(--text);
64
+ height: 100dvh;
65
+ display: flex;
66
+ flex-direction: column;
67
+ font-size: 16px;
68
+ }
69
+
70
+ /* Header */
71
+ #header {
72
+ padding: 6px 16px;
73
+ background: var(--surface);
74
+ border-bottom: 1px solid var(--border);
75
+ display: grid;
76
+ grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr);
77
+ align-items: center;
78
+ gap: 12px;
79
+ font-size: 15px;
80
+ }
81
+ #header .logo {
82
+ font-weight: bold;
83
+ color: var(--green);
84
+ }
85
+ .header-side {
86
+ min-width: 0;
87
+ display: flex;
88
+ align-items: center;
89
+ }
90
+ .header-left {
91
+ justify-content: flex-start;
92
+ }
93
+ .header-right {
94
+ justify-content: flex-end;
95
+ gap: 12px;
96
+ }
97
+ #header .status {
98
+ color: var(--text-dim);
99
+ }
100
+ #status {
101
+ width: 12px;
102
+ height: 12px;
103
+ display: inline-block;
104
+ flex: 0 0 auto;
105
+ border-radius: 999px;
106
+ border: 2px solid transparent;
107
+ background: transparent;
108
+ }
109
+ #status.is-disconnected {
110
+ background: var(--red);
111
+ border-color: var(--red);
112
+ }
113
+ #status.is-connected {
114
+ background: var(--green);
115
+ border-color: var(--green);
116
+ }
117
+ #status.is-connecting {
118
+ border-color: var(--yellow);
119
+ animation: status-pulse 1.2s ease-in-out infinite;
120
+ }
121
+ @keyframes status-pulse {
122
+ 0%,
123
+ 100% {
124
+ background: transparent;
125
+ opacity: 0.9;
126
+ }
127
+ 50% {
128
+ background: var(--yellow);
129
+ opacity: 1;
130
+ }
131
+ }
132
+ #session-info {
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
135
+ white-space: nowrap;
136
+ min-width: 0;
137
+ width: 100%;
138
+ text-align: center;
139
+ }
140
+ #theme-btn {
141
+ background: transparent;
142
+ border: none;
143
+ color: var(--text-dim);
144
+ cursor: pointer;
145
+ font-size: 15px;
146
+ font-family: inherit;
147
+ padding: 2px 6px;
148
+ }
149
+ #theme-btn:hover {
150
+ color: var(--text);
151
+ }
152
+ @media (max-width: 640px) {
153
+ #header {
154
+ display: flex;
155
+ gap: 8px;
156
+ }
157
+ .header-left,
158
+ .header-right {
159
+ flex: 0 0 auto;
160
+ }
161
+ .header-right {
162
+ margin-left: auto;
163
+ }
164
+ #session-info {
165
+ flex: 1 1 auto;
166
+ text-align: left;
167
+ }
168
+ }
169
+
170
+ /* Messages */
171
+ #messages {
172
+ flex: 1;
173
+ overflow-y: auto;
174
+ padding: 16px;
175
+ display: flex;
176
+ flex-direction: column;
177
+ gap: 4px;
178
+ }
179
+ #messages > * {
180
+ min-width: 0;
181
+ max-width: 100%;
182
+ overflow-wrap: break-word;
183
+ }
184
+ .msg {
185
+ padding: 8px 14px;
186
+ line-height: 1.6;
187
+ font-size: 16px;
188
+ overflow-wrap: break-word;
189
+ }
190
+ .msg.user {
191
+ background: var(--user-bg);
192
+ border-left: 3px solid var(--accent);
193
+ border-radius: 0 var(--radius) var(--radius) 0;
194
+ margin: 8px 0 4px 0;
195
+ font-weight: 500;
196
+ }
197
+ .msg.user::before {
198
+ content: "▶ ";
199
+ color: var(--accent);
200
+ font-weight: bold;
201
+ }
202
+ .msg.assistant {
203
+ padding: 4px 14px;
204
+ }
205
+ .msg.assistant pre {
206
+ background: none;
207
+ padding: 8px 14px;
208
+ overflow-x: auto;
209
+ margin: 0;
210
+ font-size: 15px;
211
+ border-radius: 0;
212
+ }
213
+ .msg.assistant code {
214
+ font-family: "SF Mono", "Fira Code", monospace;
215
+ font-size: 15px;
216
+ }
217
+
218
+ /* Code block wrapper — aligned with prompt/permission/thinking style */
219
+ .code-block-wrapper {
220
+ margin: 8px -14px;
221
+ background: var(--code-bg);
222
+ border-left: 3px solid var(--green);
223
+ border-radius: 0 var(--radius) var(--radius) 0;
224
+ position: relative;
225
+ overflow: hidden;
226
+ }
227
+ .code-block-wrapper pre {
228
+ margin: 0;
229
+ padding: 8px 14px;
230
+ }
231
+ .code-block-wrapper pre code,
232
+ .code-block-wrapper pre code.hljs {
233
+ background: none;
234
+ padding: 0;
235
+ }
236
+ .code-toolbar {
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: flex-end;
240
+ padding: 2px 6px;
241
+ position: absolute;
242
+ top: 0;
243
+ right: 0;
244
+ z-index: 1;
245
+ font-size: 12px;
246
+ color: var(--text-dim);
247
+ gap: 8px;
248
+ opacity: 0;
249
+ transition: opacity 0.15s;
250
+ }
251
+ .code-block-wrapper:hover .code-toolbar {
252
+ opacity: 1;
253
+ }
254
+ .copy-btn {
255
+ background: transparent;
256
+ color: var(--text-dim);
257
+ border: 1px solid var(--border);
258
+ border-radius: var(--radius);
259
+ min-width: 28px;
260
+ height: 22px;
261
+ padding: 0 4px;
262
+ font-size: 12px;
263
+ font-family: inherit;
264
+ cursor: pointer;
265
+ display: inline-flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ line-height: 1;
269
+ transition:
270
+ color 0.15s,
271
+ border-color 0.15s;
272
+ }
273
+ .copy-btn:hover {
274
+ color: var(--text);
275
+ border-color: var(--text-dim);
276
+ }
277
+ .copy-btn.copied {
278
+ color: var(--green);
279
+ border-color: var(--green);
280
+ }
281
+ .msg.assistant p {
282
+ margin: 4px 0;
283
+ }
284
+ .msg.assistant ul,
285
+ .msg.assistant ol {
286
+ padding-left: 20px;
287
+ margin: 4px 0;
288
+ }
289
+ .msg.assistant table {
290
+ border-collapse: collapse;
291
+ margin: 8px 0;
292
+ font-family: inherit;
293
+ font-size: inherit;
294
+ line-height: 1.5;
295
+ display: block;
296
+ overflow-x: auto;
297
+ max-width: 100%;
298
+ }
299
+ .msg.assistant th,
300
+ .msg.assistant td {
301
+ border: 1px solid var(--border);
302
+ padding: 5px 12px;
303
+ text-align: left;
304
+ vertical-align: top;
305
+ }
306
+ .msg.assistant th {
307
+ color: var(--green);
308
+ border-color: var(--green);
309
+ font-weight: normal;
310
+ }
311
+
312
+ /* Thinking */
313
+ .thinking {
314
+ color: var(--text-dim);
315
+ font-style: italic;
316
+ font-size: 15px;
317
+ padding: 6px 14px;
318
+ border-left: 2px solid var(--border);
319
+ }
320
+ .thinking summary {
321
+ cursor: pointer;
322
+ }
323
+ .thinking-content {
324
+ cursor: default;
325
+ }
326
+ .thinking summary.active {
327
+ animation: pulse 1.5s ease-in-out infinite;
328
+ }
329
+
330
+ /* Inbox message card — same collapsible feel as .thinking but with accent. */
331
+ .message {
332
+ color: var(--text);
333
+ font-size: 15px;
334
+ padding: 6px 14px;
335
+ border-left: 2px solid var(--accent-muted, var(--accent));
336
+ margin: 6px 0;
337
+ }
338
+ .message summary {
339
+ cursor: pointer;
340
+ color: var(--text-dim);
341
+ font-size: 13px;
342
+ font-style: italic;
343
+ }
344
+ .message-content {
345
+ cursor: default;
346
+ margin-top: 4px;
347
+ }
348
+
349
+ /* Waiting indicator (after user sends, before first response) */
350
+ @keyframes blink {
351
+ 0%,
352
+ 100% {
353
+ opacity: 1;
354
+ }
355
+ 50% {
356
+ opacity: 0.3;
357
+ }
358
+ }
359
+ @keyframes pulse {
360
+ 0%,
361
+ 100% {
362
+ opacity: 1;
363
+ }
364
+ 50% {
365
+ opacity: 0.4;
366
+ }
367
+ }
368
+ #waiting {
369
+ padding: 6px 14px;
370
+ color: var(--text-dim);
371
+ font-size: 15px;
372
+ }
373
+ #waiting .cursor {
374
+ animation: blink 1s step-end infinite;
375
+ }
376
+
377
+ /* System messages */
378
+ .system-msg {
379
+ font-size: 15px;
380
+ padding: 2px 14px;
381
+ color: var(--text-dim);
382
+ white-space: pre-wrap;
383
+ }
384
+ .system-msg a {
385
+ color: var(--accent);
386
+ text-decoration: underline;
387
+ word-break: break-all;
388
+ }
389
+ .system-msg a:hover {
390
+ color: var(--text);
391
+ }
392
+
393
+ /* Tool calls */
394
+ .tool-call {
395
+ font-size: 15px;
396
+ padding: 2px 14px;
397
+ color: var(--text-dim);
398
+ animation: pulse 1.5s ease-in-out infinite;
399
+ }
400
+ .tool-call .icon {
401
+ margin-right: 4px;
402
+ }
403
+ .tool-call.completed {
404
+ color: var(--green);
405
+ animation: none;
406
+ }
407
+ .tool-call.failed {
408
+ color: var(--red);
409
+ animation: none;
410
+ }
411
+ .tool-call {
412
+ cursor: pointer;
413
+ }
414
+ .tool-call .tc-detail {
415
+ display: block;
416
+ color: var(--text-dim);
417
+ white-space: nowrap;
418
+ overflow: hidden;
419
+ text-overflow: ellipsis;
420
+ max-width: 100%;
421
+ }
422
+ .tool-call .tc-detail.expanded {
423
+ white-space: pre-wrap;
424
+ overflow: visible;
425
+ text-overflow: unset;
426
+ }
427
+ .tool-call details {
428
+ margin-top: 2px;
429
+ }
430
+ .tool-call details summary {
431
+ cursor: pointer;
432
+ color: var(--text-dim);
433
+ }
434
+ .tool-call .tc-content {
435
+ margin: 4px 0 4px 16px;
436
+ padding: 6px 10px;
437
+ background: var(--code-bg);
438
+ border-radius: var(--radius);
439
+ font-size: 14px;
440
+ white-space: pre-wrap;
441
+ max-height: 200px;
442
+ overflow-y: auto;
443
+ color: var(--text);
444
+ cursor: default;
445
+ }
446
+ .tool-call .tc-summary {
447
+ margin: 4px 0 4px 16px;
448
+ font-size: 14px;
449
+ color: var(--text);
450
+ }
451
+
452
+ /* Diff view for edit tool calls */
453
+ .diff-view {
454
+ margin: 4px 0 4px 16px;
455
+ padding: 6px 10px;
456
+ background: var(--code-bg);
457
+ border-radius: var(--radius);
458
+ font-size: 13px;
459
+ font-family: monospace;
460
+ white-space: pre-wrap;
461
+ word-break: break-all;
462
+ max-height: 300px;
463
+ overflow-y: auto;
464
+ line-height: 1.4;
465
+ cursor: default;
466
+ }
467
+ .diff-view .diff-file {
468
+ color: var(--blue);
469
+ font-weight: bold;
470
+ }
471
+ .diff-view .diff-hunk {
472
+ color: var(--text-dim);
473
+ }
474
+ .diff-view .diff-del {
475
+ color: var(--red);
476
+ }
477
+ .diff-view .diff-add {
478
+ color: var(--green);
479
+ }
480
+
481
+ /* Plan */
482
+ .plan {
483
+ font-size: 15px;
484
+ padding: 6px 14px;
485
+ border-left: 3px solid var(--blue);
486
+ border-radius: 0 var(--radius) var(--radius) 0;
487
+ }
488
+ .plan-title {
489
+ color: var(--blue);
490
+ font-weight: bold;
491
+ margin-bottom: 2px;
492
+ }
493
+ .plan-entry {
494
+ padding: 1px 0;
495
+ }
496
+
497
+ /* Permission dialog */
498
+ .permission {
499
+ background: var(--permission-bg);
500
+ border-left: 3px solid var(--yellow);
501
+ border-radius: 0 var(--radius) var(--radius) 0;
502
+ padding: 8px 14px;
503
+ font-size: 15px;
504
+ }
505
+ .permission .title {
506
+ color: var(--permission-title);
507
+ font-weight: bold;
508
+ margin-bottom: 6px;
509
+ }
510
+ .permission button {
511
+ margin: 2px 4px 2px 0;
512
+ padding: 4px 10px;
513
+ border: 1px solid var(--border);
514
+ border-radius: var(--radius);
515
+ background: transparent;
516
+ color: var(--text);
517
+ cursor: pointer;
518
+ font-size: 14px;
519
+ font-family: inherit;
520
+ }
521
+ .permission button:hover {
522
+ background: var(--surface);
523
+ }
524
+ .permission button.allow {
525
+ border-color: var(--green);
526
+ }
527
+ .permission button.deny {
528
+ border-color: var(--red);
529
+ }
530
+
531
+ /* Bash command output */
532
+ .bash-block {
533
+ margin: 2px 0;
534
+ padding: 2px 14px;
535
+ font-size: 15px;
536
+ min-width: 0;
537
+ overflow-wrap: break-word;
538
+ }
539
+ .bash-block .bash-cmd {
540
+ color: var(--green);
541
+ font-family: monospace;
542
+ font-size: 14px;
543
+ cursor: pointer;
544
+ overflow-wrap: break-word;
545
+ }
546
+ .bash-block .bash-cmd::before {
547
+ content: "$ ";
548
+ color: var(--text-dim);
549
+ }
550
+ .bash-block .bash-cmd.running {
551
+ animation: pulse 1.5s ease-in-out infinite;
552
+ }
553
+ .bash-block .bash-output {
554
+ margin: 4px 0 4px 0;
555
+ padding: 6px 10px;
556
+ background: var(--code-bg);
557
+ border-radius: var(--radius);
558
+ font-size: 13px;
559
+ font-family: monospace;
560
+ white-space: pre-wrap;
561
+ word-break: break-all;
562
+ max-height: 400px;
563
+ overflow-y: auto;
564
+ color: var(--text);
565
+ line-height: 1.4;
566
+ display: none;
567
+ }
568
+ .bash-block .bash-output.has-content {
569
+ display: block;
570
+ }
571
+ .bash-block .bash-output .stderr {
572
+ color: var(--red);
573
+ }
574
+ .bash-block .bash-exit {
575
+ font-size: 13px;
576
+ color: var(--text-dim);
577
+ margin-left: 8px;
578
+ }
579
+ .bash-block .bash-exit.ok {
580
+ color: var(--green);
581
+ }
582
+ .bash-block .bash-exit.fail {
583
+ color: var(--red);
584
+ }
585
+
586
+ /* Input */
587
+ #input-area {
588
+ position: relative;
589
+ padding: 8px 16px 4px;
590
+ background: var(--bg);
591
+ border-top: 1px solid var(--border);
592
+ display: flex;
593
+ align-items: center;
594
+ gap: 4px;
595
+ transition: border-color 0.15s;
596
+ }
597
+ #input-area.bash-mode {
598
+ border-top: 2px solid #e8872b;
599
+ }
600
+ #input-area.bash-mode #input-prompt {
601
+ --prompt-color: #e8872b;
602
+ color: var(--prompt-color);
603
+ }
604
+ #input-area.bash-mode #input {
605
+ color: #e8872b;
606
+ }
607
+ #input-area.plan-mode {
608
+ border-top: 2px solid var(--green);
609
+ }
610
+ #input-area.plan-mode #input-prompt {
611
+ --prompt-color: var(--green);
612
+ color: var(--prompt-color);
613
+ }
614
+ #input-area.plan-mode #mode-pill {
615
+ color: var(--green);
616
+ }
617
+ #input-area.autopilot-mode {
618
+ border-top: 2px solid var(--red);
619
+ }
620
+ #input-area.autopilot-mode #input-prompt {
621
+ --prompt-color: var(--red);
622
+ color: var(--prompt-color);
623
+ }
624
+ #input-area.autopilot-mode #mode-pill {
625
+ color: var(--red);
626
+ }
627
+ #input-area.preview-mode {
628
+ border-top: 2px solid var(--blue);
629
+ }
630
+ #input-area.preview-mode #input-prompt {
631
+ --prompt-color: var(--blue);
632
+ color: var(--prompt-color);
633
+ }
634
+ #input-area.preview-mode #mode-pill {
635
+ color: var(--blue);
636
+ }
637
+ /* Mode pill: JS writes the actual mode name (#plan, autopilot, default,
638
+ acceptEdits, etc.) into textContent. The :empty selector hides the
639
+ element when there's no mode to show (e.g. before configOptions land).
640
+ Color comes from the bucket-specific rules above; default is dim. */
641
+ #mode-pill {
642
+ position: absolute;
643
+ top: -7px;
644
+ left: 16px;
645
+ font-size: 10px;
646
+ line-height: 1;
647
+ padding: 0 4px;
648
+ background: var(--bg);
649
+ color: var(--text-dim);
650
+ text-transform: uppercase;
651
+ letter-spacing: 0.5px;
652
+ }
653
+ #mode-pill:empty {
654
+ display: none;
655
+ }
656
+ #status-bar {
657
+ display: flex;
658
+ padding: 0 16px 10px;
659
+ background: var(--bg);
660
+ color: var(--text-dim);
661
+ font-size: 11px;
662
+ line-height: 1.4;
663
+ white-space: nowrap;
664
+ user-select: none;
665
+ }
666
+ #status-bar::before {
667
+ content: "\200b";
668
+ }
669
+ #status-bar .status-cwd {
670
+ overflow: hidden;
671
+ text-overflow: ellipsis;
672
+ direction: rtl;
673
+ text-align: left;
674
+ }
675
+ #input-prompt {
676
+ --prompt-color: var(--text);
677
+ color: var(--prompt-color);
678
+ font-weight: bold;
679
+ user-select: none;
680
+ line-height: 1.5;
681
+ cursor: pointer;
682
+ }
683
+ #input-prompt::before {
684
+ content: "❯ ";
685
+ }
686
+ #input-prompt.busy::before {
687
+ content: "⠋ ";
688
+ animation: spinner 0.8s steps(1) infinite;
689
+ }
690
+ #input {
691
+ flex: 1;
692
+ background: transparent;
693
+ color: var(--text);
694
+ border: none;
695
+ padding: 4px 8px;
696
+ font-size: 16px;
697
+ font-family: inherit;
698
+ resize: none;
699
+ min-height: 28px;
700
+ max-height: 200px;
701
+ line-height: 1.5;
702
+ }
703
+ #input:focus {
704
+ outline: none;
705
+ }
706
+ .input-btn {
707
+ background: transparent;
708
+ color: var(--text-dim);
709
+ border: 1px solid var(--border);
710
+ border-radius: var(--radius);
711
+ width: 34px;
712
+ height: 28px;
713
+ padding: 0 6px;
714
+ font-size: 14px;
715
+ font-family: inherit;
716
+ cursor: pointer;
717
+ display: inline-flex;
718
+ align-items: center;
719
+ justify-content: center;
720
+ line-height: 1;
721
+ flex: 0 0 auto;
722
+ }
723
+ .input-btn:hover {
724
+ color: var(--text);
725
+ border-color: var(--text-dim);
726
+ }
727
+ #send-btn.cancel {
728
+ color: var(--red);
729
+ border-color: var(--red);
730
+ font-weight: bold;
731
+ }
732
+ #send-btn.cancel:hover,
733
+ #send-btn.cancel:focus,
734
+ #send-btn.cancel:active {
735
+ color: var(--red);
736
+ border-color: var(--red);
737
+ }
738
+ .input-btn.publish {
739
+ color: var(--blue);
740
+ border-color: var(--blue);
741
+ font-weight: bold;
742
+ }
743
+ .input-btn.publish:hover,
744
+ .input-btn.publish:focus,
745
+ .input-btn.publish:active {
746
+ color: var(--blue);
747
+ border-color: var(--blue);
748
+ }
749
+ #input-area.preview-mode #input {
750
+ opacity: 0.5;
751
+ cursor: not-allowed;
752
+ }
753
+ @keyframes spinner {
754
+ 0% {
755
+ content: "⠋";
756
+ }
757
+ 10% {
758
+ content: "⠙";
759
+ }
760
+ 20% {
761
+ content: "⠹";
762
+ }
763
+ 30% {
764
+ content: "⠸";
765
+ }
766
+ 40% {
767
+ content: "⠼";
768
+ }
769
+ 50% {
770
+ content: "⠴";
771
+ }
772
+ 60% {
773
+ content: "⠦";
774
+ }
775
+ 70% {
776
+ content: "⠧";
777
+ }
778
+ 80% {
779
+ content: "⠇";
780
+ }
781
+ 90% {
782
+ content: "⠏";
783
+ }
784
+ }
785
+
786
+ /* Slash command autocomplete */
787
+ #slash-menu {
788
+ display: none;
789
+ position: absolute;
790
+ bottom: 100%;
791
+ left: 0;
792
+ right: 0;
793
+ background: var(--surface);
794
+ border: 1px solid var(--border);
795
+ border-bottom: none;
796
+ max-height: 220px;
797
+ overflow-y: auto;
798
+ z-index: 10;
799
+ }
800
+ #slash-menu.active {
801
+ display: block;
802
+ }
803
+
804
+ .slash-item {
805
+ padding: 6px 6px;
806
+ cursor: pointer;
807
+ font-size: 15px;
808
+ display: flex;
809
+ flex-direction: column;
810
+ gap: 2px;
811
+ width: max-content;
812
+ min-width: 100%;
813
+ box-sizing: border-box;
814
+ }
815
+ .slash-item:hover,
816
+ .slash-item.selected {
817
+ background: var(--accent-soft);
818
+ }
819
+
820
+ .slash-row-l1 {
821
+ display: grid;
822
+ grid-template-columns: 1ch auto 1fr;
823
+ align-items: baseline;
824
+ gap: 4px;
825
+ min-width: 100%;
826
+ }
827
+ .slash-row-l2 {
828
+ grid-column: 2 / -1;
829
+ display: flex;
830
+ align-items: baseline;
831
+ gap: 8px;
832
+ color: var(--text-dim);
833
+ font-size: 12px;
834
+ line-height: 1.4;
835
+ padding-left: calc(4ch + 4px);
836
+ min-width: 100%;
837
+ }
838
+
839
+ .slash-prefix {
840
+ display: inline-block;
841
+ width: 1ch;
842
+ text-align: center;
843
+ user-select: none;
844
+ flex: 0 0 auto;
845
+ }
846
+ .slash-primary {
847
+ font-weight: bold;
848
+ white-space: nowrap;
849
+ }
850
+ .slash-menu-root .slash-primary {
851
+ min-width: 7ch;
852
+ }
853
+ .slash-current {
854
+ color: var(--green);
855
+ }
856
+ .slash-secondary {
857
+ color: var(--text-dim);
858
+ white-space: nowrap;
859
+ margin-left: 1ch;
860
+ }
861
+ .slash-path {
862
+ white-space: nowrap;
863
+ overflow: hidden;
864
+ text-overflow: ellipsis;
865
+ direction: rtl;
866
+ text-align: left;
867
+ flex: 1 1 auto;
868
+ min-width: 0;
869
+ }
870
+ .slash-path-secondary {
871
+ white-space: nowrap;
872
+ flex: 0 0 auto;
873
+ }
874
+
875
+ .slash-separator {
876
+ height: 1px;
877
+ background: var(--border);
878
+ opacity: 0.5;
879
+ margin: 4px 0;
880
+ }
881
+ .slash-placeholder {
882
+ color: var(--text-dim);
883
+ font-style: italic;
884
+ }
885
+ .slash-placeholder:hover,
886
+ .slash-placeholder.selected {
887
+ background: transparent;
888
+ cursor: default;
889
+ }
890
+
891
+ /* Image attach */
892
+ #attach-preview {
893
+ display: none;
894
+ padding: 4px 16px;
895
+ background: var(--bg);
896
+ border-top: 1px solid var(--border);
897
+ }
898
+ #attach-preview.active {
899
+ display: flex;
900
+ gap: 8px;
901
+ flex-wrap: wrap;
902
+ align-items: center;
903
+ }
904
+ .attach-thumb {
905
+ position: relative;
906
+ display: inline-block;
907
+ }
908
+ .attach-thumb img {
909
+ max-height: 60px;
910
+ max-width: 120px;
911
+ border-radius: 4px;
912
+ border: 1px solid var(--border);
913
+ }
914
+ .attach-thumb.attach-file {
915
+ border: 1px solid var(--border);
916
+ border-radius: 4px;
917
+ padding: 6px 8px;
918
+ font-size: 12px;
919
+ color: var(--fg);
920
+ background: var(--bg-alt, transparent);
921
+ max-width: 200px;
922
+ }
923
+ .attach-thumb.attach-file .attach-file-name {
924
+ display: inline-block;
925
+ max-width: 170px;
926
+ overflow: hidden;
927
+ text-overflow: ellipsis;
928
+ white-space: nowrap;
929
+ vertical-align: middle;
930
+ }
931
+ .attach-thumb .remove {
932
+ position: absolute;
933
+ top: -4px;
934
+ right: -4px;
935
+ background: var(--red);
936
+ color: #fff;
937
+ border: none;
938
+ border-radius: 50%;
939
+ width: 16px;
940
+ height: 16px;
941
+ font-size: 10px;
942
+ line-height: 16px;
943
+ text-align: center;
944
+ cursor: pointer;
945
+ padding: 0;
946
+ }
947
+ .msg.user img.user-image {
948
+ max-width: 200px;
949
+ max-height: 150px;
950
+ border-radius: 4px;
951
+ border: 1px solid var(--border);
952
+ display: block;
953
+ margin-top: 4px;
954
+ cursor: zoom-in;
955
+ }
956
+ .msg.user a.user-file {
957
+ display: inline-block;
958
+ margin-top: 4px;
959
+ padding: 2px 6px;
960
+ border: 1px solid var(--border);
961
+ border-radius: 4px;
962
+ color: var(--accent);
963
+ text-decoration: none;
964
+ font-family: monospace;
965
+ font-size: 0.9em;
966
+ }
967
+ .msg.user a.user-file:hover {
968
+ text-decoration: underline;
969
+ }
970
+
971
+ /* Image lightbox overlay */
972
+ #lightbox-overlay {
973
+ position: fixed;
974
+ inset: 0;
975
+ z-index: 9999;
976
+ background: rgba(0, 0, 0, 0.85);
977
+ display: flex;
978
+ align-items: center;
979
+ justify-content: center;
980
+ cursor: zoom-out;
981
+ visibility: hidden;
982
+ pointer-events: none;
983
+ }
984
+ #lightbox-overlay.active {
985
+ visibility: visible;
986
+ pointer-events: auto;
987
+ }
988
+ #lightbox-overlay img {
989
+ max-width: 90vw;
990
+ max-height: 90vh;
991
+ border-radius: 6px;
992
+ cursor: default;
993
+ }
994
+
995
+ /* History pagination sentinel */
996
+ .history-sentinel {
997
+ text-align: center;
998
+ padding: 8px;
999
+ opacity: 0.5;
1000
+ font-size: 0.85em;
1001
+ }
1002
+
1003
+ /* Utility: dim out cancelled / settled / past states. Used in dynamic innerHTML
1004
+ where inline `style="opacity:0.5"` would violate strict CSP `style-src 'self'`. */
1005
+ .dim {
1006
+ opacity: 0.5;
1007
+ }
1008
+
1009
+ /* --- Login page (extracted from login.html for CSP `style-src 'self'`) --- */
1010
+ body.login-page {
1011
+ display: flex;
1012
+ align-items: center;
1013
+ justify-content: center;
1014
+ min-height: 100vh;
1015
+ margin: 0;
1016
+ }
1017
+ .login-card {
1018
+ width: 100%;
1019
+ max-width: 480px;
1020
+ padding: 2rem 1.5rem;
1021
+ box-sizing: border-box;
1022
+ }
1023
+ .login-card h1 {
1024
+ font-size: 1.2rem;
1025
+ margin: 0 0 0.5rem;
1026
+ }
1027
+ .login-card p {
1028
+ font-size: 0.9rem;
1029
+ opacity: 0.75;
1030
+ margin: 0 0 1.25rem;
1031
+ line-height: 1.45;
1032
+ }
1033
+ .login-card input {
1034
+ width: 100%;
1035
+ box-sizing: border-box;
1036
+ font-family: inherit;
1037
+ font-size: 0.95rem;
1038
+ padding: 0.6rem;
1039
+ border: 1px solid currentColor;
1040
+ border-radius: 4px;
1041
+ background: transparent;
1042
+ color: inherit;
1043
+ }
1044
+ .login-card .error {
1045
+ display: none;
1046
+ margin-top: 0.75rem;
1047
+ padding: 0.5rem 0.75rem;
1048
+ border: 1px solid #c0392b;
1049
+ color: #c0392b;
1050
+ border-radius: 4px;
1051
+ font-size: 0.85rem;
1052
+ }
1053
+ .login-card button {
1054
+ margin-top: 1rem;
1055
+ width: 100%;
1056
+ padding: 0.6rem;
1057
+ font: inherit;
1058
+ cursor: pointer;
1059
+ border: 1px solid currentColor;
1060
+ background: transparent;
1061
+ color: inherit;
1062
+ border-radius: 4px;
1063
+ }
1064
+ .login-card button:disabled {
1065
+ opacity: 0.5;
1066
+ cursor: not-allowed;
1067
+ }
1068
+ .login-card .hint {
1069
+ font-size: 0.78rem;
1070
+ opacity: 0.6;
1071
+ margin-top: 1rem;
1072
+ }
1073
+ .login-card code {
1074
+ background: rgba(127, 127, 127, 0.15);
1075
+ padding: 0.1rem 0.35rem;
1076
+ border-radius: 3px;
1077
+ }
1078
+
1079
+ /* --- highlight.js themes (vendored from highlight.js@common, BSD-3-Clause) --- */
1080
+ /* light: default */
1081
+ pre code.hljs {
1082
+ display: block;
1083
+ overflow-x: auto;
1084
+ padding: 1em
1085
+ }
1086
+ code.hljs {
1087
+ padding: 3px 5px
1088
+ }
1089
+ /*!
1090
+ Theme: GitHub
1091
+ Description: Light theme as seen on github.com
1092
+ Author: github.com
1093
+ Maintainer: @Hirse
1094
+ Updated: 2021-05-15
1095
+
1096
+ Outdated base version: https://github.com/primer/github-syntax-light
1097
+ Current colors taken from GitHub's CSS
1098
+ */
1099
+ .hljs {
1100
+ color: #24292e;
1101
+ background: #ffffff
1102
+ }
1103
+ .hljs-doctag,
1104
+ .hljs-keyword,
1105
+ .hljs-meta .hljs-keyword,
1106
+ .hljs-template-tag,
1107
+ .hljs-template-variable,
1108
+ .hljs-type,
1109
+ .hljs-variable.language_ {
1110
+ /* prettylights-syntax-keyword */
1111
+ color: #d73a49
1112
+ }
1113
+ .hljs-title,
1114
+ .hljs-title.class_,
1115
+ .hljs-title.class_.inherited__,
1116
+ .hljs-title.function_ {
1117
+ /* prettylights-syntax-entity */
1118
+ color: #6f42c1
1119
+ }
1120
+ .hljs-attr,
1121
+ .hljs-attribute,
1122
+ .hljs-literal,
1123
+ .hljs-meta,
1124
+ .hljs-number,
1125
+ .hljs-operator,
1126
+ .hljs-variable,
1127
+ .hljs-selector-attr,
1128
+ .hljs-selector-class,
1129
+ .hljs-selector-id {
1130
+ /* prettylights-syntax-constant */
1131
+ color: #005cc5
1132
+ }
1133
+ .hljs-regexp,
1134
+ .hljs-string,
1135
+ .hljs-meta .hljs-string {
1136
+ /* prettylights-syntax-string */
1137
+ color: #032f62
1138
+ }
1139
+ .hljs-built_in,
1140
+ .hljs-symbol {
1141
+ /* prettylights-syntax-variable */
1142
+ color: #e36209
1143
+ }
1144
+ .hljs-comment,
1145
+ .hljs-code,
1146
+ .hljs-formula {
1147
+ /* prettylights-syntax-comment */
1148
+ color: #6a737d
1149
+ }
1150
+ .hljs-name,
1151
+ .hljs-quote,
1152
+ .hljs-selector-tag,
1153
+ .hljs-selector-pseudo {
1154
+ /* prettylights-syntax-entity-tag */
1155
+ color: #22863a
1156
+ }
1157
+ .hljs-subst {
1158
+ /* prettylights-syntax-storage-modifier-import */
1159
+ color: #24292e
1160
+ }
1161
+ .hljs-section {
1162
+ /* prettylights-syntax-markup-heading */
1163
+ color: #005cc5;
1164
+ font-weight: bold
1165
+ }
1166
+ .hljs-bullet {
1167
+ /* prettylights-syntax-markup-list */
1168
+ color: #735c0f
1169
+ }
1170
+ .hljs-emphasis {
1171
+ /* prettylights-syntax-markup-italic */
1172
+ color: #24292e;
1173
+ font-style: italic
1174
+ }
1175
+ .hljs-strong {
1176
+ /* prettylights-syntax-markup-bold */
1177
+ color: #24292e;
1178
+ font-weight: bold
1179
+ }
1180
+ .hljs-addition {
1181
+ /* prettylights-syntax-markup-inserted */
1182
+ color: #22863a;
1183
+ background-color: #f0fff4
1184
+ }
1185
+ .hljs-deletion {
1186
+ /* prettylights-syntax-markup-deleted */
1187
+ color: #b31d28;
1188
+ background-color: #ffeef0
1189
+ }
1190
+ .hljs-char.escape_,
1191
+ .hljs-link,
1192
+ .hljs-params,
1193
+ .hljs-property,
1194
+ .hljs-punctuation,
1195
+ .hljs-tag {
1196
+ /* purposely ignored */
1197
+
1198
+ }
1199
+ /* dark: explicit */
1200
+ [data-theme="dark"] {
1201
+ pre code.hljs {
1202
+ display: block;
1203
+ overflow-x: auto;
1204
+ padding: 1em
1205
+ }
1206
+ code.hljs {
1207
+ padding: 3px 5px
1208
+ }
1209
+ /*!
1210
+ Theme: GitHub Dark
1211
+ Description: Dark theme as seen on github.com
1212
+ Author: github.com
1213
+ Maintainer: @Hirse
1214
+ Updated: 2021-05-15
1215
+
1216
+ Outdated base version: https://github.com/primer/github-syntax-dark
1217
+ Current colors taken from GitHub's CSS
1218
+ */
1219
+ .hljs {
1220
+ color: #c9d1d9;
1221
+ background: #0d1117
1222
+ }
1223
+ .hljs-doctag,
1224
+ .hljs-keyword,
1225
+ .hljs-meta .hljs-keyword,
1226
+ .hljs-template-tag,
1227
+ .hljs-template-variable,
1228
+ .hljs-type,
1229
+ .hljs-variable.language_ {
1230
+ /* prettylights-syntax-keyword */
1231
+ color: #ff7b72
1232
+ }
1233
+ .hljs-title,
1234
+ .hljs-title.class_,
1235
+ .hljs-title.class_.inherited__,
1236
+ .hljs-title.function_ {
1237
+ /* prettylights-syntax-entity */
1238
+ color: #d2a8ff
1239
+ }
1240
+ .hljs-attr,
1241
+ .hljs-attribute,
1242
+ .hljs-literal,
1243
+ .hljs-meta,
1244
+ .hljs-number,
1245
+ .hljs-operator,
1246
+ .hljs-variable,
1247
+ .hljs-selector-attr,
1248
+ .hljs-selector-class,
1249
+ .hljs-selector-id {
1250
+ /* prettylights-syntax-constant */
1251
+ color: #79c0ff
1252
+ }
1253
+ .hljs-regexp,
1254
+ .hljs-string,
1255
+ .hljs-meta .hljs-string {
1256
+ /* prettylights-syntax-string */
1257
+ color: #a5d6ff
1258
+ }
1259
+ .hljs-built_in,
1260
+ .hljs-symbol {
1261
+ /* prettylights-syntax-variable */
1262
+ color: #ffa657
1263
+ }
1264
+ .hljs-comment,
1265
+ .hljs-code,
1266
+ .hljs-formula {
1267
+ /* prettylights-syntax-comment */
1268
+ color: #8b949e
1269
+ }
1270
+ .hljs-name,
1271
+ .hljs-quote,
1272
+ .hljs-selector-tag,
1273
+ .hljs-selector-pseudo {
1274
+ /* prettylights-syntax-entity-tag */
1275
+ color: #7ee787
1276
+ }
1277
+ .hljs-subst {
1278
+ /* prettylights-syntax-storage-modifier-import */
1279
+ color: #c9d1d9
1280
+ }
1281
+ .hljs-section {
1282
+ /* prettylights-syntax-markup-heading */
1283
+ color: #1f6feb;
1284
+ font-weight: bold
1285
+ }
1286
+ .hljs-bullet {
1287
+ /* prettylights-syntax-markup-list */
1288
+ color: #f2cc60
1289
+ }
1290
+ .hljs-emphasis {
1291
+ /* prettylights-syntax-markup-italic */
1292
+ color: #c9d1d9;
1293
+ font-style: italic
1294
+ }
1295
+ .hljs-strong {
1296
+ /* prettylights-syntax-markup-bold */
1297
+ color: #c9d1d9;
1298
+ font-weight: bold
1299
+ }
1300
+ .hljs-addition {
1301
+ /* prettylights-syntax-markup-inserted */
1302
+ color: #aff5b4;
1303
+ background-color: #033a16
1304
+ }
1305
+ .hljs-deletion {
1306
+ /* prettylights-syntax-markup-deleted */
1307
+ color: #ffdcd7;
1308
+ background-color: #67060c
1309
+ }
1310
+ .hljs-char.escape_,
1311
+ .hljs-link,
1312
+ .hljs-params,
1313
+ .hljs-property,
1314
+ .hljs-punctuation,
1315
+ .hljs-tag {
1316
+ /* purposely ignored */
1317
+
1318
+ }
1319
+ }
1320
+
1321
+ /* dark: auto + system prefers dark */
1322
+ @media (prefers-color-scheme: dark) {
1323
+ [data-theme="auto"] {
1324
+ pre code.hljs {
1325
+ display: block;
1326
+ overflow-x: auto;
1327
+ padding: 1em
1328
+ }
1329
+ code.hljs {
1330
+ padding: 3px 5px
1331
+ }
1332
+ /*!
1333
+ Theme: GitHub Dark
1334
+ Description: Dark theme as seen on github.com
1335
+ Author: github.com
1336
+ Maintainer: @Hirse
1337
+ Updated: 2021-05-15
1338
+
1339
+ Outdated base version: https://github.com/primer/github-syntax-dark
1340
+ Current colors taken from GitHub's CSS
1341
+ */
1342
+ .hljs {
1343
+ color: #c9d1d9;
1344
+ background: #0d1117
1345
+ }
1346
+ .hljs-doctag,
1347
+ .hljs-keyword,
1348
+ .hljs-meta .hljs-keyword,
1349
+ .hljs-template-tag,
1350
+ .hljs-template-variable,
1351
+ .hljs-type,
1352
+ .hljs-variable.language_ {
1353
+ /* prettylights-syntax-keyword */
1354
+ color: #ff7b72
1355
+ }
1356
+ .hljs-title,
1357
+ .hljs-title.class_,
1358
+ .hljs-title.class_.inherited__,
1359
+ .hljs-title.function_ {
1360
+ /* prettylights-syntax-entity */
1361
+ color: #d2a8ff
1362
+ }
1363
+ .hljs-attr,
1364
+ .hljs-attribute,
1365
+ .hljs-literal,
1366
+ .hljs-meta,
1367
+ .hljs-number,
1368
+ .hljs-operator,
1369
+ .hljs-variable,
1370
+ .hljs-selector-attr,
1371
+ .hljs-selector-class,
1372
+ .hljs-selector-id {
1373
+ /* prettylights-syntax-constant */
1374
+ color: #79c0ff
1375
+ }
1376
+ .hljs-regexp,
1377
+ .hljs-string,
1378
+ .hljs-meta .hljs-string {
1379
+ /* prettylights-syntax-string */
1380
+ color: #a5d6ff
1381
+ }
1382
+ .hljs-built_in,
1383
+ .hljs-symbol {
1384
+ /* prettylights-syntax-variable */
1385
+ color: #ffa657
1386
+ }
1387
+ .hljs-comment,
1388
+ .hljs-code,
1389
+ .hljs-formula {
1390
+ /* prettylights-syntax-comment */
1391
+ color: #8b949e
1392
+ }
1393
+ .hljs-name,
1394
+ .hljs-quote,
1395
+ .hljs-selector-tag,
1396
+ .hljs-selector-pseudo {
1397
+ /* prettylights-syntax-entity-tag */
1398
+ color: #7ee787
1399
+ }
1400
+ .hljs-subst {
1401
+ /* prettylights-syntax-storage-modifier-import */
1402
+ color: #c9d1d9
1403
+ }
1404
+ .hljs-section {
1405
+ /* prettylights-syntax-markup-heading */
1406
+ color: #1f6feb;
1407
+ font-weight: bold
1408
+ }
1409
+ .hljs-bullet {
1410
+ /* prettylights-syntax-markup-list */
1411
+ color: #f2cc60
1412
+ }
1413
+ .hljs-emphasis {
1414
+ /* prettylights-syntax-markup-italic */
1415
+ color: #c9d1d9;
1416
+ font-style: italic
1417
+ }
1418
+ .hljs-strong {
1419
+ /* prettylights-syntax-markup-bold */
1420
+ color: #c9d1d9;
1421
+ font-weight: bold
1422
+ }
1423
+ .hljs-addition {
1424
+ /* prettylights-syntax-markup-inserted */
1425
+ color: #aff5b4;
1426
+ background-color: #033a16
1427
+ }
1428
+ .hljs-deletion {
1429
+ /* prettylights-syntax-markup-deleted */
1430
+ color: #ffdcd7;
1431
+ background-color: #67060c
1432
+ }
1433
+ .hljs-char.escape_,
1434
+ .hljs-link,
1435
+ .hljs-params,
1436
+ .hljs-property,
1437
+ .hljs-punctuation,
1438
+ .hljs-tag {
1439
+ /* purposely ignored */
1440
+
1441
+ }
1442
+ }
1443
+ }