agentgui 1.0.1003 → 1.0.1005

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/AGENTS.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # AgentGUI — Agent Notes
2
2
 
3
+ ## GUI ux-craft sweep (2026-07-02) — twenty-second run
4
+
5
+ `gui-ux-craft` workflow wf_48cd6bae-6ae (35 agents, 20 confirmed). Kit (`../design`): **accent-on-paper contrast fix** — `var(--accent)` (lime, fill-only per its own token comment) was used directly as TEXT color in 7 sites and as a non-text FILL in 3 more (the live status dot, green session-rail fill), rendering ~1.07:1 contrast on the paper theme (WCAG needs 4.5:1 text / 3:1 non-text). Swapped all 10 to `--accent-ink`; borders/outlines/box-shadows on the same rules stayed on `--accent` (already non-text-passing). Four typography-rhythm fixes: `.ds-dash-title` now matches `.ds-session-title` size (was one step larger despite a comment claiming parity), `ContextPane` Row meta/sub now match the kit-wide Row default size (were one step smaller, `.sub` also dropped an unwanted forced monospace), `.ds-session-group-label` now matches `.panel-head`/`table th` sizing, `.ws-crumb` height now derives from `--app-crumb-h` instead of an unlinked magic number. Session rail's new-chat button and search input now share a 36px desktop height. `.ds-file-act` gained an explicit `:focus-visible` ring (was the only icon/toolbar-button family without one).
6
+
7
+ App (`site/app/js/app.js`): 5 copy-tone fixes (clear-history confirm button now says "yes, clear history" not "yes, clear chat"; "conversation" → "chat" in the cross-tab-update banner; "runs via npx" → "installs automatically when used"; raw ACP provider error string now prefixed + capped at 80 chars; disabled "export chat" button keeps its action label instead of swapping to "no saved chat"). Search-result rows with no title/snippet fall back to `session <8-char-sid>…` instead of a raw UUID. `index.html` gained a synchronous (non-module) inline script that reads the kit's `247420:theme` localStorage key and sets `data-theme` before first paint — the hardcoded `data-theme="dark"` previously flashed for users with a saved light/'paper' theme while the kit's ES module graph loaded.
8
+
9
+ Deferred (recorded as PRD rows, explicitly re-scoped, not silently dropped): kit README/`ui_kits` examples missing the flagship components (AgentChat/WorkspaceShell/SessionDashboard/ConversationList/ContextPane) and undocumented `stableFrame`/`mainFlush` props — a docs-only pass, not this visual/UX-craft run's scope. Perceived-performance work (first-render network-gating, CDN modulepreload, settings loading-affordance) — a dedicated perf pass, larger than a one-line fix. Kit pushed `anentrypoint-design` `3f50e7a` (rebased onto concurrent `0826e40`, also picked up an inherited uncommitted emoji-picker search feature). agentgui pushed `06f108d`. Both repos: build/lints/28 tests pass, browser-witnessed 0 console errors, CI green.
10
+
3
11
  ## GUI cohesion sweep (2026-07-02) — twenty-first run
4
12
 
