leedab 0.2.6 → 0.3.1

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.
Binary file
@@ -1,162 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <link rel="icon" type="image/png" href="/favicon.png">
7
- <title>LeedAB — Sessions</title>
8
- <link rel="stylesheet" href="/style.css">
9
- </head>
10
- <body>
11
- <style>
12
- .page-header { display:flex; align-items:center; justify-content:space-between; padding:0 20px; height:52px; border-bottom:1px solid var(--border); background:var(--bg); }
13
- .page-header-left { display:flex; align-items:center; gap:10px; }
14
- .page-header-title { display:flex; align-items:center; }
15
- .page-header-title .logo-img { height:22px; width:auto; display:block; }
16
- .page-nav { display:flex; align-items:center; gap:2px; }
17
- .page-nav a, .page-nav button { color:var(--text-dim); text-decoration:none; display:flex; align-items:center; gap:5px; padding:6px 12px; border-radius:8px; font-size:13px; font-weight:450; transition:all 0.15s; background:none; border:none; cursor:pointer; font-family:inherit; }
18
- .page-nav a:hover, .page-nav button:hover { color:var(--text-secondary); background:var(--surface-raised); }
19
- .page-nav .theme-btn { border:1px solid var(--border); padding:5px 8px; }
20
- </style>
21
-
22
- <div class="page-header">
23
- <div class="page-header-left">
24
- <a href="/" class="page-header-title" aria-label="LeedAB"><img class="logo-img" alt="LeedAB"></a>
25
- </div>
26
- <div class="page-nav">
27
- </div>
28
- </div>
29
-
30
- <div class="container">
31
- <main>
32
- <p class="section-desc">Conversation history across all channels. Read-only log.</p>
33
-
34
- <div class="session-list" id="session-list">
35
- <div style="color:var(--text-dim);font-size:14px;padding:24px 0">Loading sessions...</div>
36
- </div>
37
- </main>
38
- </div>
39
-
40
- <style>
41
- .session-list {
42
- display: flex;
43
- flex-direction: column;
44
- gap: 8px;
45
- }
46
-
47
- .session-item {
48
- display: flex;
49
- align-items: center;
50
- justify-content: space-between;
51
- padding: 16px 20px;
52
- background: var(--surface);
53
- border: 1px solid var(--border);
54
- border-radius: 12px;
55
- text-decoration: none;
56
- color: inherit;
57
- transition: border-color 0.15s;
58
- }
59
-
60
- .session-item:hover {
61
- border-color: var(--border-hover);
62
- }
63
-
64
- .session-info h3 {
65
- font-size: 14px;
66
- font-weight: 500;
67
- margin-bottom: 2px;
68
- }
69
-
70
- .session-info p {
71
- font-size: 12px;
72
- color: var(--text-dim);
73
- }
74
-
75
- .session-summary {
76
- color: var(--text-secondary) !important;
77
- font-size: 13px !important;
78
- margin-bottom: 2px;
79
- overflow: hidden;
80
- text-overflow: ellipsis;
81
- white-space: nowrap;
82
- max-width: 500px;
83
- }
84
-
85
- .session-meta {
86
- font-size: 12px;
87
- color: var(--text-faint);
88
- text-align: right;
89
- }
90
-
91
- .session-meta .channel {
92
- display: inline-block;
93
- padding: 2px 8px;
94
- background: var(--accent-soft);
95
- color: var(--accent);
96
- border-radius: 6px;
97
- font-size: 11px;
98
- margin-bottom: 4px;
99
- }
100
- </style>
101
-
102
- <script>
103
- function initTheme() {
104
- const saved = localStorage.getItem("leedab-theme") || "dark";
105
- document.documentElement.setAttribute("data-theme", saved);
106
- const src = saved === "dark" ? "/logo-dark.png" : "/logo-light.png";
107
- document.querySelectorAll(".logo-img").forEach(img => img.src = src);
108
- }
109
- initTheme();
110
-
111
- document.addEventListener("DOMContentLoaded", loadSessions);
112
-
113
- async function loadSessions() {
114
- const list = document.getElementById("session-list");
115
- try {
116
- const res = await fetch("/api/sessions");
117
- const sessions = await res.json();
118
-
119
- if (!sessions.length) {
120
- list.innerHTML = '<div style="text-align:center;padding:48px 0;color:var(--text-dim);font-size:14px">No conversations yet.</div>';
121
- return;
122
- }
123
-
124
- list.innerHTML = sessions.map(s => {
125
- const date = s.updatedAt ? new Date(s.updatedAt).toLocaleDateString("en-US", {
126
- month: "short", day: "numeric", hour: "numeric", minute: "2-digit"
127
- }) : "";
128
- // Derive channel from key like "agent:main:telegram:direct:123"
129
- const parts = (s.key || "").split(":");
130
- let channel = "console";
131
- if (parts[2] === "telegram") channel = "telegram";
132
- else if (parts[2] === "cron") channel = "cron";
133
- else if (parts[2] === "subagent") channel = "subagent";
134
-
135
- const title = s.senderName || channel;
136
- const summary = s.summary ? escapeHtml(s.summary) : "";
137
- const tokens = s.totalTokens != null ? `${(s.totalTokens / 1000).toFixed(1)}k tokens` : "";
138
- const sid = s.sessionId || s.key || "";
139
- return `
140
- <a class="session-item" href="/?session=${encodeURIComponent(sid)}">
141
- <div class="session-info">
142
- <h3>${escapeHtml(title)}</h3>
143
- ${summary ? `<p class="session-summary">${summary}</p>` : ""}
144
- <p>${escapeHtml(s.model || "")} ${tokens ? "· " + tokens : ""}</p>
145
- </div>
146
- <div class="session-meta">
147
- <div class="channel">${channel}</div>
148
- <div>${date}</div>
149
- </div>
150
- </a>`;
151
- }).join("");
152
- } catch {
153
- list.innerHTML = '<div style="text-align:center;padding:48px 0;color:var(--text-dim);font-size:14px">Could not load sessions. Is the gateway running?</div>';
154
- }
155
- }
156
-
157
- function escapeHtml(str) {
158
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
159
- }
160
- </script>
161
- </body>
162
- </html>
@@ -1,493 +0,0 @@
1
- * {
2
- margin: 0;
3
- padding: 0;
4
- box-sizing: border-box;
5
- }
6
-
7
- :root {
8
- --bg: #0a0a0b;
9
- --surface: #141416;
10
- --surface-raised: #18181b;
11
- --border: #232328;
12
- --border-hover: #333338;
13
- --text: #e4e4e7;
14
- --text-secondary: #a1a1aa;
15
- --text-dim: #71717a;
16
- --text-faint: #52525b;
17
- --accent: #AE5630;
18
- --accent-hover: #c4633a;
19
- --accent-soft: rgba(174, 86, 48, 0.08);
20
- --accent-medium: rgba(174, 86, 48, 0.15);
21
- --success: #22c55e;
22
- --warning: #f59e0b;
23
- --error: #ef4444;
24
- --radius: 12px;
25
- --radius-sm: 8px;
26
- }
27
-
28
- [data-theme="light"] {
29
- --bg: #f8f8fa;
30
- --surface: #ffffff;
31
- --surface-raised: #f0f0f3;
32
- --border: #d4d4d8;
33
- --border-hover: #a1a1aa;
34
- --text: #18181b;
35
- --text-secondary: #3f3f46;
36
- --text-dim: #52525b;
37
- --text-faint: #71717a;
38
- --accent: #9a4528;
39
- --accent-hover: #AE5630;
40
- --accent-soft: rgba(174, 86, 48, 0.06);
41
- --accent-medium: rgba(174, 86, 48, 0.12);
42
- --success: #16a34a;
43
- --warning: #d97706;
44
- --error: #dc2626;
45
- }
46
-
47
- body {
48
- font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
49
- background: var(--bg);
50
- color: var(--text);
51
- min-height: 100vh;
52
- line-height: 1.5;
53
- -webkit-font-smoothing: antialiased;
54
- -moz-osx-font-smoothing: grayscale;
55
- }
56
-
57
- .container {
58
- max-width: 720px;
59
- margin: 0 auto;
60
- padding: 48px 24px;
61
- }
62
-
63
- header {
64
- margin-bottom: 48px;
65
- }
66
-
67
- header h1 {
68
- font-size: 2rem;
69
- font-weight: 700;
70
- letter-spacing: -0.02em;
71
- }
72
-
73
- .subtitle {
74
- color: var(--text-dim);
75
- margin-top: 4px;
76
- }
77
-
78
- /* Sections */
79
- .section {
80
- margin-bottom: 40px;
81
- }
82
-
83
- .section-title {
84
- font-size: 1rem;
85
- font-weight: 600;
86
- margin-bottom: 4px;
87
- text-transform: uppercase;
88
- letter-spacing: 0.05em;
89
- color: var(--text-secondary);
90
- font-size: 0.75rem;
91
- }
92
-
93
- .section-desc {
94
- color: var(--text-dim);
95
- font-size: 0.875rem;
96
- margin-bottom: 16px;
97
- }
98
-
99
- /* Info grid */
100
- .info-grid {
101
- display: flex;
102
- gap: 24px;
103
- flex-wrap: wrap;
104
- }
105
-
106
- .info-item {
107
- display: flex;
108
- flex-direction: column;
109
- gap: 2px;
110
- }
111
-
112
- .info-label {
113
- font-size: 0.75rem;
114
- color: var(--text-faint);
115
- text-transform: uppercase;
116
- letter-spacing: 0.05em;
117
- }
118
-
119
- .info-value {
120
- font-size: 0.9rem;
121
- color: var(--text);
122
- font-weight: 500;
123
- }
124
-
125
- .info-value code {
126
- background: var(--surface-raised);
127
- padding: 2px 8px;
128
- border-radius: 4px;
129
- font-family: "SF Mono", "Fira Code", monospace;
130
- font-size: 0.85rem;
131
- }
132
-
133
- /* Badge */
134
- .badge {
135
- display: inline-flex;
136
- align-items: center;
137
- gap: 6px;
138
- padding: 3px 10px;
139
- border-radius: 20px;
140
- font-size: 12px;
141
- font-weight: 500;
142
- }
143
-
144
- .badge-dot {
145
- width: 6px;
146
- height: 6px;
147
- border-radius: 50%;
148
- }
149
-
150
- .badge-online {
151
- background: rgba(34, 197, 94, 0.1);
152
- color: var(--success);
153
- }
154
-
155
- .badge-online .badge-dot {
156
- background: var(--success);
157
- }
158
-
159
- .badge-offline {
160
- background: rgba(239, 68, 68, 0.1);
161
- color: var(--error);
162
- }
163
-
164
- .badge-offline .badge-dot {
165
- background: var(--error);
166
- }
167
-
168
- /* Cards */
169
- .cards {
170
- display: grid;
171
- grid-template-columns: 1fr 1fr;
172
- gap: 12px;
173
- }
174
-
175
- @media (max-width: 600px) {
176
- .cards {
177
- grid-template-columns: 1fr;
178
- }
179
- }
180
-
181
- .card {
182
- display: flex;
183
- align-items: flex-start;
184
- gap: 12px;
185
- background: var(--surface);
186
- border: 1px solid var(--border);
187
- border-radius: var(--radius);
188
- padding: 16px;
189
- transition: border-color 0.15s;
190
- flex-wrap: wrap;
191
- }
192
-
193
- .card .btn {
194
- margin-top: 4px;
195
- width: 100%;
196
- text-align: center;
197
- }
198
-
199
- .card:hover {
200
- border-color: var(--border-hover);
201
- }
202
-
203
- .card.connected {
204
- border-color: color-mix(in srgb, var(--success) 40%, transparent);
205
- }
206
-
207
- .card-icon {
208
- flex-shrink: 0;
209
- width: 48px;
210
- height: 48px;
211
- display: flex;
212
- align-items: center;
213
- justify-content: center;
214
- background: var(--accent-soft);
215
- border-radius: 12px;
216
- color: var(--accent);
217
- }
218
-
219
- .connected .card-icon {
220
- background: color-mix(in srgb, var(--success) 10%, transparent);
221
- color: var(--success);
222
- }
223
-
224
- .card-body {
225
- flex: 1;
226
- min-width: 0;
227
- }
228
-
229
- .card-body h3 {
230
- font-size: 1rem;
231
- font-weight: 600;
232
- }
233
-
234
- .card-body p {
235
- color: var(--text-dim);
236
- font-size: 0.875rem;
237
- margin-top: 2px;
238
- }
239
-
240
- .card-status {
241
- display: flex;
242
- align-items: center;
243
- gap: 6px;
244
- font-size: 0.8rem;
245
- color: var(--text-dim);
246
- margin-top: 6px;
247
- }
248
-
249
- .dot {
250
- width: 8px;
251
- height: 8px;
252
- border-radius: 50%;
253
- background: var(--border);
254
- display: inline-block;
255
- }
256
-
257
- .connected .dot {
258
- background: var(--success);
259
- }
260
-
261
- /* Buttons */
262
- .btn {
263
- background: var(--accent);
264
- color: white;
265
- border: none;
266
- padding: 8px 20px;
267
- border-radius: var(--radius-sm);
268
- font-size: 0.875rem;
269
- font-weight: 500;
270
- cursor: pointer;
271
- transition: background 0.15s;
272
- white-space: nowrap;
273
- flex-shrink: 0;
274
- text-decoration: none;
275
- }
276
-
277
- .btn:hover {
278
- background: var(--accent-hover);
279
- }
280
-
281
- .btn:disabled {
282
- opacity: 0.5;
283
- cursor: not-allowed;
284
- }
285
-
286
- .btn-ghost {
287
- background: var(--surface-raised);
288
- color: var(--text-secondary);
289
- border: 1px solid var(--border-hover);
290
- }
291
-
292
- .btn-ghost:hover {
293
- background: var(--accent-soft);
294
- color: var(--text);
295
- border-color: var(--accent);
296
- }
297
-
298
- .btn-connected {
299
- background: color-mix(in srgb, var(--success) 15%, transparent);
300
- color: var(--success);
301
- cursor: default;
302
- }
303
-
304
- .btn-connected:hover {
305
- background: color-mix(in srgb, var(--success) 15%, transparent);
306
- }
307
-
308
- .btn-danger {
309
- background: transparent;
310
- color: var(--error);
311
- border: 1px solid color-mix(in srgb, var(--error) 30%, transparent);
312
- padding: 4px 12px;
313
- font-size: 0.8rem;
314
- }
315
-
316
- .btn-danger:hover {
317
- background: color-mix(in srgb, var(--error) 10%, transparent);
318
- }
319
-
320
- /* Form panel */
321
- .form-panel {
322
- background: var(--surface);
323
- border: 1px solid var(--border);
324
- border-radius: var(--radius);
325
- padding: 24px;
326
- margin-top: 16px;
327
- }
328
-
329
- .form-panel h3 {
330
- font-size: 1rem;
331
- font-weight: 600;
332
- margin-bottom: 4px;
333
- }
334
-
335
- .form-help {
336
- color: var(--text-dim);
337
- font-size: 0.85rem;
338
- margin-bottom: 16px;
339
- }
340
-
341
- .form-help a {
342
- color: var(--accent);
343
- text-decoration: none;
344
- }
345
-
346
- .form-panel label {
347
- display: block;
348
- font-size: 0.85rem;
349
- color: var(--text-dim);
350
- margin-bottom: 12px;
351
- }
352
-
353
- .form-panel input,
354
- .form-panel textarea {
355
- display: block;
356
- width: 100%;
357
- margin-top: 4px;
358
- padding: 10px 12px;
359
- background: var(--bg);
360
- border: 1px solid var(--border);
361
- border-radius: 8px;
362
- color: var(--text);
363
- font-size: 0.9rem;
364
- font-family: inherit;
365
- }
366
-
367
- .form-panel input:focus,
368
- .form-panel textarea:focus {
369
- outline: none;
370
- border-color: var(--accent);
371
- }
372
-
373
- .form-panel textarea {
374
- resize: vertical;
375
- min-height: 60px;
376
- }
377
-
378
- .form-actions {
379
- display: flex;
380
- gap: 8px;
381
- margin-top: 16px;
382
- }
383
-
384
- /* Vault table */
385
- .vault-table {
386
- width: 100%;
387
- border-collapse: collapse;
388
- margin-top: 16px;
389
- }
390
-
391
- .vault-table th,
392
- .vault-table td {
393
- text-align: left;
394
- padding: 10px 12px;
395
- font-size: 0.875rem;
396
- border-bottom: 1px solid var(--border);
397
- }
398
-
399
- .vault-table th {
400
- color: var(--text-faint);
401
- font-weight: 500;
402
- font-size: 0.75rem;
403
- text-transform: uppercase;
404
- letter-spacing: 0.05em;
405
- }
406
-
407
- .vault-table td {
408
- color: var(--text);
409
- }
410
-
411
- .vault-empty {
412
- color: var(--text-dim);
413
- font-size: 0.875rem;
414
- padding: 24px 0;
415
- text-align: center;
416
- }
417
-
418
- /* QR area */
419
- .qr-area {
420
- background: white;
421
- border-radius: 8px;
422
- padding: 24px;
423
- text-align: center;
424
- margin: 16px 0;
425
- color: #333;
426
- min-height: 200px;
427
- display: flex;
428
- align-items: center;
429
- justify-content: center;
430
- }
431
-
432
- /* Toast */
433
- .toast {
434
- position: fixed;
435
- top: 24px;
436
- right: 24px;
437
- padding: 12px 20px;
438
- border-radius: 8px;
439
- font-size: 0.875rem;
440
- font-weight: 500;
441
- z-index: 100;
442
- transition: opacity 0.3s, transform 0.3s;
443
- }
444
-
445
- .toast.success {
446
- background: color-mix(in srgb, var(--success) 15%, var(--surface));
447
- color: var(--success);
448
- border: 1px solid color-mix(in srgb, var(--success) 30%, transparent);
449
- }
450
-
451
- .toast.error {
452
- background: color-mix(in srgb, var(--error) 15%, var(--surface));
453
- color: var(--error);
454
- border: 1px solid color-mix(in srgb, var(--error) 30%, transparent);
455
- }
456
-
457
- .hidden {
458
- display: none;
459
- }
460
-
461
- /* Theme toggle */
462
- .theme-toggle {
463
- background: var(--surface-raised);
464
- border: 1px solid var(--border-hover);
465
- border-radius: var(--radius-sm);
466
- padding: 6px 10px;
467
- cursor: pointer;
468
- color: var(--text-secondary);
469
- display: flex;
470
- align-items: center;
471
- gap: 6px;
472
- font-size: 13px;
473
- font-family: inherit;
474
- transition: background 0.15s, border-color 0.15s, color 0.15s;
475
- }
476
-
477
- .theme-toggle:hover {
478
- background: var(--accent-soft);
479
- border-color: var(--accent);
480
- color: var(--text);
481
- }
482
-
483
- .theme-toggle svg {
484
- width: 16px;
485
- height: 16px;
486
- }
487
-
488
- footer {
489
- text-align: center;
490
- margin-top: 48px;
491
- color: var(--text-dim);
492
- font-size: 0.8rem;
493
- }