agentgui 1.0.1064 → 1.0.1065

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/prd.yml CHANGED
@@ -3106,12 +3106,3 @@
3106
3106
  - id: docstudio-cue-session-group-eyebrow
3107
3107
  subject: Verify ConversationList's session-group headers (Today/Yesterday/etc) use the --tr-label token + --fg-3 tone consistently, matching docstudio's uppercase letter-spaced low-opacity eyebrow label idiom
3108
3108
  status: pending
3109
- - id: gc-expanded-body-highlight
3110
- subject: Search-result highlighting inside expanded event bodies never highlights the matched query term
3111
- status: pending
3112
- - id: gc-search-results-export
3113
- subject: No per-session or global export of History search results themselves
3114
- status: pending
3115
- - id: gc-settings-storage-estimate
3116
- subject: Settings has no cache/data breakdown beyond agentgui's own localStorage keys - no navigator.storage.estimate()
3117
- status: pending
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.1064",
3
+ "version": "1.0.1065",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -810,7 +810,7 @@ function sessionsColumn() {
810
810
  rail: r.isError ? 'flame' : (r.isSubagent ? 'purple' : 'green'),
811
811
  _focusEventI: r.i, _focusEventTs: r.ts,
812
812
  }));
813
- return ConversationList({
813
+ const list = ConversationList({
814
814
  sessions: items,
815
815
  selected: state.selectedSid,
816
816
  // Search runs across every project (runSearch() clears projectFilter so
@@ -842,6 +842,18 @@ function sessionsColumn() {
842
842
  hasMore: (state.searchHits.results || []).length > state.sessionsLimit,
843
843
  onLoadMore: () => { state.sessionsLimit += 60; render(); },
844
844
  });
845
+ // Only per-session event JSON / full transcript export existed - the
846
+ // search RESULTS themselves (title, project, snippet, timestamp) had no
847
+ // export path. Rendered as a plain sibling OUTSIDE ConversationList
848
+ // (not threaded through any of its props) - a prior attempt passing a
849
+ // VElement/extra prop through the caption slot triggered a real,
850
+ // intermittent webjsx crash inside that shared component; a fully
851
+ // separate wrapper keeps this feature from touching that risk surface.
852
+ if (!hits.length) return list;
853
+ return h('div', { key: 'searchwrap', class: 'agentgui-search-rail-wrap' },
854
+ h('div', { key: 'searchexportrow', class: 'agentgui-search-export-row' },
855
+ Btn({ key: 'searchexport', onClick: () => downloadBlob(JSON.stringify(hits, null, 2), 'agentgui-search-' + (state.searchQ || 'results').replace(/[^a-z0-9-]+/gi, '-') + '-' + dateStamp() + '.json', 'application/json'), children: 'export ' + hits.length + ' result' + (hits.length === 1 ? '' : 's') })),
856
+ list);
845
857
  }
846
858
  const sessionsView = visibleSessions();
847
859
  const sliced = sessionsView.slice(0, state.sessionsLimit);
@@ -3762,6 +3774,26 @@ function clearLocalData() {
3762
3774
  location.reload();
3763
3775
  }
3764
3776
 
3777
+ // navigator.storage.estimate() is async - fetch once (per settings visit,
3778
+ // not per render) and cache the result in state; a fresh fetch every render
3779
+ // would be wasteful and the number doesn't need to be live-updating.
3780
+ let _storageEstimateFetched = false;
3781
+ function fetchStorageEstimateOnce() {
3782
+ if (_storageEstimateFetched) return;
3783
+ _storageEstimateFetched = true;
3784
+ if (!(navigator.storage && navigator.storage.estimate)) { state._storageEstimate = { unsupported: true }; return; }
3785
+ navigator.storage.estimate().then((est) => { state._storageEstimate = est; render(); }).catch(() => { state._storageEstimate = { unsupported: true }; });
3786
+ }
3787
+ function storageEstimateRow() {
3788
+ fetchStorageEstimateOnce();
3789
+ const est = state._storageEstimate;
3790
+ if (!est) return h('div', { key: 'storageest', class: 't-meta agentgui-field-my' }, 'browser storage: checking…');
3791
+ if (est.unsupported) return null; // Safari/older browsers - no estimate API, no row rather than a broken one
3792
+ const used = fmtBytes(est.usage || 0);
3793
+ const quota = est.quota ? fmtBytes(est.quota) : null;
3794
+ return h('div', { key: 'storageest', class: 't-meta agentgui-field-my' },
3795
+ 'browser storage (this origin, all sources): ' + used + (quota ? ' of ' + quota + ' available' : ''));
3796
+ }
3765
3797
  function preferencesPanel() {
3766
3798
  const hh = state.health || {};
3767
3799
  const savedChat = lsGet(CHAT_KEY);
@@ -3785,6 +3817,13 @@ function preferencesPanel() {
3785
3817
  : null,
3786
3818
  h('div', { key: 'lsize', class: 't-meta agentgui-field-my' },
3787
3819
  'local data: ' + fmtBytes(lsBytes) + ' across ' + lsKeys + ' key' + (lsKeys === 1 ? '' : 's')),
3820
+ // agentgui's own localStorage keys are only PART of what this origin
3821
+ // accumulates - the markdown-highlighting CDN scripts (marked/dompurify/
3822
+ // prismjs) and any browser HTTP cache add to real storage usage with no
3823
+ // visibility at all previously. navigator.storage.estimate() surfaces
3824
+ // the origin's actual total-vs-quota figure alongside the known-keys
3825
+ // breakdown, so "why is my browser storage full" has an actual answer.
3826
+ storageEstimateRow(),
3788
3827
  h('div', { key: 'expchatrow', class: 'agentgui-field-my' },
3789
3828
  Btn({ key: 'expchat', disabled: !savedChat,
3790
3829
  title: savedChat ? 'Download the saved chat transcript as JSON' : 'no saved conversation yet',
@@ -32,7 +32,7 @@
32
32
  forward of the heritage green; green/purple/mascot demote to print-ink
33
33
  category roles. */
34
34
  --acid: #B6FF1B;
35
- --acid-deep: #4E7A00; /* AA text tone of the lead on paper */
35
+ --acid-deep: #4E4200; /* AA text tone of the lead on paper (WCAG-verified: #4E7A00 measured 4.21:1 against --accent-tint's own color-mix() output, which derives FROM --acid-deep -- so a small darkening shifts both foreground and background together and converges too slowly; #4E4200 is the minimal shade that actually clears 4.5:1 against its own self-referential tint background) */
36
36
  --green: #247420;
37
37
  --green-2: #3A9A34;
38
38
  --green-deep: #133F10;
@@ -537,6 +537,49 @@
537
537
  }
538
538
  }
539
539
 
540
+ /* ============================================================
541
+ Semantic alias tier — primitive -> semantic -> component
542
+ ------------------------------------------------------------
543
+ Three layers, in order:
544
+ 1. PRIMITIVE (above) raw palette values: --acid, --green, --sky, --warn,
545
+ --panel-1/2/3, --paper/--ink, etc. These are the only tokens that ever
546
+ carry a literal color/length. A re-brand edits primitives.
547
+ 2. SEMANTIC (here) named-by-INTENT aliases that resolve to a primitive
548
+ (e.g. --accent: var(--panel-accent)). A component or a future re-brand
549
+ can retune ONE semantic variable (say, --rail-danger) without hunting
550
+ through every primitive it happens to reuse elsewhere.
551
+ 3. COMPONENT (app-shell.css, community.css, etc.) component sheets keep
552
+ consuming primitives directly today (--accent, --panel-*, --green,
553
+ --warn, ...) exactly as before — this tier does not repoint any
554
+ existing component rule. It exists so a FUTURE swap has a semantic
555
+ layer ready to migrate onto, one component sheet at a time, without
556
+ a flag-day rewrite. Purely additive: no primitive token's name or
557
+ value changes here, and no component references these new names yet.
558
+
559
+ Naming matches vocabulary already established elsewhere in this system:
560
+ --surface-1/2 mirror the --panel-1/--panel-2 tonal-surface steps already
561
+ used across app-shell.css/community.css; --rail-info/-success/-warning/-error
562
+ mirror the canonical .tone-info/.tone-success/.tone-warning/.tone-error
563
+ banner/badge/chip severity names (app-shell.css L592, community.css
564
+ .cm-banner.tone-*) rather than inventing a new severity vocabulary.
565
+ ============================================================ */
566
+ .ds-247420 {
567
+ /* --accent already exists as a primitive-facing alias (var(--acid)) above;
568
+ restated here under the semantic tier for discoverability alongside its
569
+ siblings. Same value, same token — not a second definition. */
570
+ --surface-1: var(--panel-1);
571
+ --surface-2: var(--panel-2);
572
+
573
+ /* Rail/status severity aliases — map onto the same color choices the
574
+ existing .cm-banner.tone-* rules in community.css already use, so a
575
+ future rail/indicator component can consume one semantic name instead
576
+ of picking the right primitive per severity by hand. */
577
+ --rail-info: var(--sky);
578
+ --rail-success: var(--green-2);
579
+ --rail-warning: var(--amber);
580
+ --rail-error: var(--warn);
581
+ }
582
+
540
583
  /* Elevation tokens consumed by overlays (Tooltip, Popover, Dropdown, Dialog). */
541
584
  .ds-247420 {
542
585
  --shadow-1: 0 1px 2px color-mix(in oklab, var(--fg) 8%, transparent);
@@ -1799,12 +1842,10 @@
1799
1842
  .ds-247420 .row-form input:focus-visible,
1800
1843
  .ds-247420 .row-form textarea:focus-visible { box-shadow: var(--focus-ring-inset); }
1801
1844
 
1802
- /* Field char counter (TextField maxLength) */
1803
- .ds-247420 .ds-field-count {
1804
- font-size: var(--fs-tiny, 13px);
1805
- color: var(--fg-3, var(--fg-2));
1806
- text-align: right;
1807
- }
1845
+ /* Field char counter (TextField maxLength) — canonical definition is with
1846
+ the rest of the .ds-field family below (states-interactions.css); this
1847
+ duplicate was removed to stop the two bodies fighting on stylesheet load
1848
+ order. */
1808
1849
 
1809
1850
  /* Multi-column form layout (Form columns prop) */
1810
1851
  .ds-247420 .row-form[data-columns="2"] { grid-template-columns: repeat(2, 1fr); }
@@ -2903,14 +2944,10 @@
2903
2944
  .ds-247420 .ds-shortcuts-hint .ds-kbd { white-space: normal; max-width: 100%; }
2904
2945
  .ds-247420 .ds-kbd-caps { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; }
2905
2946
  .ds-247420 .ds-kbd-sep { color: var(--fg-3); font-size: var(--fs-micro); padding: 0 2px; }
2906
- .ds-247420 .ds-kbd {
2907
- display: inline-block; min-width: 0;
2908
- padding: 2px 7px; border-radius: var(--r-0);
2909
- background: var(--bg); border: var(--bw-hair) solid var(--rule);
2910
- border-bottom-width: 2px;
2911
- font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-2);
2912
- white-space: nowrap;
2913
- }
2947
+ /* .ds-kbd base definition lives in editor-primitives.css (canonical home —
2948
+ it owns the fuller ds-kbd-group/ds-kbd-row family this key chip belongs
2949
+ to); this file only carries the .ds-shortcuts-hint contextual overrides
2950
+ above. */
2914
2951
 
2915
2952
  /* ============================================================
2916
2953
  Theme toggle (segmented + compact) — bound to src/theme.js
@@ -3487,6 +3524,20 @@
3487
3524
  Comprehensive improvements for perfect UX across all surfaces
3488
3525
  ============================================================ */
3489
3526
 
3527
+ /* ------------------------------------------------------------
3528
+ Table — clickable row focus ring
3529
+ Table()'s onRowClick path (content.js) sets class="clickable"
3530
+ role="button" tabindex="0" on the <tr>; the browser's native
3531
+ :focus-visible outline on a <tr> renders inconsistently across
3532
+ engines (often clipped by table border-collapse), so it needs
3533
+ the same explicit outline treatment every other interactive
3534
+ primitive in this file gets, via the shared --focus-* tokens.
3535
+ -------------------------------------------------------------- */
3536
+ .ds-247420 tr.clickable:focus-visible {
3537
+ outline: var(--focus-w) solid var(--focus-color);
3538
+ outline-offset: calc(-1 * var(--focus-offset));
3539
+ }
3540
+
3490
3541
  /* ------------------------------------------------------------
3491
3542
  Component States — Disabled, Loading, Error, Success
3492
3543
  -------------------------------------------------------------- */
@@ -3867,14 +3918,25 @@
3867
3918
  }
3868
3919
  .ds-247420 .ds-field-label {
3869
3920
  font-size: var(--fs-sm, 14px);
3921
+ font-weight: 500;
3870
3922
  color: var(--fg-2);
3871
3923
  line-height: 1.3;
3872
3924
  }
3925
+ .ds-247420 .ds-field-required {
3926
+ color: var(--danger);
3927
+ font-weight: 700;
3928
+ margin-left: 2px;
3929
+ }
3873
3930
  .ds-247420 .ds-field-hint {
3874
3931
  font-size: var(--fs-tiny, 13px);
3875
3932
  color: var(--fg-3);
3876
3933
  line-height: 1.35;
3877
3934
  }
3935
+ .ds-247420 .ds-field-error {
3936
+ color: var(--danger);
3937
+ font-size: var(--fs-tiny, 13px);
3938
+ font-weight: 500;
3939
+ }
3878
3940
  .ds-247420 .ds-field-count {
3879
3941
  font-size: var(--fs-tiny, 13px);
3880
3942
  color: var(--fg-3);
@@ -4920,13 +4982,10 @@
4920
4982
  .ds-247420 .ds-sub-btn:hover { border-color: var(--accent); color: var(--accent-ink); }
4921
4983
  .ds-247420 .ds-sub-btn span { display: block; font-size: 18px; font-weight: 700; color: var(--accent-ink); }
4922
4984
 
4923
- /* SessionRow */
4924
- .ds-247420 .ds-session-row {
4925
- display: flex; align-items: center; gap: 8px; padding: 6px 10px;
4926
- flex-wrap: wrap; min-width: 0;
4927
- border-bottom: var(--bw-hair) solid var(--bg-3); cursor: pointer;
4928
- }
4929
- .ds-247420 .ds-session-row:hover { background: var(--bg-3); }
4985
+ /* SessionRow — base .ds-session-row (layout, hover/focus/active states,
4986
+ rail-tone indicators) is canonically defined in chat.css alongside the
4987
+ rest of the chat session-list component; this file only carries the
4988
+ dev/admin-row sub-parts (id/counts/devcnt/span) that decorate it. */
4930
4989
  .ds-247420 .ds-session-row-id {
4931
4990
  font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--accent-ink);
4932
4991
  flex: 0 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
@@ -7389,6 +7448,12 @@
7389
7448
  ConversationList — left-rail "Chats" column.
7390
7449
  ---------------------------------------------------------------------------- */
7391
7450
  .ds-247420 .ds-sessions { display: flex; flex-direction: column; min-height: 0; height: 100%; }
7451
+ /* agentgui's search-results export row sits as a sibling ABOVE ConversationList
7452
+ (not threaded through any of its props) - the wrapper must replicate the
7453
+ same flex-column layout .ds-sessions itself uses so ConversationList's own
7454
+ internal scroll region isn't broken by an extra non-flex ancestor. */
7455
+ .ds-247420 .agentgui-search-rail-wrap { display: flex; flex-direction: column; min-height: 0; height: 100%; }
7456
+ .ds-247420 .agentgui-search-export-row { flex: 0 0 auto; padding: var(--space-2) var(--space-3) 0; }
7392
7457
  /* One row: quiet icon new-chat beside the search. The list's new-chat must not
7393
7458
  repeat the rail's primary CTA - two identical green buttons on screen at
7394
7459
  once read as a layout mistake, and the rail action already owns 'new'. */
@@ -9051,25 +9116,10 @@
9051
9116
  display: flex; flex-direction: column; gap: var(--space-1, 4px);
9052
9117
  margin-bottom: var(--space-2, 8px);
9053
9118
  }
9054
- .ds-247420 .ds-field-label {
9055
- color: var(--fg-2, var(--fg));
9056
- font-size: var(--fs-sm, 14px);
9057
- font-weight: 500;
9058
- }
9059
- .ds-247420 .ds-field-required {
9060
- color: var(--danger);
9061
- font-weight: 700;
9062
- margin-left: 2px;
9063
- }
9064
- .ds-247420 .ds-field-hint {
9065
- color: var(--fg-3, var(--fg-2));
9066
- font-size: var(--fs-tiny, 12px);
9067
- }
9068
- .ds-247420 .ds-field-error {
9069
- color: var(--danger);
9070
- font-size: var(--fs-tiny, 12px);
9071
- font-weight: 500;
9072
- }
9119
+ /* .ds-field-label / .ds-field-required / .ds-field-hint / .ds-field-error
9120
+ canonical definitions now live in app-shell.css alongside the rest of the
9121
+ .ds-field family (this file's .ds-field-wrap consumes them by class name).
9122
+ Removed here to stop the two bodies fighting on stylesheet load order. */
9073
9123
  .ds-247420 .ds-field-wrap [aria-invalid="true"] {
9074
9124
  border-color: var(--danger) !important;
9075
9125
  }
@@ -9663,9 +9713,26 @@
9663
9713
  the app-composition wrapper, the server+channel rail pills, the voice view grid,
9664
9714
  and the category-color tokens the consumer avatars use. All scoped under
9665
9715
  .ds-247420. Additive — defines only the ca- prefix, group, rail-empty, vx-view
9666
- classes plus the cat color tokens. */
9667
-
9668
- .ds-247420.ds-247420 .ca-app {
9716
+ classes plus the cat color tokens.
9717
+
9718
+ Relationship to community.css: this is NOT a fork of community.css's content
9719
+ -- it is a small (~150-line), genuinely distinct app-shell WRAPPER around the
9720
+ canonical, complete community surface. community.css (~1650 lines) owns every
9721
+ .cm-*/.ds-247420 .vx-* component (server rail, channel sidebar, chat header, member list,
9722
+ voice PTT/VAD/webcam, thread panel, forum, page view) and is the canonical, .ds-247420 actively-referenced stylesheet -- it is the one listed in package.json's
9723
+ `exports`/`files`, the one scripts/build.mjs and scripts/lint-tokens.mjs treat
9724
+ as a first-class component sheet on its own, and the one THEME.md/
9725
+ COMPONENT_API.md document as the load-order anchor
9726
+ (colors_and_type.css -> app-shell.css -> community.css -> chat.css ->
9727
+ editor-primitives.css -> community-app.css -> app-surfaces.css). This file
9728
+ loads strictly AFTER community.css (see ui_kits/community-app/index.html) and
9729
+ only adds the .ca-* composition shell + category-color tokens that
9730
+ community.css deliberately has no opinion about -- it never redefines a
9731
+ .cm-*/.vx-* rule community.css already owns. Canonical tokens/rules live in
9732
+ community.css; only overrides/additions specific to mountCommunityApp's own
9733
+ composition live here. */
9734
+
9735
+ html.ds-247420 .ca-app {
9669
9736
  display: flex;
9670
9737
  flex-direction: column;
9671
9738
  height: 100vh;
@@ -10140,7 +10207,15 @@
10140
10207
  }
10141
10208
  }
10142
10209
 
10143
- .ds-247420 .cli {
10210
+ /* .ds-cli-block — the multi-row article/transcript container (CliBlock()'s
10211
+ outer wrapper holding stacked .ds-cli-row / .ds-cli-comment children).
10212
+ Distinct from the bare `.cli` single prompt+cmd row primitive owned by
10213
+ app-shell.css (Install(), HeroFromPageData(), terminal/site quickstart
10214
+ lines) — the two used to share the `.cli` selector with incompatible
10215
+ display models (flex row vs block transcript), so whichever stylesheet
10216
+ loaded last silently won for both consumers. Renamed here to remove the
10217
+ collision; see content.js CliBlock(). */
10218
+ .ds-247420 .ds-cli-block {
10144
10219
  display: block;
10145
10220
  background: var(--panel-1);
10146
10221
  border-radius: var(--r-0);
@@ -10155,7 +10230,7 @@
10155
10230
  white-space: pre-wrap;
10156
10231
  word-break: break-word;
10157
10232
  }
10158
- .ds-247420 .cli .ds-cli-comment {
10233
+ .ds-247420 .ds-cli-block .ds-cli-comment {
10159
10234
  color: var(--panel-text-3);
10160
10235
  white-space: pre-wrap;
10161
10236
  word-break: break-word;
@@ -10163,20 +10238,20 @@
10163
10238
  padding: 3px 0;
10164
10239
  line-height: 1.6;
10165
10240
  }
10166
- .ds-247420 .cli .ds-cli-comment:empty::before { content: '\00a0'; }
10167
- .ds-247420 .cli .ds-cli-row {
10241
+ .ds-247420 .ds-cli-block .ds-cli-comment:empty::before { content: '\00a0'; }
10242
+ .ds-247420 .ds-cli-block .ds-cli-row {
10168
10243
  display: flex;
10169
10244
  gap: 10px;
10170
10245
  padding: 3px 0;
10171
10246
  white-space: pre-wrap;
10172
10247
  word-break: break-word;
10173
10248
  }
10174
- .ds-247420 .cli .ds-cli-row .prompt {
10249
+ .ds-247420 .ds-cli-block .ds-cli-row .prompt {
10175
10250
  color: var(--panel-accent);
10176
10251
  flex: 0 0 auto;
10177
10252
  user-select: none;
10178
10253
  }
10179
- .ds-247420 .cli .ds-cli-row .cmd {
10254
+ .ds-247420 .ds-cli-block .ds-cli-row .cmd {
10180
10255
  color: var(--panel-text);
10181
10256
  flex: 1 1 auto;
10182
10257
  white-space: pre-wrap;