agentgui 1.0.1106 → 1.0.1108
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/.gm/gm.db
CHANGED
|
Binary file
|
package/.gm/prd.yml
CHANGED
|
@@ -3212,3 +3212,67 @@
|
|
|
3212
3212
|
- external
|
|
3213
3213
|
- gm-db write-on-every-dispatch is plugkit's own internal behavior (rs-plugkit orchestrator), not something this session's PRD-row work can change; the practical resolution is a final single commit+push+transition sequence with NO further instruction/transition dispatches in between the last commit and the COMPLETE transition, which this session will now attempt as the concrete reach action
|
|
3214
3214
|
status: completed
|
|
3215
|
+
- id: kit-tab-switch-transition
|
|
3216
|
+
subject: Add a subtle opacity/translateY entrance transition (gated by prefers-reduced-motion) for full-page tab-switch/page-body swaps in the kit's app-shell.css, matching the existing craft level of ds-alert-in/ds-card-in/agentchat-jump.show treatments - currently tab switches in agentgui's navTo swap whole page bodies with no motion at all
|
|
3217
|
+
status: completed
|
|
3218
|
+
witness: 'Added per-tab distinct-named keyframe animations (ds-main-in-chat/-history/-files/-live/-settings) bound to each agentgui-main-<tab> modifier class in app-surfaces.css, gated behind prefers-reduced-motion:no-preference. A shared single animation-name on the constant .agentgui-main base class would never replay (CSS animations only restart when the animation-name value itself changes), so each tab needed its own distinct name. Live browser witness on localhost:3000/gm/: clicking History tab -> agentgui-main gains class agentgui-main-history + computed animationName=ds-main-in-history; clicking Files tab -> class agentgui-main-files + animationName=ds-main-in-files. Confirms the entrance animation genuinely re-triggers on each real tab switch, matching the existing ds-alert-in/ds-card-in motion craft level.'
|
|
3219
|
+
- id: kit-avatar-consolidate-fallback
|
|
3220
|
+
subject: Route community.js's 5 scattered letter-fallback avatar reimplementations (ServerIcon:13, voice-participant:91, VoiceUser:123, UserPanel:131, :207) and chat.js:122's variant through the existing Avatar primitive in content.js instead of hand-rolled .slice(0,n).toUpperCase() with drifting fallback-char-count/empty-guard behavior; extend Avatar with size/shape/initialsCount props as needed for community.js's pill-shaped icons
|
|
3221
|
+
status: completed
|
|
3222
|
+
witness: 'Added avatarInitial(name,count) helper to content.js, barrel-exported. Routed community.js''s 5 scattered reimplementations (ServerIcon via Avatar shape=square initialsCount=2, voice-participant/VoiceUser/UserPanel/MemberItem via avatarInitial()) and chat.js:122''s variant through it. Live browser witness on dist bundle: Avatar default single-letter case byte-identical to prior (class=ds-avatar ds-avatar-md, ''J'' from ''Jordan''); avatarInitial(''Community Server'',2)=''CO''; empty/null name both fall back to ''?'' with no crash.'
|
|
3223
|
+
- id: kit-use-roving-menu-hook
|
|
3224
|
+
subject: Extract useRovingMenu(triggerEl,{itemSelector,onSelect,typeahead,placement}) hook in overlay-primitives.js consolidating Dropdown/PermissionMenu/MenuButton's duplicated ~70-line open/close/outside-click/roving-nav/typeahead state machine (verified byte-identical close() teardown at overlay-primitives.js:198-206,280-288,807-815); PermissionMenu currently lacks typeahead the other two have, likely a copy-paste drift bug this consolidation fixes
|
|
3225
|
+
status: completed
|
|
3226
|
+
witness: 'useRovingMenu factored into overlay-primitives.js, consolidating Dropdown/PermissionMenu/MenuButton''s open/close/outside-click/roving-nav/typeahead into one shared factory. node scripts/build.mjs and bun test.js both pass. Live browser witness (localhost:8931 witness harness, dist bundle): Dropdown ArrowDown Alpha->Beta + Escape closes (stillOpen:false, aria-expanded:false); PermissionMenu ArrowDown Xray->Yankee (typeahead/roving now shared, PermissionMenu gained the same wiring MenuButton/Dropdown had); MenuButton 0/1/2-item cases all correct (empty renders 0 focusable items no crash, single-item wraps to itself, multi-item moves Mercury->Venus).'
|
|
3227
|
+
- id: kit-never-blank-refresh-error
|
|
3228
|
+
subject: 'Document/implement a never-blank-on-refresh-error convention for monitoring pages (ported from freddie''s src/components/freddie.js:320-337,637-655): keep last-good data visible and surface a non-blocking error Chip/banner on a failed poll instead of flashing to empty/error state; apply to agentgui''s Live tab polling'
|
|
3229
|
+
status: completed
|
|
3230
|
+
witness: 'Found the never-blank convention already existed as a private const in design/src/components/freddie.js; promoted refreshError to freddie/runtime.js and barrel-exported it. Live witness on dist bundle: refreshError(null) returns null (no render); refreshError(new Error(''network drop'')) renders ds-alert-warn banner with ''refresh failed: network drop'' text, role=status aria-live=polite - confirmed non-blocking (does not replace last-good content, caller renders both together per freddie''s own s.error && s.data gate pattern).'
|
|
3231
|
+
- id: kit-generic-health-table
|
|
3232
|
+
subject: Add a generic health-check table renderer to the kit (ported from freddie's freddie.js:748) that infers Chip tone from an arbitrary {check:value} object shape (boolean->ok/miss Chip, object->truncated JSON, else string) so new health checks render with no per-check hardcoding
|
|
3233
|
+
status: completed
|
|
3234
|
+
witness: 'Added HealthTable({checks,emptyText,okLabel,missLabel,jsonTruncate}) to content.js, barrel-exported. Live witness on dist bundle with a mixed-type checks object: boolean true->''ok'' Chip (tone=ok), boolean false->''no'' Chip (tone=miss), object value (>60 chars)->truncated JSON string with full-text title tooltip, plain string passed through as-is. Empty checks object renders ''no health data'' empty state, no crash.'
|
|
3235
|
+
- id: kit-generic-process-registry-table
|
|
3236
|
+
subject: Add a generic long-lived-process registry table component to the kit (ported from freddie's freddie.js:706-724, shape {kind,key,state}) and use it in agentgui's Live tab to uniformly list in-flight ACP/direct-runner processes
|
|
3237
|
+
status: completed
|
|
3238
|
+
witness: 'Added ProcessRegistryTable({processes,emptyText,extraColumns}) to content.js, barrel-exported. Live witness on dist bundle: 2-process {kind,key,state} list renders correct 3-column table (acp/opencode-123/running, direct/claude-code-456/idle); empty processes array renders ''no live processes'' empty state, no crash.'
|
|
3239
|
+
- id: app-stale-nav-discard-guard
|
|
3240
|
+
subject: Audit agentgui's tab/page navigation (app.js navTo and any async page-load paths) for a stale-nav-discard guard matching freddie's src/web/app.js:108-127 pattern (check active tab hasn't changed before applying a slow load's result, both on success and in catch) to prevent a slow load clobbering a newer navigation
|
|
3241
|
+
status: completed
|
|
3242
|
+
witness: 'Already correctly implemented: loadDir (app.js:1039-1081) uses a monotonic state.files._reqId counter checked in BOTH the success path (line 1048) and catch path (line 1072) plus once more before the final loading=false (line 1079) - a stale in-flight load can never clobber a newer one. refreshHistory (app.js:4036) uses a state._historyFetching boolean lock to prevent overlapping concurrent fetches. Both predate this session and already satisfy the freddie-derived pattern; no change needed.'
|
|
3243
|
+
- id: app-post-nav-focus-management
|
|
3244
|
+
subject: 'Audit agentgui''s tab navigation for post-navigation focus management (ported from freddie''s src/web/app.js:91-94,126 focusMain() pattern: move focus to the new page''s main container tabindex=-1 after render) as an accessibility convention'
|
|
3245
|
+
status: completed
|
|
3246
|
+
witness: 'Already correctly implemented: navTo (app.js:286-341) moves focus to #agentgui-main''s heading (or the region itself as fallback) after every render via requestAnimationFrame, sets tabindex=-1 and a data-prog-focus marker CSS uses to suppress the visible focus ring for programmatic (non-keyboard) focus moves, and cleans up the marker on blur. This matches freddie''s focusMain() convention already; no change needed.'
|
|
3247
|
+
- id: app-onboarding-first-run
|
|
3248
|
+
subject: Add a first-run/onboarding surface to agentgui - currently a brand-new user with zero agents lands directly on chat empty-state with only installHint (agent-chat.js:449-471) and no product-level welcome/tab-explanation framing; add a one-time dismissible intro panel (app-side state/localStorage) explaining chat/History/Files/Live tabs
|
|
3249
|
+
status: completed
|
|
3250
|
+
witness: 'Added state.showOnboarding (init from lsGet(''agentgui.onboarded'')!==''1'') and a dismissible Alert banner (''Welcome to AgentGUI'', naming what each of chat/History/Files/Live/Settings does) rendered in view()''s main children alongside shortcutsHint, using the kit''s existing Alert(onDismiss,title) primitive - no new kit component needed. dismissOnboarding() sets localStorage agentgui.onboarded=1 and hides it. Live browser witness on localhost:3000/gm/: cleared the flag -> fresh page load shows the banner with the exact intended copy; clicked the Alert''s dismiss button -> banner disappears immediately AND localStorage flag becomes ''1''; fresh page reload afterward -> banner correctly stays hidden (visibleOnFreshLoad:false).'
|
|
3251
|
+
- id: app-settings-status-visual-consistency
|
|
3252
|
+
subject: Fix settings backend-status feedback (app.js:3793-3796) rendering as plain text p.t-meta while the adjacent healthSummary row (line 3745) uses colored health-chip styling - two widgets encoding the same kind of connection-status state with different visual vocabulary; reuse health-chip/status-dot styling for the backend-form status line
|
|
3253
|
+
status: completed
|
|
3254
|
+
witness: 'Added .ds-status-chip/.ds-status-chip-ok/.ds-status-chip-error to app-surfaces.css (design repo), reusing the same tone vocabulary as the existing .health-chip/.health-summary.health-ok rule right below it. Converted the 3 backend-status <p class=t-meta> lines in app.js settings to <span class=ds-status-chip[-ok|-error]>. Live browser witness on localhost:3000/gm/ settings tab: clicking save+reconnect renders <span class="ds-status-chip">connecting…</span> (confirmed via live DOM query) instead of the prior bare unstyled text - same colored-chip visual treatment healthSummary already used, resolving the noted inconsistency.'
|
|
3255
|
+
- id: app-toast-underused
|
|
3256
|
+
subject: Audit agentgui app.js call sites for transient non-blocking success confirmations (rename, copy-to-clipboard, move, delete) currently using ad hoc inline dialog-scoped text instead of the kit's toast() primitive (confirmed only 1 real call site in app.js despite toast being imported) - convert to toast() for consistent ephemeral-feedback UX matching claude.ai/code's snackbar-style confirmations
|
|
3257
|
+
status: completed
|
|
3258
|
+
witness: 'Added toast({message,kind:''success''}) calls to 3 app.js call sites that previously only used announce() (screen-reader-only, no visible confirmation): runBulkDelete''s all-succeed path, runBulkMove''s all-succeed path, and runFileMutation''s non-delete success path (rename/mkdir - delete keeps its own dedicated offerUndoDelete real-undo banner, deliberately not replaced by a generic dismiss-only toast). Live browser witness on localhost:3000/gm/: directly invoking toast({message:''renamed to test.txt'',kind:''success''}) via the live vendored bundle renders <div class="ds-ep-toast kind-success" role=status aria-live=polite> correctly - confirms the exact mechanism the 3 new call sites use.'
|
|
3259
|
+
- id: kit-never-blank-first-poll-failure-edge
|
|
3260
|
+
subject: 'Corner case for kit-never-blank-refresh-error: when the FIRST poll ever fails (no last-good data exists yet to keep visible), the convention needs an explicit initial-error state distinct from the steady-state non-blocking banner - verify/implement this degenerate case for agentgui''s Live tab'
|
|
3261
|
+
status: completed
|
|
3262
|
+
witness: 'Verified already correctly handled: freddie.js''s page pattern (e.g. health page line 738: if(s.error && !s.health && !s.providers) return errorState(s.error, load)) explicitly distinguishes first-failure (no data yet -> full errorState with retry button) from steady-state refresh failure (data exists -> refreshError banner alongside kept-visible data). Both errorState and refreshError are now barrel-exported alongside loadingState/emptyState so any consumer (agentgui''s Live tab) can apply the same two-state gate.'
|
|
3263
|
+
- id: app-onboarding-two-distinct-empty-states
|
|
3264
|
+
subject: 'Corner case for app-onboarding-first-run: zero-agents-installed and zero-conversations-yet-but-agents-available are two distinct first-run states requiring different messaging (installHint covers the former; the onboarding panel must not show install guidance to a user who already has agents but simply hasn''t chatted yet)'
|
|
3265
|
+
status: completed
|
|
3266
|
+
witness: 'Verified already correctly distinct in agent-chat.js: installHint (line 449) renders ONLY when zero agents are installed (guided install commands + recheck button); the calm agentchat-empty state (line 433) renders whenever the thread is empty regardless of agent availability, with copy that adapts to selectedAgent presence (''{name} is ready. Type a message below.'' vs ''Select an agent to start.''). These are already two separate, correctly-gated code paths - no change needed. Added onboardingBanner is a THIRD, product-level welcome (shown once ever, not per-empty-thread) explaining the existence of History/Files/Live tabs, which neither installHint nor agentchat-empty ever addressed.'
|
|
3267
|
+
- id: kit-roving-menu-consolidation-regression-guard
|
|
3268
|
+
subject: 'Corner case for kit-use-roving-menu-hook: after consolidating Dropdown/PermissionMenu/MenuButton onto the shared hook, verify empty-list (0 items) and single-item (1 item) roving-nav edge cases still hold for ALL THREE consumers (previously only individually verified for MenuButton per the 2026-07-24 docstudio-port session), and verify PermissionMenu gaining typeahead as a side effect of consolidation doesn''t change its existing keyboard contract unexpectedly'
|
|
3269
|
+
status: completed
|
|
3270
|
+
witness: 'Verified live via browser dispatch: MenuButton-empty (0 items) renders 0 focusable menu items, no crash, stillOpen:false after Escape (nothing was open to close). MenuButton-single (1 item) ArrowDown wraps to itself (Only->Only). PermissionMenu gained typeahead as a side effect of sharing useRovingMenu with Dropdown/MenuButton - this is the intended fix for the previously-noted copy-paste drift (PermissionMenu lacked typeahead before consolidation); existing Escape/ArrowUp/ArrowDown/Home/End contract unchanged (verified ArrowDown Xray->Yankee, Escape closes cleanly).'
|
|
3271
|
+
- id: kit-avatar-extension-backward-compat
|
|
3272
|
+
subject: 'Corner case for kit-avatar-consolidate-fallback: extending Avatar with size/shape/initialsCount props must remain byte-identical for every existing Avatar call site that doesn''t pass the new props (default initialsCount=1, default shape matching current circular rendering) - verify no visual regression at chat.js''s existing Avatar usage'
|
|
3273
|
+
status: completed
|
|
3274
|
+
witness: 'Live browser witness on dist bundle: Avatar({name:''Jordan''}) with no new props renders byte-identical to pre-change output (class="ds-avatar ds-avatar-md" role=img aria-label=Jordan, single letter J) - confirmed via direct DOM inspection. New initialsCount=2 prop correctly renders ''JO''; new shape=''square'' prop correctly adds ds-avatar-square class alongside existing classes, nothing removed.'
|
|
3275
|
+
- id: app-generic-tables-live-tab-integration
|
|
3276
|
+
subject: 'Corner case for kit-generic-health-table and kit-generic-process-registry-table: agentgui''s Live tab currently renders its own bespoke session/process listing markup - integrating the new generic tables must preserve all existing per-session actions (stop button, click-to-view) that the bespoke markup currently provides, not just visual parity'
|
|
3277
|
+
status: completed
|
|
3278
|
+
witness: 'Investigated: agentgui''s Live tab (app.js:2123 liveMain()) already renders SessionDashboard, a purpose-built kit component with sorting (status/elapsed/activity/errors), filtering, errors-only toggle, tri-state select-all, bulk-stop with two-step arm confirmation, per-session stop actions, and activity-ticking - strictly more capable than the new generic ProcessRegistryTable/HealthTable (plain 3-column display, no actions). Per this row''s own expansion note (must preserve all existing per-session actions, not just visual parity), swapping SessionDashboard for the generic table would be a regression, not an improvement. Correct resolution: do NOT integrate the generic tables into Live tab - they remain valuable standalone kit primitives for simpler monitoring surfaces (freddie''s own pages, or a future agentgui surface with no need for SessionDashboard''s richer feature set).'
|
package/package.json
CHANGED
package/site/app/js/app.js
CHANGED
|
@@ -44,6 +44,9 @@ const state = {
|
|
|
44
44
|
eventsLimit: 300, // how many of the most-recent events to render; grows via "load older"
|
|
45
45
|
files: { path: '', segments: [], entries: [], roots: [], loading: false, error: null, preview: null, sort: 'name', sortDir: 'asc', filter: '' },
|
|
46
46
|
git: { loading: false, error: null, diff: '', commits: [], worktrees: [], files: [], file: '', worktreeBusy: false },
|
|
47
|
+
// One-time welcome banner naming what each tab is for. Shown until
|
|
48
|
+
// dismissed once, ever - a returning user has already learned the tabs.
|
|
49
|
+
showOnboarding: lsGet('agentgui.onboarded') !== '1',
|
|
47
50
|
};
|
|
48
51
|
|
|
49
52
|
// Two-step arm controls auto-reset after this delay so an accidental first click
|
|
@@ -170,6 +173,12 @@ function lsGet(k) { try { return localStorage.getItem(k); } catch { return null;
|
|
|
170
173
|
function lsSet(k, v) { try { localStorage.setItem(k, v); } catch {} }
|
|
171
174
|
function lsRemove(k) { try { localStorage.removeItem(k); } catch {} }
|
|
172
175
|
|
|
176
|
+
function dismissOnboarding() {
|
|
177
|
+
state.showOnboarding = false;
|
|
178
|
+
lsSet('agentgui.onboarded', '1');
|
|
179
|
+
render();
|
|
180
|
+
}
|
|
181
|
+
|
|
173
182
|
// A single visually-hidden aria-live region for transient announcements (tab
|
|
174
183
|
// changes, etc.) so screen-reader users hear context that's otherwise conveyed
|
|
175
184
|
// only by focus movement or color.
|
|
@@ -669,7 +678,18 @@ function view() {
|
|
|
669
678
|
h('div', { key: 'sc-body', class: 'ds-alert-body' }, ShortcutList({ shortcuts: SHORTCUTS })),
|
|
670
679
|
] }))
|
|
671
680
|
: null;
|
|
672
|
-
|
|
681
|
+
// One-time welcome naming what each tab is for - a brand-new user's only
|
|
682
|
+
// other guidance is installHint (zero-agents case) or the calm chat empty
|
|
683
|
+
// state (agents-but-no-conversation case); neither explains History/Files/
|
|
684
|
+
// Live exist at all. Dismissed once, ever, via localStorage.
|
|
685
|
+
const onboardingBanner = state.showOnboarding
|
|
686
|
+
? Alert({
|
|
687
|
+
key: 'onboarding', kind: 'info', title: 'Welcome to AgentGUI',
|
|
688
|
+
onDismiss: dismissOnboarding,
|
|
689
|
+
children: 'Chat with an agent here. History holds every past conversation, Files browses and edits project directories, Live shows every running session at once, and Settings covers connection, appearance, and keyboard shortcuts.',
|
|
690
|
+
})
|
|
691
|
+
: null;
|
|
692
|
+
const main = h('div', { id: 'agentgui-main', role: 'region', 'aria-label': 'main content', 'data-chat-scroll': '', class: 'agentgui-main agentgui-main-' + state.tab }, [shortcutsHint, onboardingBanner, ...mainContent()].filter(Boolean));
|
|
673
693
|
|
|
674
694
|
// Claude-Desktop three-column shell: a persistent left rail (workspace nav), an
|
|
675
695
|
// optional sessions column (chat + history share the conversation list), the
|
|
@@ -1215,7 +1235,9 @@ async function runBulkDelete() {
|
|
|
1215
1235
|
state.files.dialog = null;
|
|
1216
1236
|
restoreFileDialogFocus(d._trigger);
|
|
1217
1237
|
marked.clear(); state.files._lastMarkIdx = null;
|
|
1218
|
-
|
|
1238
|
+
const successMsg = 'deleted ' + okCount + ' ' + (okCount === 1 ? 'entry' : 'entries');
|
|
1239
|
+
announce(successMsg);
|
|
1240
|
+
toast({ message: successMsg, kind: 'success' });
|
|
1219
1241
|
// Patch the visible list immediately instead of waiting on a second full
|
|
1220
1242
|
// directory round-trip - the server already confirmed every deletion.
|
|
1221
1243
|
const gone = new Set(targets.map((e) => e.path || e.name));
|
|
@@ -1265,7 +1287,9 @@ async function runBulkMove(destDir) {
|
|
|
1265
1287
|
state.files.dialog = null;
|
|
1266
1288
|
restoreFileDialogFocus(d._trigger);
|
|
1267
1289
|
marked.clear(); state.files._lastMarkIdx = null;
|
|
1268
|
-
|
|
1290
|
+
const successMsg = 'moved ' + okCount + ' ' + (okCount === 1 ? 'entry' : 'entries');
|
|
1291
|
+
announce(successMsg);
|
|
1292
|
+
toast({ message: successMsg, kind: 'success' });
|
|
1269
1293
|
// Moved entries leave the current dir - patch them out immediately rather
|
|
1270
1294
|
// than waiting on a second full directory round-trip.
|
|
1271
1295
|
const gone = new Set(targets.map((e) => e.path || e.name));
|
|
@@ -1301,8 +1325,11 @@ async function runFileMutation(fn, doneMsg, patch) {
|
|
|
1301
1325
|
restoreFileDialogFocus(d._trigger);
|
|
1302
1326
|
announce(doneMsg);
|
|
1303
1327
|
// A soft-delete's trashId (if this mutation was a delete) rides the
|
|
1304
|
-
// return value straight to the undo-toast caller
|
|
1328
|
+
// return value straight to the undo-toast caller - that banner is its own
|
|
1329
|
+
// dedicated real-undo-action UI, not a generic dismiss-only confirmation,
|
|
1330
|
+
// so it stays separate from toast() rather than being replaced by it.
|
|
1305
1331
|
if (result && result.trashId) offerUndoDelete(result.trashId, doneMsg);
|
|
1332
|
+
else toast({ message: doneMsg, kind: 'success' });
|
|
1306
1333
|
if (patch) {
|
|
1307
1334
|
// Patch the visible list immediately, matching the bulk-delete/move
|
|
1308
1335
|
// pattern, instead of stalling the dialog on a second full round-trip.
|
|
@@ -3790,9 +3817,9 @@ function settingsMain() {
|
|
|
3790
3817
|
render();
|
|
3791
3818
|
},
|
|
3792
3819
|
}),
|
|
3793
|
-
state.backendStatus === 'connecting' ? h('
|
|
3794
|
-
state.backendStatus === 'ok' ? h('
|
|
3795
|
-
state.backendStatus === 'failed' ? h('
|
|
3820
|
+
state.backendStatus === 'connecting' ? h('span', { key: 'bst-connecting', class: 'ds-status-chip', role: 'status' }, 'connecting…') : null,
|
|
3821
|
+
state.backendStatus === 'ok' ? h('span', { key: 'bst-ok', class: 'ds-status-chip ds-status-chip-ok', role: 'status' }, 'connected') : null,
|
|
3822
|
+
state.backendStatus === 'failed' ? h('span', { key: 'bst-failed', class: 'ds-status-chip ds-status-chip-error', role: 'alert' }, 'connection failed - check the URL') : null,
|
|
3796
3823
|
(state.confirmingBackend !== undefined && state.confirmingBackend === state.backendDraft && isValid && state.backendDraft !== state.backend)
|
|
3797
3824
|
? h('p', { key: 'bcw', class: 't-meta field-error', role: 'alert' }, 'changing backend discards this browser\'s chat transcript - press save again to confirm') : null,
|
|
3798
3825
|
healthSummary(),
|
|
@@ -5451,6 +5451,7 @@
|
|
|
5451
5451
|
.ds-247420 .ds-avatar-sm { width: 24px; height: 24px; font-size: 10px; }
|
|
5452
5452
|
.ds-247420 .ds-avatar-md { width: 36px; height: 36px; font-size: 12px; }
|
|
5453
5453
|
.ds-247420 .ds-avatar-lg { width: 48px; height: 48px; font-size: 15px; }
|
|
5454
|
+
.ds-247420 .ds-avatar-square { border-radius: var(--r-2, 6px); }
|
|
5454
5455
|
|
|
5455
5456
|
/* SpreadsheetPreview — tabbed inline spreadsheet/CSV viewer (docstudio
|
|
5456
5457
|
xls-preview.js port). Tabs reuse the same neutral-at-rest pattern as
|
|
@@ -10477,6 +10478,32 @@
|
|
|
10477
10478
|
.ds-247420 .agentgui-main-chat { display: flex; flex-direction: column; flex: 1; }
|
|
10478
10479
|
.ds-247420 .agentgui-main .ds-section { margin: 0 0 var(--space-4, 16px); }
|
|
10479
10480
|
|
|
10481
|
+
/* Tab-switch entrance: navTo() sets a per-tab modifier class
|
|
10482
|
+
(agentgui-main-<tab>) on the SAME #agentgui-main DOM node every switch
|
|
10483
|
+
(webjsx patches props on the existing element rather than replacing it).
|
|
10484
|
+
A single shared animation-name bound to the constant .agentgui-main base
|
|
10485
|
+
class would only ever fire once (on first mount) since a CSS animation
|
|
10486
|
+
restarts only when the animation-name value itself changes or the
|
|
10487
|
+
element is detached/reattached - the base class never changes. Each tab
|
|
10488
|
+
gets its OWN animation-name (functionally identical keyframes, distinct
|
|
10489
|
+
names) so switching from e.g. agentgui-main-chat to agentgui-main-history
|
|
10490
|
+
genuinely changes which animation-name applies, which is what makes the
|
|
10491
|
+
browser replay the entrance on every switch. Matches the existing motion
|
|
10492
|
+
craft level of ds-alert-in/ds-card-in/agentchat-jump.show instead of every
|
|
10493
|
+
full-page tab swap happening with zero transition. */
|
|
10494
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
10495
|
+
.ds-247420 .agentgui-main-chat { animation: ds-main-in-chat var(--dur-base) var(--ease); }
|
|
10496
|
+
.ds-247420 .agentgui-main-history { animation: ds-main-in-history var(--dur-base) var(--ease); }
|
|
10497
|
+
.ds-247420 .agentgui-main-files { animation: ds-main-in-files var(--dur-base) var(--ease); }
|
|
10498
|
+
.ds-247420 .agentgui-main-live { animation: ds-main-in-live var(--dur-base) var(--ease); }
|
|
10499
|
+
.ds-247420 .agentgui-main-settings { animation: ds-main-in-settings var(--dur-base) var(--ease); }
|
|
10500
|
+
}
|
|
10501
|
+
@keyframes ds-main-in-chat { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
10502
|
+
@keyframes ds-main-in-history { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
10503
|
+
@keyframes ds-main-in-files { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
10504
|
+
@keyframes ds-main-in-live { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
10505
|
+
@keyframes ds-main-in-settings { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
10506
|
+
|
|
10480
10507
|
/* Readable backend health summary (replaces raw JSON dump). */
|
|
10481
10508
|
.ds-247420 .health-summary { display: flex; flex-wrap: wrap; gap: .4em; margin: .6em 0; }
|
|
10482
10509
|
.ds-247420 .health-chip {
|
|
@@ -10492,6 +10519,30 @@
|
|
|
10492
10519
|
border-color: color-mix(in srgb, var(--accent) 40%, transparent);
|
|
10493
10520
|
}
|
|
10494
10521
|
|
|
10522
|
+
/* Standalone connection-status chip — same visual vocabulary as
|
|
10523
|
+
.health-chip so a form's own connecting/connected/failed feedback reads
|
|
10524
|
+
consistently with the healthSummary row beneath it, instead of one being
|
|
10525
|
+
a colored chip and the other bare <p class="t-meta"> text. */
|
|
10526
|
+
.ds-247420 .ds-status-chip {
|
|
10527
|
+
display: inline-flex; align-items: center; gap: .35em;
|
|
10528
|
+
font-family: var(--ff-mono, ui-monospace, monospace);
|
|
10529
|
+
font-size: .8rem; padding: .15em .55em; border-radius: var(--r-1, 6px);
|
|
10530
|
+
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
|
10531
|
+
color: var(--fg-2);
|
|
10532
|
+
border: var(--bw-hair, 1px) solid color-mix(in srgb, var(--fg) 12%, transparent);
|
|
10533
|
+
margin: .4em 0;
|
|
10534
|
+
}
|
|
10535
|
+
.ds-247420 .ds-status-chip-ok {
|
|
10536
|
+
color: var(--accent-ink);
|
|
10537
|
+
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
|
10538
|
+
border-color: color-mix(in srgb, var(--accent) 40%, transparent);
|
|
10539
|
+
}
|
|
10540
|
+
.ds-247420 .ds-status-chip-error {
|
|
10541
|
+
color: var(--danger);
|
|
10542
|
+
background: color-mix(in srgb, var(--danger) 12%, transparent);
|
|
10543
|
+
border-color: color-mix(in srgb, var(--danger) 35%, transparent);
|
|
10544
|
+
}
|
|
10545
|
+
|
|
10495
10546
|
/* Compact working-directory bar. */
|
|
10496
10547
|
.ds-247420 .cwd-bar {
|
|
10497
10548
|
display: flex; align-items: center; gap: .5em; flex-wrap: wrap;
|