@oddessentials/agent-guild 0.2.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.
- package/README.md +20 -7
- package/config/providers.default.json +10 -0
- package/package.json +1 -1
- package/src/manager/config.mjs +7 -1
- package/src/manager/main.mjs +20 -7
- package/src/manager/news.mjs +470 -0
- package/src/manager/providers.mjs +89 -5
- package/src/manager/self-update.mjs +205 -0
- package/src/manager/server.mjs +15 -1
- package/src/manager/session-manager.mjs +58 -7
- package/src/manager/session.mjs +4 -1
- package/src/manager/usage.mjs +106 -25
- package/web/app.js +489 -12
- package/web/art/art.css +28 -6
- package/web/index.html +31 -0
- package/web/styles.css +87 -19
- package/web/theme.js +10 -0
package/web/art/art.css
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
.level-badge { display: none; }
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
/* The guild look is the dark theme. The rules below nest under the theme
|
|
4
|
+
attribute that theme.js sets on <html>, so they apply whether the user
|
|
5
|
+
chose dark or the system did. :where() keeps their specificity as it was
|
|
6
|
+
inside the media query, so styles.css still loses to them only on order. */
|
|
7
|
+
:where(:root[data-theme="dark"]) {
|
|
8
|
+
--gold: #e8c47c;
|
|
9
|
+
--gold-dim: #8a6d3b;
|
|
10
|
+
--card-bg: rgba(18, 20, 26, 0.9);
|
|
9
11
|
|
|
10
12
|
.provider, .session-card {
|
|
11
13
|
--pc: #a67cf6;
|
|
@@ -153,6 +155,26 @@
|
|
|
153
155
|
.badge { background: rgba(0, 0, 0, 0.45); border-color: #4a3d25; }
|
|
154
156
|
.model-pill:hover { border-color: var(--gold-dim); }
|
|
155
157
|
|
|
158
|
+
.news-latest {
|
|
159
|
+
border-radius: 6px; border-color: #4a3d25; background: var(--card-bg);
|
|
160
|
+
box-shadow: inset 0 0 0 1px rgba(232, 196, 124, 0.06), 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
161
|
+
}
|
|
162
|
+
.news-row + .news-row, .news-bar, .news-filters, .news-item, .news-status { border-color: #2a2418; }
|
|
163
|
+
.news-link { color: #f3ead8; }
|
|
164
|
+
a.news-link:visited { color: var(--muted); }
|
|
165
|
+
.news-panel {
|
|
166
|
+
background: #12141a; border-left-color: #4a3d25;
|
|
167
|
+
box-shadow: inset 1px 0 0 rgba(232, 196, 124, 0.08), -24px 0 60px rgba(0, 0, 0, 0.6);
|
|
168
|
+
}
|
|
169
|
+
.news-panel::backdrop { background: rgba(5, 6, 9, 0.72); }
|
|
170
|
+
.news-bar { padding: 16px 18px 12px; }
|
|
171
|
+
.news-filters, .news-status { padding-left: 18px; padding-right: 18px; }
|
|
172
|
+
.news-body { padding: 0 18px 14px; }
|
|
173
|
+
.news-day { background: #12141a; color: #c9ab72; }
|
|
174
|
+
.news-filter { border-color: #4a3d25; background: rgba(0, 0, 0, 0.35); }
|
|
175
|
+
.news-filter:hover { border-color: var(--gold-dim); }
|
|
176
|
+
.news-filter[aria-pressed="true"] { border-color: #b8955a; color: #fff; background: linear-gradient(#8e8ef6, #6262d6); }
|
|
177
|
+
|
|
156
178
|
.session-card { padding-left: 152px; min-height: 196px; }
|
|
157
179
|
.session-card::before {
|
|
158
180
|
inset: 0 auto 0 0; width: 168px; background-size: 168px auto;
|
package/web/index.html
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>Agent Guild</title>
|
|
7
7
|
<meta name="color-scheme" content="light dark">
|
|
8
|
+
<script src="/theme.js"></script>
|
|
8
9
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%235B5BD6'/%3E%3Cpath d='M9 22l7-12 7 12' stroke='white' stroke-width='3' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E">
|
|
9
10
|
<link rel="stylesheet" href="/vendor/xterm/xterm.css">
|
|
10
11
|
<link rel="stylesheet" href="/styles.css">
|
|
@@ -20,6 +21,9 @@
|
|
|
20
21
|
<div id="connection" class="connection" role="status" aria-live="polite">
|
|
21
22
|
<span class="dot"></span><span class="label">Connecting…</span>
|
|
22
23
|
</div>
|
|
24
|
+
<span id="upgrade-note" class="upgrade-note" hidden></span>
|
|
25
|
+
<button id="upgrade" class="btn upgrade" type="button" hidden></button>
|
|
26
|
+
<button id="theme-toggle" class="btn theme-toggle" type="button"></button>
|
|
23
27
|
<button id="stop-manager" class="btn danger stop-manager" type="button" hidden title="Stop the session manager. This ends every session.">Stop manager</button>
|
|
24
28
|
</div>
|
|
25
29
|
</header>
|
|
@@ -43,6 +47,15 @@
|
|
|
43
47
|
<div id="sessions" class="session-grid" role="list"></div>
|
|
44
48
|
<p id="empty" class="empty">No sessions yet. Pick a provider above to start one. Sessions keep running when you close this page.</p>
|
|
45
49
|
</section>
|
|
50
|
+
|
|
51
|
+
<section class="news" aria-labelledby="news-heading">
|
|
52
|
+
<div class="section-head">
|
|
53
|
+
<h2 id="news-heading">Latest news <span id="news-count" class="count"></span></h2>
|
|
54
|
+
<button id="news-all" class="btn" type="button" aria-haspopup="dialog">All news</button>
|
|
55
|
+
</div>
|
|
56
|
+
<ol id="news-latest" class="news-latest" hidden></ol>
|
|
57
|
+
<p id="news-note" class="empty">Loading news…</p>
|
|
58
|
+
</section>
|
|
46
59
|
</main>
|
|
47
60
|
|
|
48
61
|
<section id="auth" class="auth" hidden>
|
|
@@ -101,6 +114,23 @@
|
|
|
101
114
|
<p id="models-source" class="models-source"></p>
|
|
102
115
|
</dialog>
|
|
103
116
|
|
|
117
|
+
<dialog id="news" class="news-panel" aria-labelledby="news-title">
|
|
118
|
+
<div class="news-bar">
|
|
119
|
+
<div class="news-heading">
|
|
120
|
+
<h2 id="news-title">News</h2>
|
|
121
|
+
<p id="news-sub" class="sub"></p>
|
|
122
|
+
</div>
|
|
123
|
+
<button id="news-close" class="btn" type="button">Close</button>
|
|
124
|
+
</div>
|
|
125
|
+
<div id="news-filters" class="news-filters" role="group" aria-label="Show"></div>
|
|
126
|
+
<div class="news-body">
|
|
127
|
+
<button id="news-fresh" class="btn news-fresh" type="button" hidden></button>
|
|
128
|
+
<div id="news-list"></div>
|
|
129
|
+
<p id="news-empty" class="news-empty" hidden></p>
|
|
130
|
+
</div>
|
|
131
|
+
<p id="news-status" class="news-status" hidden></p>
|
|
132
|
+
</dialog>
|
|
133
|
+
|
|
104
134
|
<div id="tip" class="tip" aria-hidden="true" hidden><strong id="tip-title"></strong><span id="tip-source"></span><p id="tip-text"></p></div>
|
|
105
135
|
|
|
106
136
|
<div id="toast" class="toast" role="alert" hidden></div>
|
|
@@ -113,6 +143,7 @@
|
|
|
113
143
|
<span class="tool"></span>
|
|
114
144
|
<span class="state"></span>
|
|
115
145
|
</span>
|
|
146
|
+
<div class="accounts" role="tablist" aria-label="Accounts" hidden></div>
|
|
116
147
|
<div class="usage"></div>
|
|
117
148
|
<div class="model-stats"></div>
|
|
118
149
|
<div class="provider-links">
|
package/web/styles.css
CHANGED
|
@@ -18,21 +18,20 @@
|
|
|
18
18
|
color-scheme: light;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
21
|
+
/* theme.js sets data-theme from the saved choice or the system setting before the first paint. */
|
|
22
|
+
:root[data-theme="dark"] {
|
|
23
|
+
--bg: #0f1115;
|
|
24
|
+
--surface: #171a21;
|
|
25
|
+
--surface-2: #1e222b;
|
|
26
|
+
--border: #2a303b;
|
|
27
|
+
--text: #e6e9ef;
|
|
28
|
+
--muted: #9aa4b2;
|
|
29
|
+
--accent: #7c7cf0;
|
|
30
|
+
--danger: #ef6b66;
|
|
31
|
+
--ok: #4cc38a;
|
|
32
|
+
--warn: #e0a84a;
|
|
33
|
+
--shadow: none;
|
|
34
|
+
color-scheme: dark;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
* { box-sizing: border-box; }
|
|
@@ -86,6 +85,16 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
86
85
|
.provider .state.update-available { color: var(--warn); }
|
|
87
86
|
.provider.unavailable .state { color: var(--muted); }
|
|
88
87
|
.provider .update { color: var(--warn); border-color: var(--warn); }
|
|
88
|
+
.provider .accounts { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 6px; }
|
|
89
|
+
.account-chip {
|
|
90
|
+
font: inherit; font-size: 0.75rem; font-weight: 600; padding: 2px 10px; border-radius: 999px; cursor: pointer;
|
|
91
|
+
border: 1px solid var(--border); background: var(--surface-2); color: var(--muted); max-width: 100%;
|
|
92
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
93
|
+
}
|
|
94
|
+
.account-chip:hover { border-color: var(--muted); }
|
|
95
|
+
.account-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
96
|
+
.account-chip[aria-selected="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
|
|
97
|
+
.account-chip.unsigned { border-style: dashed; }
|
|
89
98
|
.provider .usage { grid-column: 1 / -1; display: grid; gap: 4px; }
|
|
90
99
|
.provider .usage:empty { display: none; }
|
|
91
100
|
.meter { display: grid; grid-template-columns: 5.5em 1fr auto; align-items: center; gap: 8px; font-size: 0.75rem; color: var(--muted); }
|
|
@@ -152,7 +161,7 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
152
161
|
.tier-b { --tier: #3b82f6; --tier-ink: #1d4ed8; }
|
|
153
162
|
.tier-c { --tier: #22a35a; --tier-ink: #166534; }
|
|
154
163
|
.tier-d { --tier: #94a3b8; --tier-ink: #475569; }
|
|
155
|
-
|
|
164
|
+
:where(:root[data-theme="dark"]) {
|
|
156
165
|
.tier-s { --tier: #e0b45c; --tier-ink: #f6dea6; }
|
|
157
166
|
.tier-a { --tier: #a78bfa; --tier-ink: #ddd3ff; }
|
|
158
167
|
.tier-b { --tier: #60a5fa; --tier-ink: #cfe3ff; }
|
|
@@ -240,7 +249,9 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
240
249
|
.btn.danger { color: var(--danger); }
|
|
241
250
|
.btn.danger:hover { border-color: var(--danger); }
|
|
242
251
|
.btn:disabled { opacity: 0.6; cursor: progress; }
|
|
243
|
-
.stop-manager { white-space: nowrap; }
|
|
252
|
+
.stop-manager, .theme-toggle, .upgrade { white-space: nowrap; }
|
|
253
|
+
.btn.upgrade { color: var(--warn); border-color: var(--warn); }
|
|
254
|
+
.upgrade-note { font-size: 0.85rem; color: var(--warn); }
|
|
244
255
|
|
|
245
256
|
.empty { color: var(--muted); margin: 8px 0 0; }
|
|
246
257
|
|
|
@@ -308,7 +319,7 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
308
319
|
.badge.new { --badge: var(--ok); color: color-mix(in srgb, var(--badge) 72%, #000); }
|
|
309
320
|
.badge.expires { --badge: var(--warn); color: color-mix(in srgb, var(--badge) 62%, #000); }
|
|
310
321
|
.badge.in-use, .badge.new, .badge.expires { border-color: color-mix(in srgb, var(--badge) 45%, transparent); }
|
|
311
|
-
|
|
322
|
+
:where(:root[data-theme="dark"]) {
|
|
312
323
|
.badge.in-use, .badge.new, .badge.expires { color: var(--badge); }
|
|
313
324
|
}
|
|
314
325
|
.model-detail {
|
|
@@ -330,6 +341,59 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
330
341
|
.models-note { margin: 14px 0 0; color: var(--muted); }
|
|
331
342
|
.models-source { margin: 0; padding: 10px 14px; border-top: 1px solid var(--border); color: var(--muted); font-size: 0.75rem; line-height: 1.45; }
|
|
332
343
|
|
|
344
|
+
.news-latest {
|
|
345
|
+
list-style: none; margin: 0; padding: 0;
|
|
346
|
+
border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow);
|
|
347
|
+
}
|
|
348
|
+
.news-row { display: flex; align-items: baseline; gap: 4px 10px; min-width: 0; padding: 9px 14px; }
|
|
349
|
+
.news-row + .news-row { border-top: 1px solid var(--border); }
|
|
350
|
+
.news-row .news-link { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
351
|
+
.news-row .badge, .news-row .news-meta { flex: none; }
|
|
352
|
+
.news-link { color: var(--text); font-weight: 600; text-decoration: none; }
|
|
353
|
+
a.news-link:hover, .news-discussion:hover { text-decoration: underline; }
|
|
354
|
+
a.news-link:visited { color: var(--muted); }
|
|
355
|
+
.news-link:focus-visible, .news-discussion:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
|
|
356
|
+
.news-meta { color: var(--muted); font-size: 0.78rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
357
|
+
|
|
358
|
+
.news-panel {
|
|
359
|
+
width: min(460px, 100vw); max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0 0 0 auto; padding: 0;
|
|
360
|
+
border: 0; border-left: 1px solid var(--border); background: var(--surface); color: var(--text);
|
|
361
|
+
box-shadow: -16px 0 48px rgba(0, 0, 0, 0.25);
|
|
362
|
+
}
|
|
363
|
+
.news-panel[open] { display: flex; flex-direction: column; animation: news-in 0.18s ease-out; }
|
|
364
|
+
.news-panel::backdrop { background: rgba(15, 17, 21, 0.4); }
|
|
365
|
+
.news-bar { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--border); }
|
|
366
|
+
.news-heading { flex: 1; min-width: 0; }
|
|
367
|
+
.news-heading .sub { margin: 2px 0 0; color: var(--muted); font-size: 0.78rem; }
|
|
368
|
+
.news-filters { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 14px; border-bottom: 1px solid var(--border); }
|
|
369
|
+
.news-filter {
|
|
370
|
+
font: inherit; font-size: 0.75rem; font-weight: 600; padding: 3px 11px; border-radius: 999px; cursor: pointer;
|
|
371
|
+
border: 1px solid var(--border); background: var(--surface-2); color: var(--muted);
|
|
372
|
+
}
|
|
373
|
+
.news-filter:hover { border-color: var(--muted); }
|
|
374
|
+
.news-filter:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
375
|
+
.news-filter[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
|
|
376
|
+
.news-body { flex: 1; min-height: 0; overflow: auto; padding: 0 14px 14px; }
|
|
377
|
+
.news-fresh { width: 100%; margin-top: 12px; }
|
|
378
|
+
.news-day {
|
|
379
|
+
position: sticky; top: 0; z-index: 1; margin: 0; padding: 12px 0 6px; background: var(--surface);
|
|
380
|
+
color: var(--muted); font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
|
|
381
|
+
}
|
|
382
|
+
.news-items { list-style: none; margin: 0; padding: 0; }
|
|
383
|
+
.news-item { padding: 10px 0; border-top: 1px solid var(--border); }
|
|
384
|
+
.news-head { display: flex; align-items: baseline; gap: 6px; }
|
|
385
|
+
.news-head .news-link { overflow-wrap: anywhere; }
|
|
386
|
+
.news-head .badge { flex: none; margin-left: auto; }
|
|
387
|
+
.news-item .news-meta { display: block; margin-top: 3px; }
|
|
388
|
+
.news-summary {
|
|
389
|
+
margin: 4px 0 0; color: var(--muted); font-size: 0.82rem; line-height: 1.45; overflow-wrap: anywhere;
|
|
390
|
+
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
|
|
391
|
+
}
|
|
392
|
+
.news-discussion { color: inherit; text-decoration: none; }
|
|
393
|
+
.news-empty { margin: 14px 0 0; color: var(--muted); }
|
|
394
|
+
.news-status { margin: 0; padding: 10px 14px; border-top: 1px solid var(--border); color: var(--muted); font-size: 0.75rem; line-height: 1.45; }
|
|
395
|
+
.news-status span { display: block; }
|
|
396
|
+
|
|
333
397
|
.toast {
|
|
334
398
|
position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%); z-index: 20;
|
|
335
399
|
max-width: min(640px, calc(100vw - 32px)); padding: 10px 14px; border-radius: 8px;
|
|
@@ -339,9 +403,10 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
339
403
|
@keyframes pulse { 50% { opacity: 0.35; } }
|
|
340
404
|
@keyframes ring { 0% { transform: scale(0.85); opacity: 0.8; } 100% { transform: scale(1.3); opacity: 0; } }
|
|
341
405
|
@keyframes stat-fill { from { transform: scaleX(0); } }
|
|
406
|
+
@keyframes news-in { from { transform: translateX(24px); opacity: 0; } }
|
|
342
407
|
|
|
343
408
|
@media (prefers-reduced-motion: reduce) {
|
|
344
|
-
.status-pill.active::before, .agent.working::after, .model-detail .stat-fill { animation: none; }
|
|
409
|
+
.status-pill.active::before, .agent.working::after, .model-detail .stat-fill, .news-panel[open] { animation: none; }
|
|
345
410
|
.model-name::before { transition: none; }
|
|
346
411
|
}
|
|
347
412
|
|
|
@@ -359,4 +424,7 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; display: grid
|
|
|
359
424
|
.model-detail .stat { padding-bottom: 6px; }
|
|
360
425
|
.model-detail .stat-reading { row-gap: 1px; }
|
|
361
426
|
.model-detail .stat-note { grid-column: 1 / -1; }
|
|
427
|
+
.news-row { flex-wrap: wrap; }
|
|
428
|
+
.news-row .news-link { flex-basis: 100%; white-space: normal; }
|
|
429
|
+
.news-panel { border-left: 0; }
|
|
362
430
|
}
|
package/web/theme.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Applies the chosen theme before the first paint, so the page never flashes
|
|
2
|
+
// the other one. Loaded in <head> as a plain script; app.js owns the toggle.
|
|
3
|
+
(function () {
|
|
4
|
+
var theme = null;
|
|
5
|
+
try { theme = localStorage.getItem('agentGuild.theme'); } catch (e) { /* storage unavailable */ }
|
|
6
|
+
if (theme !== 'light' && theme !== 'dark') {
|
|
7
|
+
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
8
|
+
}
|
|
9
|
+
document.documentElement.dataset.theme = theme;
|
|
10
|
+
})();
|