5
13
  `gui-cohesion` workflow wf_6b9f1890-320 (25 agents, 12 confirmed). Kit (`../design`): `WorkspaceRail` items gain an optional `rail` attention-dot tone (a background surface, e.g. an errored Live session, can flag its nav item even while the user is elsewhere) — new `.ws-rail-item-flag` CSS. `WorkspaceShell` extends the pane-track `stableFrame` treatment to the sessions column (`keepSessionsTrack`, mirrors `keepPaneTrack`) so navigating chat/history/files/live/settings no longer reflows the 4-column grid to 3 and back. Mobile `ws-sessions`/`ws-pane` drawers now trap Tab/Shift+Tab focus (exported `trapTab` from `overlay-primitives.js`, reused in `shell.js`'s `toggleWsDrawer`) — previously Tab could walk focus out into the scrim. `ConversationList` rows accept a richer optional `status` ('error'|'stale'|'running'|'stopping') mirroring `SessionCard`'s `STATUS_DISC`, so a session pinned to the rail's "Running" group shows stuck-vs-busy. `ContextPane` gains a `recentFiles`/`onOpenFile` "recent files" panel. Also picked up inherited uncommitted 19th/20th-run work sitting dirty in the kit tree (agent-chat/chat/files-modals/files a11y+dropzone fixes) — commit and push before starting new work if `git status --porcelain` is non-empty at PLAN entry.
@@ -52,15 +60,7 @@ Witnessed on the boxone.off.l-inc.co.za/gm deploy: the page HTML/JS/CSS loaded (
52
60
 
53
61
  ## Files command surface + PASSWORD-boot fix (2026-06-11) — eleventh run
54
62
 
55
- Lands the 10th run's deferred batch + the janks a live witness surfaced on this env. **Kit path on this (linux) env is `../design` = `/config/workspace/design`** (same repo as `c:\dev\anentrypoint-design` on the windows env); update flow unchanged: edit kit -> `node scripts/build.mjs` -> copy `dist/247420.{js,css}` into `site/app/vendor/anentrypoint-design/` -> witness -> push both.
56
-
57
- **CRITICAL fix - PASSWORD-gated deploys could never boot the SPA.** `/gm/?token=` served index.html but the static subresources (`gm/js/app.js`, `gm/vendor/247420.{js,css}`) carry no token -> 401 -> blank page forever (witnessed: `readyState` stuck `loading`, `hasAgentgui:false`). `lib/http-handler.js` now sets an HttpOnly SameSite=Lax `agentgui_token` cookie (URL-encoded) on any successful auth and the gate accepts it; WS keeps `?token=`. Lax + the CSRF guard keep cross-site mutations rejected (a cross-site form never carries the Lax cookie on POST).
58
-
59
- **Files is a command surface.** Kit `FileGrid` gains multi-select (`selectable`/`marked` Set keyed by path/`onMark({range})` shift-ranges/`onSelectAll`/`onClearSelection`, tri-state `[x]/[-]/[ ]` header checkbox over SHOWN rows, EACCES rows unmarkable, Ctrl/Cmd+A in-grid) + density modes (`density` list/compact/thumb + `onDensity` radiogroup; thumb tiles via `FileCell` with lazy `thumbUrl` images) + new `BulkBar` export (`{count,noun,nounPlural,actions,onClear,busy}`, pluralizes `-y` nouns). App: `state.files.marked` (cleared on dir change, pruned on refresh), BulkBar -> armed `bulk-delete` ConfirmDialog -> `Promise.allSettled` over the confined delete (failures STAY selected + count in dialog), Escape clears selection (ladder slot after stop-arms), density persisted in `agentgui.files`. **thumbUrl uses `downloadUrl` (fsAllowRoots) NOT `imageUrl` - `/api/image` has its own narrower allowlist and 403s repo files; `<img>` ignores the attachment disposition.**
60
-
61
- **Shipped-jank fixes the witness caught.** (1) `.ds-file-open` (run 5) never had CSS - FileRow's UA-styled button sat in a grid sized for the old flat children; row+open are now flex strips with a full button reset. (2) filesMain DROPPED `permissions` in its entry mapping - the EACCES/read-only affordances were dead on the files tab. (3) The Crumb narrow collapse keys on the `.app` @container which doesn't exist under WorkspaceShell -> `.crumb-right` overflowed 420px viewports (h-scroll); mirrored into the `.ws-*` 900px media block. (4) webjsx attr-diff can leave a null-valued attribute unset when toggling - `data-density` is now always concrete. (5) F3 elevation unification: `.panel` = bg-2 + hairline + r-2 (no `--panel-shadow`), seg-control is-on = inset ring, chat image/pdf/link hover lift shadows dropped; overlay shadows (modal, jump pill) stay.
62
-
63
- **Env/tooling.** `scripts/validate-mutations.mjs` is now portable (ROOT from env/cwd, sep-aware joins, posix traversal targets, Bearer from PASSWORD; csrf case expects 401 under PASSWORD / 403 open) - 17/17 PASS on this env. Browser witnessing here: plugkit's chromium needs `--no-sandbox` (written to `/etc/chromium.d/no-sandbox`); `page.goto` waits on hung CDN subresources so use `waitUntil:'commit'` + `waitForSelector`; the witness body is shell-interpolated (NEVER use `$(...)`/backticks - use `page.locator(...)`); same-URL `goto` with only a hash change does NOT reload (use `page.reload()` after re-vendoring).
63
+ Fixed PASSWORD-gated deploys never booting the SPA (static subresources carried no token, `agentgui_token` cookie now set on auth) and made Files a full command surface (multi-select, density modes, bulk delete). Full detail in rs-learn (recall "agentgui 11th run Files command surface PASSWORD-boot").
64
64
 
65
65
  ## GUI screen-real-estate layer (2026-06-12) — fluid columns + drag-resize handles
66
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.1003",
3
+ "version": "1.0.1005",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -37,6 +37,13 @@
37
37
  <link rel="modulepreload" href="./js/backend.js">
38
38
  <link rel="modulepreload" href="./js/codec.js">
39
39
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
40
+ <!-- Preconnect alone still leaves the marked/dompurify ESM fetch+parse as a
41
+ full round trip AFTER the kit loads, on the first chat markdown render
42
+ (escaped-text -> rendered-markdown swap). modulepreload starts that
43
+ fetch in parallel with everything else instead of waiting for
44
+ markdown.js to reach its dynamic import. -->
45
+ <link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/marked@15.0.12/+esm" crossorigin>
46
+ <link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/+esm" crossorigin>
40
47
  <!-- No design content lives here. Every agentgui application-surface style
41
48
  (pills, cwd bar, resume banner, health chips, settings grid, history
42
49
  empty state, boot splash, scrollbar theming, focus rings, print) now
@@ -3075,14 +3075,18 @@ function serverPanel() {
3075
3075
  const roots = Array.isArray(hh.allowRoots) ? hh.allowRoots : [];
3076
3076
  const upMs = hh.uptimeMs != null ? hh.uptimeMs : (hh.uptime != null ? hh.uptime * 1000 : null);
3077
3077
  const wsClients = hh.wsClients != null ? hh.wsClients : (hh.clients != null ? hh.clients : null);
3078
+ // The very first health probe is in flight (not yet failed, not yet
3079
+ // succeeded): 'checking…' reads as progress, 'unknown' reads as a
3080
+ // permanent fact about the server - only the first is true here.
3081
+ const fallback = (hh.status === 'unknown' && state.healthChecking) ? 'checking…' : 'unknown';
3078
3082
  return Panel({
3079
3083
  id: 'server',
3080
3084
  title: 'server',
3081
3085
  children: [
3082
- h('div', { key: 'sv', class: 'lede' }, 'version: ' + (hh.version ? 'v' + hh.version : 'unknown')),
3083
- h('div', { key: 'sup', class: 'lede' }, 'uptime: ' + (upMs != null ? fmtDuration(upMs) : 'unknown')),
3084
- h('div', { key: 'swc', class: 'lede' }, 'connected clients: ' + (wsClients != null ? wsClients : 'unknown')),
3085
- h('div', { key: 'spd', class: 'lede' }, 'projects folder: ' + (hh.projectsDir || 'unknown')),
3086
+ h('div', { key: 'sv', class: 'lede' }, 'version: ' + (hh.version ? 'v' + hh.version : fallback)),
3087
+ h('div', { key: 'sup', class: 'lede' }, 'uptime: ' + (upMs != null ? fmtDuration(upMs) : fallback)),
3088
+ h('div', { key: 'swc', class: 'lede' }, 'connected clients: ' + (wsClients != null ? wsClients : fallback)),
3089
+ h('div', { key: 'spd', class: 'lede' }, 'projects folder: ' + (hh.projectsDir || fallback)),
3086
3090
  roots.length
3087
3091
  ? SessionMeta({ key: 'sroots', items: roots.map((r, i) => ({ label: 'root ' + (i + 1), value: r, title: r, onCopy: () => copyText(r, 'root copied') })) })
3088
3092
  : (hh.status && hh.status !== 'unknown' ? h('div', { key: 'snoroots', class: 'lede' }, 'allowed roots: none configured') : null),
@@ -3163,9 +3167,14 @@ function acpStatusFor(agentId) {
3163
3167
  function agentsPanel() {
3164
3168
  const installed = state.agents.filter(a => a.available !== false);
3165
3169
  const hasAcp = (Array.isArray(state.health.acp) ? state.health.acp : []).length > 0;
3170
+ // '0/0 installed' during the initial fetch reads as "nothing works", not
3171
+ // "still loading" - show the loading word instead until the list lands.
3172
+ const title = (state.agentsLoading && !state.agents.length)
3173
+ ? 'agents · loading…'
3174
+ : 'agents · ' + installed.length + '/' + state.agents.length + ' installed';
3166
3175
  return Panel({
3167
3176
  id: 'agents',
3168
- title: 'agents · ' + installed.length + '/' + state.agents.length + ' installed',
3177
+ title,
3169
3178
  children: [
3170
3179
  // ACP agents (opencode/kilo/codex) are managed automatically: started
3171
3180
  // on-demand and restarted with backoff by the server, so there are no
@@ -3439,7 +3448,13 @@ function startHealthPolling() {
3439
3448
  }
3440
3449
  async function recheckHealth() {
3441
3450
  const wasOk = state.health.status === 'ok';
3451
+ // Distinguishes "never probed yet" (status stays 'unknown', server panel
3452
+ // shows literal 'unknown' fields with no affordance) from "probe in
3453
+ // flight" - the settings server panel reads this to show 'checking…'
3454
+ // instead of a wall of 'unknown' during the very first health probe.
3455
+ state.healthChecking = true;
3442
3456
  const r = await B.probeBackend(state.backend);
3457
+ state.healthChecking = false;
3443
3458
  if (r.ok) {
3444
3459
  state.health = { status: 'ok', ...r.info };
3445
3460
  stopHealthPolling();