agentgui 1.0.938 → 1.0.939
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/package.json
CHANGED
package/site/app/index.html
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<title>agentgui</title>
|
|
7
7
|
<meta name="description" content="agentgui — multi-agent client with same-origin server, in-process ccsniff history, and ACP chat.">
|
|
8
|
-
<link rel="stylesheet" href="
|
|
8
|
+
<link rel="stylesheet" href="vendor/anentrypoint-design/247420.css">
|
|
9
9
|
<script type="importmap">
|
|
10
|
-
{ "imports": { "anentrypoint-design": "
|
|
10
|
+
{ "imports": { "anentrypoint-design": "./vendor/anentrypoint-design/247420.js" } }
|
|
11
11
|
</script>
|
|
12
12
|
<style>
|
|
13
13
|
:root {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
color: var(--fg, var(--agentgui-fg));
|
|
24
24
|
font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif);
|
|
25
25
|
}
|
|
26
|
-
#app {
|
|
27
|
-
#app > * {
|
|
26
|
+
#app { height: 100vh; height: 100dvh; }
|
|
27
|
+
#app > * { height: 100%; }
|
|
28
28
|
|
|
29
29
|
/* skip link for keyboard/AT users */
|
|
30
30
|
.skip-link {
|
|
@@ -90,6 +90,65 @@
|
|
|
90
90
|
|
|
91
91
|
.field-error { color: var(--warn, var(--agentgui-warn)); }
|
|
92
92
|
|
|
93
|
+
/* chat control cluster in the crumb bar: keep model picker, +new, status
|
|
94
|
+
on one tidy baseline-aligned row instead of wrapping under the nav. */
|
|
95
|
+
.chat-controls { display: flex; align-items: center; gap: .6em; flex-wrap: nowrap; }
|
|
96
|
+
.chat-controls > * { flex: 0 0 auto; }
|
|
97
|
+
.chat-controls select,
|
|
98
|
+
.chat-controls .select,
|
|
99
|
+
.chat-controls [role="combobox"] { min-width: 150px; max-width: 220px; }
|
|
100
|
+
.chat-controls .status-dot { white-space: nowrap; }
|
|
101
|
+
|
|
102
|
+
/* Tame the design-system hero-sized PageHeader h1 to a sensible page title.
|
|
103
|
+
The DS default (--fs-h1, cqi-scaled to ~64-80px) overpowers app content. */
|
|
104
|
+
.agentgui-main .ds-section > h1 {
|
|
105
|
+
font-size: clamp(22px, 2.2vw, 30px);
|
|
106
|
+
line-height: 1.15;
|
|
107
|
+
margin-bottom: .35em;
|
|
108
|
+
}
|
|
109
|
+
.agentgui-main .ds-section { margin: 0 0 var(--space-4, 16px); }
|
|
110
|
+
|
|
111
|
+
/* TextField: stack label above the input so the label can't overlap it. */
|
|
112
|
+
.agentgui-main .ds-field {
|
|
113
|
+
display: flex; flex-direction: column; gap: .35em; align-items: stretch;
|
|
114
|
+
}
|
|
115
|
+
.agentgui-main .ds-field-label { font-size: .8rem; color: var(--fg-2, #ccc); }
|
|
116
|
+
.agentgui-main .ds-field input,
|
|
117
|
+
.agentgui-main .ds-field textarea { width: 100%; }
|
|
118
|
+
|
|
119
|
+
/* readable backend health summary (replaces raw JSON dump) */
|
|
120
|
+
.health-summary { display: flex; flex-wrap: wrap; gap: .4em; margin: .6em 0; }
|
|
121
|
+
.health-chip {
|
|
122
|
+
font-family: var(--ff-mono, ui-monospace, monospace);
|
|
123
|
+
font-size: .8rem; padding: .15em .55em; border-radius: 6px;
|
|
124
|
+
background: color-mix(in srgb, var(--fg, var(--agentgui-fg)) 8%, transparent);
|
|
125
|
+
color: var(--fg-2, var(--agentgui-fg));
|
|
126
|
+
border: 1px solid color-mix(in srgb, var(--fg, var(--agentgui-fg)) 12%, transparent);
|
|
127
|
+
}
|
|
128
|
+
.health-summary.health-ok .health-chip:first-child {
|
|
129
|
+
color: var(--accent, var(--agentgui-accent));
|
|
130
|
+
border-color: color-mix(in srgb, var(--accent, var(--agentgui-accent)) 40%, transparent);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* search input: match the dark theme instead of a bare white box */
|
|
134
|
+
.app input[type="search"],
|
|
135
|
+
.app .search-input input,
|
|
136
|
+
.app input.search,
|
|
137
|
+
input[type="search"] {
|
|
138
|
+
background: color-mix(in srgb, var(--fg, var(--agentgui-fg)) 6%, transparent);
|
|
139
|
+
color: var(--fg, var(--agentgui-fg));
|
|
140
|
+
border: 1px solid color-mix(in srgb, var(--fg, var(--agentgui-fg)) 16%, transparent);
|
|
141
|
+
border-radius: 8px; padding: .5em .7em;
|
|
142
|
+
}
|
|
143
|
+
.app input[type="search"]::placeholder { color: var(--fg-3, #888); }
|
|
144
|
+
.app input[type="search"]:focus-visible {
|
|
145
|
+
outline: 2px solid var(--accent, var(--agentgui-accent)); outline-offset: 1px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* empty-state: keep it from wrapping awkwardly in the narrow sidebar */
|
|
149
|
+
.empty-state { white-space: normal; }
|
|
150
|
+
p.empty-state { text-align: left; padding: .6em 0; color: var(--fg-3, #888); }
|
|
151
|
+
|
|
93
152
|
/* generic interactive focus ring */
|
|
94
153
|
button:focus-visible, [tabindex]:focus-visible, a:focus-visible {
|
|
95
154
|
outline: 2px solid var(--accent, var(--agentgui-accent)); outline-offset: 2px;
|
package/site/app/js/app.js
CHANGED
|
@@ -172,7 +172,7 @@ function view() {
|
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
const crumbRight = state.tab === 'chat'
|
|
175
|
-
? [
|
|
175
|
+
? [h('div', { key: 'cc', class: 'chat-controls' },
|
|
176
176
|
Select({
|
|
177
177
|
key: 'modelsel',
|
|
178
178
|
value: state.selectedModel,
|
|
@@ -185,39 +185,32 @@ function view() {
|
|
|
185
185
|
? Btn({ key: 'stop', onClick: cancelChat, children: '◼ stop', title: 'Stop streaming' })
|
|
186
186
|
: Btn({ key: 'new', onClick: newChat, children: '+ new', title: 'Start new chat (clears history)' }),
|
|
187
187
|
dot,
|
|
188
|
-
]
|
|
188
|
+
)]
|
|
189
189
|
: [dot];
|
|
190
190
|
|
|
191
|
+
// Topbar already shows "agentgui / <tab>"; the crumb is reserved for contextual
|
|
192
|
+
// controls (model picker, new/stop, live status) so it doesn't duplicate the path.
|
|
191
193
|
const crumb = Crumb({
|
|
192
|
-
trail: [
|
|
193
|
-
leaf:
|
|
194
|
+
trail: [],
|
|
195
|
+
leaf: '',
|
|
194
196
|
right: crumbRight,
|
|
195
197
|
});
|
|
196
198
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
group: 'navigate',
|
|
201
|
-
items: [
|
|
202
|
-
{ glyph: '▣', label: 'chat', key: 'chat', active: state.tab === 'chat',
|
|
203
|
-
onClick: (e) => { e.preventDefault(); navTo('chat'); } },
|
|
204
|
-
{ glyph: '§', label: 'history', key: 'history', active: state.tab === 'history',
|
|
205
|
-
onClick: (e) => { e.preventDefault(); navTo('history'); } },
|
|
206
|
-
{ glyph: '⌘', label: 'settings', key: 'settings', active: state.tab === 'settings',
|
|
207
|
-
onClick: (e) => { e.preventDefault(); navTo('settings'); } },
|
|
208
|
-
],
|
|
209
|
-
},
|
|
210
|
-
],
|
|
211
|
-
});
|
|
212
|
-
const side = state.tab === 'history' ? historySide() : navSide;
|
|
199
|
+
// Sidebar is contextual: history shows the session list; chat/settings have no
|
|
200
|
+
// sidebar (the topbar already provides primary nav) so main content gets full width.
|
|
201
|
+
const side = state.tab === 'history' ? historySide() : null;
|
|
213
202
|
|
|
214
203
|
const status = Status({
|
|
215
|
-
left: [state.backend, ok ? '● live' : '○ offline'],
|
|
204
|
+
left: [state.backend || 'same-origin', ok ? '● live' : '○ offline'],
|
|
216
205
|
right: [state.selectedModel ? '⌘ ' + state.selectedModel : '○ no model'],
|
|
217
206
|
});
|
|
218
207
|
|
|
219
|
-
const
|
|
220
|
-
|
|
208
|
+
const mainStyle = state.tab === 'chat'
|
|
209
|
+
? 'min-height:0;height:100%;display:flex;flex-direction:column'
|
|
210
|
+
: 'min-height:0;height:100%;overflow:auto';
|
|
211
|
+
const main = h('div', { id: 'agentgui-main', role: 'main', 'data-chat-scroll': '', class: 'agentgui-main agentgui-main-' + state.tab, style: mainStyle }, mainContent());
|
|
212
|
+
// settings reads better centered in a measure; chat + history use full width.
|
|
213
|
+
return AppShell({ topbar, crumb, side, main, status, narrow: state.tab === 'settings' });
|
|
221
214
|
}
|
|
222
215
|
|
|
223
216
|
function mainContent() {
|
|
@@ -262,7 +255,7 @@ function chatMain() {
|
|
|
262
255
|
resumeBanner,
|
|
263
256
|
Chat({
|
|
264
257
|
title: (state.selectedModel || 'agent') + (state.chat.resumeSid ? ' · resume' : ''),
|
|
265
|
-
sub: state.chat.busy ? 'streaming…' :
|
|
258
|
+
sub: state.chat.busy ? 'streaming…' : undefined,
|
|
266
259
|
messages: msgs,
|
|
267
260
|
composer,
|
|
268
261
|
}),
|
|
@@ -436,18 +429,6 @@ function historySide() {
|
|
|
436
429
|
const projects = uniqueProjects();
|
|
437
430
|
|
|
438
431
|
return [
|
|
439
|
-
Side({
|
|
440
|
-
sections: [
|
|
441
|
-
{
|
|
442
|
-
group: 'navigate',
|
|
443
|
-
items: [
|
|
444
|
-
{ glyph: '▣', label: 'chat', key: 'chat', onClick: (e) => { e.preventDefault(); navTo('chat'); } },
|
|
445
|
-
{ glyph: '§', label: 'history', key: 'history', active: true },
|
|
446
|
-
{ glyph: '⌘', label: 'settings', key: 'settings', onClick: (e) => { e.preventDefault(); navTo('settings'); } },
|
|
447
|
-
],
|
|
448
|
-
},
|
|
449
|
-
],
|
|
450
|
-
}),
|
|
451
432
|
Panel({
|
|
452
433
|
title: searching
|
|
453
434
|
? 'matches · ' + (state.searchHits.results?.length || 0)
|
|
@@ -505,6 +486,20 @@ function saveBackend() {
|
|
|
505
486
|
init();
|
|
506
487
|
}
|
|
507
488
|
|
|
489
|
+
function healthSummary() {
|
|
490
|
+
const hh = state.health || {};
|
|
491
|
+
const ok = hh.status === 'ok';
|
|
492
|
+
const dot = ok ? '●' : (hh.status === 'unknown' ? '◌' : '○');
|
|
493
|
+
const bits = [];
|
|
494
|
+
bits.push(dot + ' ' + (hh.status || 'unknown'));
|
|
495
|
+
if (hh.version) bits.push('v' + hh.version);
|
|
496
|
+
if (typeof hh.agents === 'number') bits.push(hh.agents + ' agents');
|
|
497
|
+
if (typeof hh.activeExecutions === 'number') bits.push(hh.activeExecutions + ' active');
|
|
498
|
+
if (hh.db) bits.push('db ' + (hh.db.ok ? 'ok' : 'down'));
|
|
499
|
+
return h('div', { key: 'hp', class: 'health-summary' + (ok ? ' health-ok' : '') },
|
|
500
|
+
...bits.map((b, i) => h('span', { key: 'hb' + i, class: 'health-chip' }, b)));
|
|
501
|
+
}
|
|
502
|
+
|
|
508
503
|
function settingsMain() {
|
|
509
504
|
const ok = state.health.status === 'ok';
|
|
510
505
|
const isValid = isValidUrl(state.backendDraft);
|
|
@@ -530,7 +525,7 @@ function settingsMain() {
|
|
|
530
525
|
onInput: (v) => { state.backendDraft = v; render(); },
|
|
531
526
|
}),
|
|
532
527
|
!isValid ? h('p', { key: 'err', id: 'backend-url-error', class: 'lede field-error', role: 'alert' }, '⚠ Invalid URL format') : null,
|
|
533
|
-
|
|
528
|
+
healthSummary(),
|
|
534
529
|
Btn({
|
|
535
530
|
key: 'savebtn',
|
|
536
531
|
type: 'submit',
|