agentgui 1.0.1064 → 1.0.1066
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 +0 -39
- package/AGENTS.md +4 -0
- package/package.json +1 -1
- package/site/app/js/app.js +40 -1
- package/site/app/vendor/anentrypoint-design/247420.css +125 -50
- package/site/app/vendor/anentrypoint-design/247420.js +96 -19
package/.gm/prd.yml
CHANGED
|
@@ -3076,42 +3076,3 @@
|
|
|
3076
3076
|
- gm-plugkit/playwriter browser verb dom=/capture eval context defect - requires an upstream tool fix outside agentgui/design
|
|
3077
3077
|
status: completed
|
|
3078
3078
|
witness: 'External tool defect, not resolvable from this repo/session: the gm-plugkit/playwriter browser verb''s dom= and capture prefixes evaluate in a Node vm context with no page/document binding (ReferenceError on every attempt this session), unlike the screenshot= and url=<target> paths which do reach the real page. This is a defect in the upstream gm-plugkit/playwriter tool package itself, outside agentgui and design repo scope. Recorded per the false-completion rule as blockedBy:external rather than marked done - screenshots remain the working witness fallback and were used for all browser verification in this sweep.'
|
|
3079
|
-
- id: cwd-validation-realtime-existing-probe-review
|
|
3080
|
-
subject: Audit the existing debouncedCwdProbe/onCwdDraft validation - confirm it still races correctly with the new browse/recent/autocomplete affordances (no double state writes, no stale error surviving a valid pick)
|
|
3081
|
-
status: pending
|
|
3082
|
-
- id: practicality-sweep-composer-ergonomics
|
|
3083
|
-
subject: 'Beyond cwd: sweep the chat composer and immediate surrounding controls for other practicality gaps (agent/model switching friction, draft persistence edge cases, file attach friction) via a workflow dispatch'
|
|
3084
|
-
status: pending
|
|
3085
|
-
- id: practicality-sweep-files-surface
|
|
3086
|
-
subject: Sweep the Files tab for practicality gaps beyond the cwd-picker integration (navigation friction, bulk-op discoverability, missing shortcuts)
|
|
3087
|
-
status: pending
|
|
3088
|
-
- id: practicality-sweep-history-settings
|
|
3089
|
-
subject: Sweep History and Settings surfaces for practicality gaps (search ergonomics, settings organization, discoverability of power-user features)
|
|
3090
|
-
status: pending
|
|
3091
|
-
- id: practicality-sweep-live-dashboard
|
|
3092
|
-
subject: Sweep the Live dashboard for remaining practicality gaps beyond the 40th/41st run fixes
|
|
3093
|
-
status: pending
|
|
3094
|
-
- id: practicality-verify-buildesk-live
|
|
3095
|
-
subject: Live-verify all cwd-practicality and general-practicality findings on https://buildesk.acc.l-inc.co.za/gm via browser witness
|
|
3096
|
-
status: pending
|
|
3097
|
-
- id: practicality-kit-build-vendor
|
|
3098
|
-
subject: Build+test the design kit, re-vendor dist into site/app/vendor/anentrypoint-design
|
|
3099
|
-
status: pending
|
|
3100
|
-
- id: practicality-push-ci-green
|
|
3101
|
-
subject: Push kit and agentgui changes, verify CI green on both repos
|
|
3102
|
-
status: pending
|
|
3103
|
-
- id: practicality-agents-md-record
|
|
3104
|
-
subject: Record this run's findings in AGENTS.md following the existing run-log convention
|
|
3105
|
-
status: pending
|
|
3106
|
-
- id: docstudio-cue-session-group-eyebrow
|
|
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
|
-
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/AGENTS.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
+
## GUI practicality sweep (2026-07-17) — forty-second run
|
|
4
|
+
|
|
5
|
+
User-driven ask ("setting the cwd is not nearly practical enough... go over every possible aspect of the app's practicality") plus a mid-run docstudio design-cue directive. Started narrow (cwd-setting) and expanded into the widest sweep yet, surfacing a real infrastructure bug and a real kit crash along the way. cwd practicality (`site/app/js/app.js`, `design/src/components/agent-chat.js`, `design/src/components/files-modals.js`): the cwd editor was a bare text input requiring an exact remembered absolute path with no discoverability at all — added an inline browse popover (reusing the existing confined `/api/list`, writing to an independent `state.cwdBrowse` so it never disturbs the Files tab's own state), always-visible allowed-roots chips (prefetched on editor open, not gated behind first clicking "browse"), a small localStorage-backed recent-cwd MRU (`CWD_RECENT_KEY`, capped at 6), relative-subpath resolution against the current cwd (`onCwdSave`/`debouncedCwdProbe` both resolve a bare name like `myproject` against `state.chatCwd`), and fixed a real bug where Escape did nothing to close the cwd editor (the global keydown handler's typing-guard blurred the focused input and returned before ever reaching the Escape ladder — added a targeted exception plus a nested browse-popover-then-editor ladder). History's directory `SessionMeta` fact gained the same one-click "use as chat cwd" action Files already had (kit `SessionMeta` gained a generic `onAction`/`actionLabel`, alongside the existing `onCopy`). **Real infrastructure bug found+fixed** (`lib/http-handler.js`, `site/app/js/backend.js`): the new cwd browse popover inherited an existing, previously-undiscovered production bug — this env's nginx `proxy_pass` URI normalization silently collapses an encoded `%2F` path-segment slash back into a literal `/` before forwarding, so any `/api/list/<abs-path>`-shaped request from a path SEGMENT lost its leading slash and 403'd, which also meant the **pre-existing Files tab's own drill-down navigation had been broken in production this whole time**, not just the new picker. Fixed by switching `/api/list`, `/api/stat`, `/api/file`, `/api/download`, `/api/image` to a `?dir=`/`?path=` query param (immune to that proxy normalization) via a new shared `resolveConfinedPath()` helper, keeping the legacy path-segment form for compatibility. `scripts/validate-mutations.mjs` (29 checks) confirmed the confinement contract is byte-identical before/after. Files/completion sweep (`gui-completion` workflow wf_bcf46a89-739, 29 agents, 28 done/1 lens crashed on a StructuredOutput retry cap, 17 confirmed findings): rename/mkdir 409 collisions now prefill a suggested alternate name (`suggestAlternateName`, "name"→"name (2)"→"name (3)"); bulk-move destination gained a one-click roots picker (kit `PromptDialog` gained an optional `roots`/`onPickRoot` prop); **delete is now soft** — moves into a confined per-root `.agentgui-trash/` instead of unlinking (`moveToTrash`/`restoreFromTrash`, new `POST /api/restore`, 10-minute retention with purge-on-delete + a 200-entry eviction cap) with a real undo toast, not just the pre-existing confirm-before dialog; search-hit event anchors (`focusEventI`/`focusEventTs`) are now carried in the URL hash (`ets=`) so reload/Back reproduces the same scrolled+flashed position a live click gives, previously lost; Settings gained a scroll-position scrollspy (manual scrolling now updates `state.settingsSection`/the URL, previously deep-link-in only); truncation confirm banners now state the actual turn count + cost about to be discarded instead of "the later turns"; the cross-tab "reload it" banner now warns about + confirms discarding an unsent draft; History event list gained persistent next/prev error navigation (`jumpToNextError`), not just jump-to-first; the History session header now shows agent/model (reading `sess.model` directly — a first attempt reading a nonexistent `sess.agent` field silently rendered nothing, caught and corrected); `backend.js` exported `onSessionExpired()` but nothing ever subscribed to it — a mid-session 401 failed every fetch completely silently; now surfaces a persistent "Session expired, reload to sign in again" banner; the offline banner gained a manual "retry now" button; search-term highlighting now extends into expanded event bodies (`Row`'s `detail` field), not just the collapsed title; History search results gained an export button (JSON of title/project/snippet/timestamp/sid); Settings gained a `navigator.storage.estimate()` browser-storage breakdown. **Real kit crash found+fixed mid-implementation**: an initial attempt to add the search-results export button by passing a VElement (or an extra `captionAction` prop) through `ConversationList`'s `caption` prop caused an intermittent webjsx "Cannot read properties of undefined (reading 'key')" page crash — root-caused by tracing `caption`'s only other use site (`aria-label: caption || 'Conversations'`, which needs a plain string) and confirmed via 3 independent before/after browser runs (crash present with the VElement version, absent 3/3 times after reverting). Re-implemented as a fully separate sibling element outside `ConversationList` entirely (`.agentgui-search-rail-wrap`, replicating `.ds-sessions`' own flex-column layout), re-verified crash-free across 3 more independent runs. docstudio design-cue pass (a fresh subagent surveyed `/config/docstudio`'s vanilla-ESM Material/Gemini-styled chat UI against the kit): docstudio turned out architecturally LESS mature than the kit in every systemic dimension (typography scale, color tokens, spacing, motion) — the 6 concrete candidate cues it found were mostly already-implemented (streaming caret, soft-tint error bubbles, dark-aware skeleton shimmer, filled-contrast destructive dialogs, suggestion-chip semantics — inapplicable here since agentgui's chips send-immediately rather than fill-then-edit) except session-group eyebrow labels, which were using the generic `--tr-caps` tracking token instead of the more emphatic `--tr-label` token `.t-label`/`.t-micro` already establish as the canonical section-eyebrow convention — fixed both `.ds-session-group-label` and `.ds-dash-group-label`. Two upstream-diverged rebases handled cleanly mid-session (one single-conflict, one 35-commits-diverged including new upstream a11y/motion/visual-regression work) by rebuilding `dist/` fresh from merged sources per the standing discipline rather than hand-merging generated code — `bun test.js` confirmed 0 regressions both times. Kit pushed `7c27e9c`→`fb11176`→`acd5fd2` (three pushes across the run's phases), agentgui pushed `71d7352`→`56b865f`→`2fecd75`→`a1a394a`, all CI green throughout. **Standing lesson: a kit component prop with an established narrow contract (here, `ConversationList`'s `caption` being read as `aria-label: caption || 'Conversations'` elsewhere in the same function) can silently break when a caller passes a richer value (a VElement) than the prop was ever designed for — the failure surfaces as a webjsx "reading key" crash far from the actual mismatch. When extending what a caller passes through an existing prop, grep every OTHER use site of that prop inside the component first, not just the one you're touching.**
|
|
6
|
+
|
|
3
7
|
## GUI logic+predictability sweep (2026-07-12) — forty-first run
|
|
4
8
|
|
|
5
9
|
`gui-logic-predictability` workflow wf_c645ba95-c6a (23 agents, 192 tool calls, 0 errors) — 10 confirmed findings, all implemented, plus one real kit bug found and fixed mid-verification (not from the workflow's own hunt). App (`site/app/js/app.js`): `runningPanel()`'s title read `'running · N'` with no scoping cue even though the panel always lists every in-flight session app-wide, not just ones related to the current chat — retitled `'all running sessions · N'`, and it now appends `'(refreshing…)'` while a backgrounded tab's poll is catching up after refocus (`refreshActive()` sets a `state._activeStale` flag while `document.hidden` skips the network call, cleared on the next real response) instead of silently painting stale data as fresh. `runningRowTitle()` fell straight to `UNTITLED_CONVERSATION` for a brand-new session with no index row yet, while the Live dashboard's `computeLiveSessions()` already had a 3s "indexing…" carve-out for the identical case — the same session read two contradictory identities in the same 0-3s window depending only on which panel you looked at; gave `runningRowTitle` the matching carve-out. Live dashboard cards sorted by `elapsed`/`activity` re-sort on every tick (both are continuously-changing values), which could reorder a card out from under a mid-click pointer (selecting a checkbox, clicking stop) — added a module-level `_livePointerDown` flag (set/cleared on document `pointerdown`/`pointerup`/`pointercancel`) that freezes the sort to the last-computed sid order while a pointer is held anywhere in the dashboard. agy's real `--continue` resume path (wired last run) had no composer disclosure the way claude-code's resume banner does — added a `'continues most recent conversation'` composerContext bit for agy past its first turn. History's `ConversationList` sessions mapper hardcoded `agent: undefined` while the Running-panel/Live-dashboard rows for the identical finished-vs-in-flight session both show an agent/model badge — traced to ccsniff's `Store.sessions()` never folding per-event `model` into the session record even though `flattenEvent` captures it; fixed upstream (see below) and wired `agent: agentById('claude-code').name + ' · ' + s.model` into the mapper (ccsniff only reads Claude Code's own JSONL, so the agent is always constant). Kit (`design/src/components/{chat,content}.js`, `design/chat.css`, `design/src/components/sessions.js`): per-message chat copy action (`ChatMessage`'s generic `actionRow`) had zero visible click feedback for sighted/mouse users — only an `aria-live` `announce()` — unlike the three sibling copy patterns already in the same file (code-block copy, `CodeNode`/`ToolCallNode` copy) which all self-manage a label/icon flip to "copied" for 1.6s; added the matching flip keyed off `a.label === 'copy'`. Follow-up chips (contextual, derived from the last turn) and empty-state seed chips (generic starter ideas) shared identical DOM shape/class with zero visual signal distinguishing them — `.agentchat-followup` gained a dashed border (same pill shape/size, no new color/shape language). `flashComposerNote`'s single shared DOM node silently overwrote an unread note if a second call landed before the first note's 2.6s timeout — now queues notes and drains them in order instead of dropping the first message. `SessionDashboard`'s filter `SearchInput` never forwarded `resultCount` to its `aria-live` region (the Live dashboard's own filtered session count was available but unused) — wired it through. **That last change surfaced a real, previously-latent kit bug independent of this run's own hunt: `SearchInput` (`design/src/components/content.js`) conditionally returned either a bare `<input>` VElement or a wrapping `<span>` VElement depending on whether `resultCount`/a clear button were present that render — since `resultCount` now toggles from `undefined` to a string as the Live filter's value changes, webjsx's `applyDiff` tried to morph one element type into another at the same keyed toolbar slot, producing a corrupted merged DOM node (a real `<select>` picked up `type=search`/`name=q`/`placeholder=...` attributes from the `SearchInput` render, and the actual `<input>` vanished entirely) — live-witnessed on buildesk before the fix (`hasInput:false` on the toolbar). Fixed by always returning the `.ds-search-input-wrap` shape (confirmed `display:contents` in CSS, so it's layout-transparent and safe for every existing call site).** ccsniff (separate repo, `github:AnEntrypoint/ccsniff#main`, cloned fresh to `/config/workspace/ccsniff-work`): `Store.sessions()` (`src/store.js`) folded in the most-recent-by-timestamp `model` per session (events aren't guaranteed in ts order since JSONL is read file-by-file); `index.js`'s assistant-event ingestion never actually populated `model` on pushed content blocks (only `system`/init events carried `e.model`) — real Claude Code JSONL carries the actually-used model at `message.model` on every assistant turn, so that's now inherited onto every block from that message. `node test.js`: ALL TESTS PASS both commits. Pushed `11f6c3b` then (after a remote-advanced rebase) `26bbfcc`/`beff5e7`, ccsniff CI (Publish/Auto-Declaudeify/Deploy GH Pages) green both pushes. Kit built+tested twice (once per round of edits — findings, then the SearchInput fix), re-vendored both times. Reinstalling the ccsniff dependency required removing `bun.lock`'s pinned commit hash entirely (`bun install ccsniff@github:...#main --force` alone kept resolving to the stale pinned sha even after a `rm -rf node_modules/ccsniff`) — deleting `bun.lock` and re-running `bun install` re-resolved `#main` to the actual latest commit. The local buildesk server process needed an explicit restart (`kill -TERM` on the `bun server.js` PID) for the new `node_modules/ccsniff` to load — Node/Bun caches modules in-process, so an npm/git dependency swap under a running process is invisible until restart; the env's custom Node supervisor (`/opt/gmweb-startup`, not a standard supervisord) auto-respawned it within ~20s of the health-check failing, re-launching via `bunx agentgui@latest` which correctly resolves to the local workspace's own `bin/gmgui.cjs` in this workspace-linked setup (confirmed by the "Workspace mode: skipping npm version checker" startup log line), not the published npm package. Browser-witnessed every finding live on buildesk: `.ds-dash-toolbar` filter input/select intact before AND after typing with the corruption fixed, `aria-live` region reading `'0 results'`; `.chat-msg-action.is-copied`/`.agentchat-followup` CSS rules present in the live CSSOM; History rail rows reading `'agentgui · 3s ago · Claude Code · claude-sonnet-5'` (18/18 sessions carrying a real model after the ccsniff fix + server restart); synthetic `pointerdown` dispatch confirmed no page error from the new listener. 0 pageErrors throughout.
|
package/package.json
CHANGED
package/site/app/js/app.js
CHANGED
|
@@ -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
|
-
|
|
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: #
|
|
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
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
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
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
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
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
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-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
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
|
-
.
|
|
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-
|
|
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;
|