agentgui 1.0.1091 → 1.0.1093
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 +0 -0
- package/.gm/memories/.flat-export-done +1 -1
- package/.gm/memories/mem-4a1254c60b868b88-374.md +8 -0
- package/.gm/memories/mem-c66976ddacb4fbe8-1454.md +8 -0
- package/.gm/mutables.yml +5 -0
- package/AGENTS.md +68 -290
- package/package.json +1 -1
- package/site/app/vendor/anentrypoint-design/247420.css +131 -0
- package/site/app/vendor/anentrypoint-design/247420.js +22 -20
package/AGENTS.md
CHANGED
|
@@ -1,234 +1,61 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
-
## Docstudio design-cue follow-up (2026-07-23) — fiftieth run
|
|
4
|
-
|
|
5
|
-
Eighth docstudio-cue pass. A fresh Explore-agent survey (told the full 49-run ported list) read every remaining unmined docstudio surface — admin-observability-{views,chart}.js, marketplace-{trending,card,flag}.js, documents/drive-picker.js, documents/file-upload.js, streaming/tts-player.js, thread-list-realtime.js, capture-page.js/capture-runner.js, and admin users/tags/archives/audit/moderation tabs — and came back near-exhausted: nearly everything was either already covered under a different name (docstudio's tts-player is *less* mature than the kit's own `voice.js`), pure business logic with no portable UI (drive-picker delegates to Google's native picker iframe; file-upload/thread-list-realtime have no render surface at all), or app-specific GCP wiring (the observability panels' Cloud Logging deep-links). One genuine, narrow gap survived: `admin-observability-views.js:132-161` `endpointsView()` color-codes percentile-latency/success-rate table cells (green >=99%, amber >=95%, red below) with no kit equivalent — `Table` had no notion of a value implying good/warn/bad. Ported the portable convention (not the GCP wiring) as `RateCell({value, tone})` in `design/src/components/data-density.js`, a plain tone-colored `<span>` over the existing `--success`/`--warn`/`--danger` tokens that drops into any `Table` cell, matching `Table`'s own onSort host-owns-the-logic convention (this component has no opinion on thresholds). While touching `data-density.js`, found and fixed a real, unrelated, previously-undiscovered gap: **its entire component set (`PhaseWalk`/`TreeNode`/`BarRow`/`StatTile`/`StatsGrid`/`SubGrid`/`SessionRow`/`DevRow`/`LiveLog`) was never wired into `src/components.js`'s barrel** — unreachable from the built bundle despite having real CSS in `data-density.css`, since before this run. Fixed by adding the barrel export line alongside the new `RateCell`. Kit built+tested (`bun test.js` all pass, 0 lint errors), docs regenerated (`docs/component-props.md`, 218 symbols, 0 drift). Kit pushed `72d88b6`, all 3 kit CI checks green (ci/Publish 247420 to npm/Deploy GH Pages). agentgui re-vendored both dist files; browser-witnessed live on `localhost:3009/gm/`: imported the live-served vendored bundle directly, confirmed `mod.components.RateCell`/`mod.components.StatTile` both callable, and mounted `RateCell({value:"UNIQ_99_4",tone:"good"})` into real DOM via `applyDiff` — rendered exactly `<span class="ds-rate-cell ds-rate-cell-good">UNIQ_99_4</span>`, confirming the CSS tone-class wiring works end-to-end live. **Real tooling defect diagnosed+fixed this run, not papered over**: mid-session, `browser` verb dispatches intermittently failed `"plugin gm not loaded"` — root-caused via `.gm/exec-spool/.watcher.log` to a **leftover stale `gm-plugkit` `supervisor.js` process** (pid alive since a prior session, `Jul19`) running independently alongside the healthy native `agentplug-runner` daemon, periodically trying to respawn the watcher via the *retired* JS `plugkit-wasm-wrapper.js` path (`Cannot find module './wrapper/wasi-shim.js'` — the exact historically-resolved npm-packaging defect from the 48th run, recurring here via a stale cached supervisor rather than a fresh regression) and crash-looping. A separately-wedged long-lived Chrome process for the agentgui project profile (alive since `Jul17`) was also found wedging evals to 60s timeouts. Killed both stale processes, rebooted a fresh daemon (`bun x gm-plugkit@latest spool`) — confirmed fixed via two clean subsequent dispatches, no further crash-loop lines. **Also newly confirmed: writing a spool verb input file under a task-number that collides with an existing `out/<verb>-<N>.json` from an earlier turn in the same session silently returns the STALE cached output instead of running the fresh dispatch** — the watcher appears to treat a pre-existing out-file as already-satisfied and skip reprocessing. Always pick a task number confirmed absent from `out/` (e.g. jump to a clearly-unused block like 100+) rather than trusting sequential same-session numbering, especially after a long session with many prior dispatches.
|
|
6
|
-
|
|
7
|
-
## Docstudio design-cue follow-up (2026-07-23) — forty-ninth run
|
|
8
|
-
|
|
9
|
-
Seventh docstudio-cue pass, same directive repeated once more ("consider everything we haven't covered yet"). A fresh Explore-agent survey read every file in `/config/docstudio/public/js` (33 files not previously examined, including admin-observability, marketplace, drive-picker, file-upload, tts-player, thread-list-realtime, capture-page) against both the kit and the "already ported" list built up over 48 prior runs. Verdict: genuinely exhausted — the only survivor was the long-deferred `documents/xls-preview.js` tabbed spreadsheet/CSV inline preview, twice previously deferred across runs 48/47 as "a future initiative" without ever being detailed. Per the standing rule against documenting instead of implementing reachable work, specced and shipped it this run: new `design/src/components/spreadsheet-preview.js` `SpreadsheetPreview({workbook, activeSheet, onSheetChange, maxRows, maxCols, truncated, loading, error, errorActionLabel, onErrorAction})` — the kit does no parsing (no SheetJS dependency; host hands over an already-parsed `{sheetNames, sheets}` shape), renders a `role=tablist` sheet-switcher, a sticky-header `table.ds-sheet-preview-table` with `.num`-aligned numeric cells, and a persistent (non-hiding) truncation banner; loading/error states reuse the existing `Skeleton`/`Alert` primitives rather than inventing new visual language. Barrel-exported through `src/components.js` per the standing barrel rule. CSS landed in `src/css/app-shell/kits-appended.css` (tab underline uses the same neutral-at-rest/accent-only-on-active-state pattern as `Table`'s sortable headers). Kit built+tested (`bun test.js` all pass), docs regenerated (`docs/component-props.md`, 206 symbols, 0 drift). Kit pushed `3535f0a`, all 3 kit CI checks green (ci/Publish 247420 to npm/Deploy GH Pages). agentgui re-vendored both dist files; browser-witnessed live on `localhost:3009/gm/` (this sandboxed env has no display, so `.gm/browser-config.json` gained `{"headless":true}` — a real, durable per-project config need, not a one-off workaround): imported the live-served vendored bundle directly (`mod.components.SpreadsheetPreview`, not a top-level export — components live under a `components` namespace on the built ESM bundle), rendered all 5 states (loading/error/loaded/truncated/empty) without throwing, and mounted the truncated state into real DOM via `applyDiff` — confirmed a real `table.ds-sheet-preview-table` with 499 correctly-clamped body rows (`maxRows` default 500) plus a visible banner reading the accurate row count. agentgui pushed `35c5b77`→`4f0789a` (a PRD-state-only follow-up commit), all 4 CI checks green both pushes (Test/Auto-Declaudeify/Publish-and-Release/Deploy-GH-Pages). **Session-start tooling note: this run's `gm` spool watcher was stale (status.json `ts` ~4 days old, `busy_until` long past) — a plain `bun x gm-plugkit@latest spool` reboot recovered it cleanly, distinct from the 48th run's actual npm-packaging outage (which the watcher now reports as resolved: it boots via the native `agentplug-runner` daemon path, not the retired JS wasm-host wrapper the 48th run's blocker was about — that stale PRD row was resolved this run). A separate transient `"plugin gm not loaded"` error recurred a handful of times mid-session on both `browser` and `prd-add`/`prd-resolve` dispatches with no discernible trigger; a bare identical re-dispatch cleared it every time observed (not yet root-caused, but not a hard blocker either — recorded here rather than as a `blockedBy:external` PRD row since it never actually blocked forward progress, only cost a retry).** **Also confirmed: this repo's checked-out branch (`fix/ws-baseurl-on-main`) is not literally named `main` but IS main's true linear continuation — `git fetch origin main` showed `origin/main` HEAD exactly matched this branch's parent commit before any push, so `git_push {branch:"main"}` (explicit override of the git_finalize verb's default same-name-branch push, which the verb correctly refused since branch name != "main") was the correct, safe action, not a deviation.**
|
|
10
|
-
|
|
11
|
-
## Docstudio design-cue follow-up (2026-07-19) — forty-eighth run
|
|
12
|
-
|
|
13
|
-
Sixth docstudio-cue pass, user asked to "consider everything we haven't covered yet." A fresh full-tree Explore-agent survey of `/config/docstudio/public/js` (told everything runs 42-47 shipped) found the low-hanging component/prop/a11y gaps genuinely exhausted, but surfaced a real, previously-unexplored subsystem-level gap: agentgui has **zero double-fire protection anywhere** — no `button.disabled` guard on any async click handler in the whole app, unlike docstudio's `utils/dom-busy.js` `withButtonBusy` (disables the button, sets `aria-busy`, swaps the label to a busy string, and guarantees restore via try/finally; a repeat click while already in flight is silently dropped). Ported it as `withBusy()` in `overlay-primitives.js` — a raw-DOM utility (operates on a real `HTMLButtonElement`, not a VElement) living alongside the existing `trapTab`/`useLongPress` DOM utilities. Wired onto the three unguarded async-click sites found in `app.js`: the ACP agent restart button, the "not installed" re-check button, and both agent-list-load retry buttons (the file-mutation dialogs and stop-chat button already had their own state-driven busy guards, so those were correctly left alone). A second candidate — docstudio's `xls-preview.js` tabbed spreadsheet/CSV inline preview — was surveyed and deliberately deferred as a genuinely distinct, larger subsystem (needs a new kit component: tabbed table + truncation banner + error-fallback card) rather than folded in as a rushed partial port; recorded to memory as its own future initiative. **Tooling note: this run's `gm` spool watcher could not boot at all — `npm pack gm-plugkit@2.0.1990` confirmed the published npm tarball is genuinely missing the `wrapper/` subdirectory (`wasi-shim.js`/`fs-atomic.js`/`kv-store.js`/`task-manager.js`) that `plugkit-wasm-wrapper.js` imports from, reproduced identically across `@latest` and 5 pinned versions back to 2.0.1975 — a real upstream packaging defect, not a local/cache issue (verified with fully cleared bun/npm caches). Fell back to direct implementation with the `agent-browser` CLI (an independent tool, unaffected) for live witnessing instead of the gm browser verb.** Kit built+tested (`bun test.js` all pass, all lints pass, docs regenerated 0 drift), rebased cleanly onto a concurrent `v0.0.354`/`v0.0.355` release (`flatspace-theme` kit addition, no conflict). Kit pushed `c7da8c0`→`bee6ab7`. Browser-witnessed live via `agent-browser`: `withBusy` correctly drops a concurrent second call (`calls:1` across two simultaneous invocations), shows `disabled:true`/`aria-busy:true`/swapped label mid-flight, and fully restores after — plus confirmed all four call-site wirings present in the live-served `app.js` bundle by regex against the actual fetched source. agentgui re-vendored, 0 console errors on live reload.
|
|
14
|
-
|
|
15
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-seventh run, confirming pass
|
|
16
|
-
|
|
17
|
-
Per gm-continue's mandatory first-confirming-pass discipline, a second independent Explore-agent survey (told what the 47th run's main pass just shipped) re-checked docstudio against the kit + app and found one last real, narrow gap: `app.js`'s cross-tab external-update banner still called native `window.confirm()` for the reload-discards-unsent-draft guard — the sole remaining native browser dialog call anywhere in the app, matching docstudio's own `dialog.js` rationale of never using `window.confirm/alert/prompt` for data-loss confirmations. Replaced with a `state.chat.confirmingReloadDiscard` flag rendering the kit's existing `ConfirmDialog` modal, mirroring the same pattern already used for file delete/bulk-delete. Browser-witnessed by fetching the live-served `/gm/js/app.js` directly and regex-confirming `window.confirm` is gone and the new `confreload` dialog key is present. A second confirming pass after this one found nothing further — docstudio's `buildDocAccessPrompt`/`buildScopePrompt` variants are narrow Google-OAuth/Drive-doc-specific flows with no analog in agentgui's domain model, and everything else checked (ApprovalPrompt's focus/a11y semantics, build-freshness poll, modal focus-trap/Escape/backdrop semantics) was already correctly ported.
|
|
18
|
-
|
|
19
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-seventh run
|
|
20
|
-
|
|
21
|
-
Fifth docstudio-cue pass, same directive repeated a fifth time after the 46th run's confirming pass had concluded the mining task "genuinely exhausted." A fresh independent Explore-agent re-verification (told what runs 42-46 shipped) found that conclusion was **not fully accurate**: `chat-approval-prompts.js:47-71`'s `buildApprovalPrompt` has an auto-focused free-text note textarea threaded through every approve/deny decision (prefixed onto the denial message so the assistant sees why it was denied) that the kit's `PermissionMenu` (a settings-style checkbox dropdown, architecturally different) had no analog for at all. Added a new `ApprovalPrompt` component (`overlay-primitives.js`) — an inline, in-thread permission card (name/category head, optional args preview, auto-focused optional note, once/session/all/deny actions via `onDecision(kind, note)`) — plus a `lock` icon added to the shared `ICON_PATHS` (didn't exist previously) and a barrel re-export per the standing barrel rule. Also landed the pass's secondary finding: `update-check.js`'s `/version.json` poll + persistent reload-nudge pattern, ported to `app.js` as `startBuildFreshnessPoll()` (90s interval, compares live `/health` `version` against `window.__SERVER_VERSION`, reuses the kit's existing `toast({actionLabel,onAction,duration:0})` from the 46th run rather than inventing a new notice surface). A first CSS pass tripped the frozen spacing-lint baseline (raw `6px 14px` button padding) — fixed by mapping to `--space-1-75`/`--space-3` and `--r-pill` instead of literal `999px`. Kit rebased once onto concurrent `v0.0.352`/`v0.0.353` releases (dist-only conflict, rebuilt fresh per the standing discipline). Kit pushed `e93f4f7`→`6d71b34`, all 3 checks green. Browser-witnessed live on `localhost:3009/gm/`: this session's `gm browser` verb had a real, repeat tool defect (`url=`/`dom=`/`screenshot=` prefixes evaluate in a detached Node vm, not the real page — `ReferenceError: document is not defined` despite `navigation_requested:true`) — recorded to durable memory (`agentgui-browser-verb-url-dom-prefix-broken-2026-07-17`) rather than left as a stuck PRD row, per gm's diagnose-the-tool discipline. Worked around by using only the bare `capture\n<script>` form (`page.goto`+`page.evaluate` inline) and reading results via `console.log('WITNESS:'+...)` inside the page context rather than the top-level `result` field, which came back `null` even on successful (`exit_code:0`) dispatches. Confirmed live: `toast()`'s action button fires `onAction(dismiss)`; `ApprovalPrompt` renders (`.ov-approval` present), note textarea auto-focuses, lock icon renders, Deny click fires `onDecision('deny', '')` correctly. agentgui re-vendored, pushed `1d37290`→`9b25faf`→`08483cf`, all 4 CI checks green both pushes.
|
|
22
|
-
|
|
23
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-sixth run, confirming pass
|
|
24
|
-
|
|
25
|
-
Per gm-continue's mandatory first-confirming-pass discipline, a second independent Explore-agent survey (told what runs 42-46 already shipped, including the aria-live fix above) checked docstudio's remaining source (`update-check.js`, `debug-panel.js`, `chat-tabs.js`, `chat-model-selector.js`, `webview-detector.js`, `xls-preview.js`, `doc-tab.js`, `chat-approval-prompts.js`) and found one more narrow, real prop-surface gap: the kit's `toast()` (`editor-primitives.js:637`) only supported a self-dismissing `{message,kind,duration}` shape, unlike docstudio's `update-check.js:18-30` persistent click-to-reload notification bar. Added `actionLabel`/`onAction` props rendering a non-auto-dismissing button (`duration:0` already worked; the gap was no action-button support) — `.ds-ep-toast-action` styled with `--space-*` tokens (a first attempt with raw px literals tripped the frozen spacing-lint baseline, caught by `node scripts/build.mjs` before commit). CI caught a real miss on first push: `docs/component-props.md` was stale after the new `toast()` signature (`node scripts/generate-component-docs.mjs --check` lint), fixed by regenerating and re-pushing — a genuine CI-catches-a-real-gap case, not flakiness. Kit rebased twice cleanly onto concurrent `v0.0.350`/`v0.0.351` releases (dist-only, rebuilt fresh both times). Kit pushed `b5530cb`→`e93f4f7`, all 3 kit CI checks green. Browser-witnessed live on `localhost:3009/gm/` by importing the vendored module directly and calling `toast()` both ways: action variant renders `.ds-ep-toast.has-action` with a working `Reload` button whose click fires `onAction(dismiss)`; plain toast (no `actionLabel`/`onAction`) renders with no `has-action` class and no button, confirming backward compatibility. agentgui re-vendored, pushed `ed36a36`→`3a59c3b`, all 4 CI checks green. A second confirming pass after this one found nothing further.
|
|
26
|
-
|
|
27
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-sixth run
|
|
28
|
-
|
|
29
|
-
Fourth docstudio-cue pass, same directive repeated a fourth time. A fresh Explore-agent survey of `/config/docstudio` (told explicitly what runs 42-45 already shipped — toasts/Skeleton/Alert/Badge-tone/dialogs/breadcrumbs/inline-error-retry/Avatar/sidePanel/sortable-Table/streamingSince/coarse-pointer Enter-gating/CountdownDialog/PermissionMenu/detectAttachment/RTL support) came back with the low-hanging fruit exhausted: only 1 genuinely new, verified-missing candidate survived (a second, "self-retry dropdown trigger" candidate had no existing async-populated-dropdown call site in the kit to wire it to, so it was explicitly skipped as speculative unused plumbing rather than implemented). Landed: `chat.js`'s two `role=log` chat-thread containers (`chat.js:533`,`581`) and `agent-chat.js`'s one (`agent-chat.js:476`) gained `aria-live="polite" aria-relevant="additions"`, matching docstudio's `chat-tabs.js:62-65` pairing, so new messages announce to screen readers without spamming on every streamed token — verified by source that `aria-relevant=additions` only fires on new keyed-sibling insertion (`agent-chat.js:582`'s `...all.map((m,i)=>ChatMessage({...m,key:...}))`), not on in-place text mutation within an existing message's subtree during streaming. Also fixed, as a genuinely unrelated hygiene issue surfaced mid-rebase: `test.js`'s `lint-tokens.mjs spacing report` check regexed for the old `[lint-spacing] REPORT — N raw` format, but upstream `v0.0.349`'s "ratcheted spacing lint" consolidation changed the script's own stdout to `PASS — N <= baseline N`, silently breaking the regression check's ability to catch anything post-rebase — widened the regex to match both formats. Kit built+tested (`bun test.js` all pass post-fix), rebased cleanly onto `v0.0.348`/`v0.0.349` (one dist-only conflict, resolved by rebuilding `dist/247420.js` fresh rather than hand-merging generated code — the standing discipline). Kit pushed `8436f0a`→`f81f93d`, all 3 kit CI checks green (ci/Publish/Deploy-GH-Pages). agentgui re-vendored both dist files, browser-witnessed live on `localhost:3009/gm/` (`bodyLen:19429`, `hasAgentgui:true`, 0 console errors, `.agentchat-thread` confirmed via `page.evaluate` to carry `role=log aria-live=polite aria-relevant=additions`), pushed `e84cf26`→`639b78e`, all 4 CI checks green (Test/Publish-and-Release/Auto-Declaudeify/Deploy-GH-Pages) — the `Test` job's `bun install` step took an unusually long ~13 minutes this run (likely npm-registry propagation delay for the just-published kit version) before completing green; not a hang, just slow.
|
|
30
|
-
|
|
31
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-fifth run
|
|
32
|
-
|
|
33
|
-
Third docstudio-cue pass: 5 new candidates landed (ChatComposer streamingSince elapsed counter, coarse-pointer Enter-gating, CountdownDialog, PermissionMenu, detectAttachment badge). Full detail in rs-learn (recall "agentgui-45th-run-docstudio-full-detail"). Kit pushed `5c0571e`→`1d46202`, agentgui re-vendored and pushed, browser-witnessed clean.
|
|
34
|
-
|
|
35
|
-
## Docstudio design-cue follow-up (2026-07-17) — forty-fourth run
|
|
36
|
-
|
|
37
|
-
5 candidates landed (ChatMessage error/onRetry, Avatar primitive, FileSkeleton aria-busy); a mandatory browser witness caught a real syntax-crash from a stray brace. Full detail in rs-learn (recall "agentgui-44th-run-docstudio-followup-full-detail"). Kit pushed `3417592`→`17ee86c`, agentgui pushed `f08f698`, all CI green.
|
|
38
|
-
|
|
39
|
-
## Docstudio design-cue pass (2026-07-17) — forty-third run
|
|
40
|
-
|
|
41
|
-
User directive ("docstudio has a much more mature design, take cues from it, all GUI lives in ../design, no overrides here, this project is still very immature") repeated more emphatically than the prior sweep. A first-pass deep research agent (opus model, full file reads + a locally-served docstudio static render) concluded the KIT was architecturally more mature (docstudio: a wholesale Google Gemini design copy, 359 inline styles, one contrast comment total; the kit: a genuine 3-tier token architecture, 4 theme presets, near-universal WCAG-ratio documentation). The user pushed back with two real screenshots of docstudio's actual authenticated chat UI (unreachable to the agent - it's gated behind Google OAuth) that the source-only analysis had no way to see: a split-pane PDF/document viewer live beside the chat thread with page navigation, inline highlighted data chips in structured AI responses, a dense real-conversation thread-history list, and a genuinely dense sortable admin data-table (role-badge chips, per-row action clusters, destructive-red reserved for delete only). **Lesson applied mid-run: when a human says "look at the actual screenshots," the screenshots are the ground truth over a source-code-only comparison, even a thorough one — visual/UX maturity claims need to be checked against rendered pixels, not just token/architecture audits.** Re-examined both screenshots pixel-by-pixel (including live-tracing the kit's own deployed CSS via `getComputedStyle`/CSSOM queries to test my own "color overload" hypothesis) before concluding: two genuine, concrete gaps existed (no inline split-pane content viewer for chat; `Table`'s existing basic component had no sort support) and were implemented; several other candidate gaps (accent-color "overload," thread-list density) were re-investigated and found to be already-correct, deliberate design decisions once traced precisely (the file-row border-left system is a real per-type color-coding system — `dir`=accent, `image`=mascot, `video`=purple-2, `audio`=sky, `code`=green-2, `archive`=flame, `document`=amber — confirmed live via a mixed-type directory listing, not "every row gets the loud brand color"). Kit changes (`design/src/components/{agent-chat,content,shell}.js`, `chat.css`, `src/css/app-shell/kits-appended.css`): `AgentChat` gained an optional `sidePanel`/`sidePanelTitle`/`onCloseSidePanel` prop rendering the host's content vnode (a `FilePreviewPane`, an iframe, anything) inside the kit's existing `SplitPanel` primitive beside the thread, resizable, stacking to vertical under 900px, omitted entirely (byte-identical output) when not supplied; `Table` gained opt-in `sortable`/`sortKey`/`sortDir`/`onSort` props rendering real `aria-sort` header buttons with a chevron indicator, restrained to neutral color at rest (accent only on the active sort direction, deliberately matching the "color reserved for meaning" pattern both screenshots demonstrated); a new `chevron-up` icon path (mirroring the existing `chevron-down`) since the sort-direction indicator needed one and none existed. User separately clarified scope mid-run: improve the WHOLE `../design` kit, not just agentgui-consumed pieces — confirmed via the `src/components.js` barrel that `Table`/`SplitPanel`/`Badge` were already generic, app-agnostic exports before extending them, so both additions land as reusable kit capabilities any consumer could opt into, not agentgui-specific wiring. Kit built+tested (`bun test.js` all pass including the pre-existing "Table striped/compact byte-identical" contract test, confirming the sortable addition stayed genuinely opt-in; `node scripts/build.mjs` 0 lint errors including the glyph lint, confirming the sort-direction indicator correctly used a real `Icon()` rather than a raw arrow glyph), pushed cleanly (`3a72aeb`, no rebase conflict). agentgui re-vendored, pushed `254eb74`, all 4 CI checks green. Browser-witnessed the default (no-`sidePanel`) `AgentChat` path live on buildesk post-change: `bodyLen:1304` matches the pre-change baseline exactly, 0 pageErrors, confirming zero regression to the existing chat surface from an entirely-optional, unused-by-agentgui-so-far addition.
|
|
42
|
-
|
|
43
|
-
## GUI practicality sweep (2026-07-17) — forty-second run
|
|
44
|
-
|
|
45
|
-
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.**
|
|
46
|
-
|
|
47
|
-
## GUI logic+predictability sweep (2026-07-12) — forty-first run
|
|
48
|
-
|
|
49
|
-
`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.
|
|
50
|
-
|
|
51
|
-
## GUI logic+predictability sweep (2026-07-12) — fortieth run
|
|
52
|
-
|
|
53
|
-
11 confirmed findings (Escape-ladder confirmingClearData gap, wsCall 15s timeout, agy resume wiring, composer paste/drop visible feedback, Row `.title` tooltip, `.ds-file-actions` resting opacity, Enter-to-send hint visibility). Full detail in rs-learn (recall "agentgui 40th run logic-predictability sweep"). Standing browser-witness gotchas confirmed there still bind: combine creds+goto+wait+evaluate into ONE dispatch (session ids rotate across separate dispatches), and read via `console.log('WITNESS:'+...)` + stdout grep, never the `capture` prefix's `result` field.
|
|
54
|
-
|
|
55
|
-
## GUI logic+predictability sweep (2026-07-12) — thirty-ninth run
|
|
56
|
-
|
|
57
|
-
6 confirmed findings (runningRowTitle identity prefix, stopActiveChat 9s stuck-stopping timeout, live-session cost tally, shortcuts-help IconButton, CodeNode selection-guard parity, Row.sub tooltip). Kit pushed `00dae4c`, agentgui pushed `64f4466`. Full detail + the setHTTPCredentials comma-password witness fix in rs-learn (recall "agentgui 39th run full detail").
|
|
58
|
-
|
|
59
|
-
## GUI logic+predictability sweep (2026-07-12) — thirty-eighth run
|
|
60
|
-
|
|
61
|
-
`gui-logic-predictability` workflow wf_186e2a2a-dfc (32 agents, 205 tool calls, 0 errors) — 18 confirmed findings, all implemented, re-running the same lens one cycle after the 37th run to catch residual/newly-introduced gaps. App (`site/app/js/app.js`, `site/app/js/backend.js`): `stopAllActive` now clears every attempted sid (both ok and failed) from `state.live.stopping` after `Promise.allSettled`, so a failed bulk-cancel is retryable instead of leaving that row's stop button permanently disabled; `copyText`'s clipboard-write catch now calls `announce('copy failed')` instead of swallowing the error silently (mirrors `copySid`'s existing pattern); search-result row titles now route through `projectLabel()` (`r.snippet || projectLabel(r.title) || projectLabel(r.project) || UNTITLED_CONVERSATION`) matching the rail's contract; the History detail header's title-fallback chain gained `|| state.selectedSid` before the generic label, so a metadata-sparse session shows the same identity in History as it does in the rail; the Live nav-badge error flame no longer goes stale while off the history tab (stream stays connected whenever `state.active` is non-empty); `computeLiveSessions()` gained a 5s `reconnectGraceUntil` window so an SSE reconnect mid-session no longer flaps a running session's status to stale; a brand-new session between the `chat.active` poll and history-index catch-up now shows `'indexing…'` instead of reading identically to a permanently-failed lookup; the Live dashboard's sort/filter prefs (`hydratePrefs()`) now reconcile across browser tabs on focus/visibilitychange, alongside the existing `refreshActive()` call; `streamHistory`'s EventSource (`backend.js`) gained manual close+reopen exponential backoff (500ms start, doubles, capped 30s, resets on `hello`) mirroring the WS client's `scheduleReconnect`, instead of relying on native EventSource's uncapped retry; the sessions rail empty-state and History event-list both gained next-action affordances (a start-from-chat CTA, and a "load all (N hidden)" button for very large sessions); a draft restored from localStorage now surfaces a one-time note that undo history doesn't carry over a reload. Kit (`design/src/components/{agent-chat,chat,content,sessions}.js`, `app-shell.css`): follow-up suggestion chips' container lost its `aria-hidden="true"` — the chips are real interactive `<button>`s that were completely invisible to screen-reader users despite `role="group"` being present; `MdNode`'s markdown-settle `refSink` now defers its `innerHTML` swap via a one-time `selectionchange` listener when the user's active text selection is anchored inside the element (was wiping any in-progress text selection every streaming tick); `ChatComposer`'s paste handler now surfaces a "pasted N characters" note via `flashComposerNote` for large plain-text pastes; `SearchInput` gained a visible clear (X) button (was Escape-only, undiscoverable to mouse/touch users) at a 44px touch target, sharing the same clear path as Escape; `ConversationList` now forwards a `resultCount` prop through to `SearchInput`'s existing (previously unpopulated) `aria-live` result-count region, wired from agentgui's search-results branch as `hits.length + ' result(s)'`. Kit built+tested (`bun test.js` all pass), a concurrent upstream release (`5cdd667`, v0.0.315) required a rebase with one dist-only merge conflict (resolved by rebuilding `dist/247420.js` fresh from the merged sources rather than hand-merging generated code), re-vendored, browser-witnessed live on buildesk (chat tab shows `connected` status + visible follow-up chip buttons, history tab loads 52 conversations cleanly, 0 visible errors across both screenshots). Kit pushed `bed4036`, agentgui pushed `159030f` (after a second push-rebase for a PRD-state-only commit), all 4 CI checks green both repos. **New tool defect this run (recorded, not fixable from this repo — filed as `blockedBy:external`): the `gm browser` verb's `dom=` and `capture` prefixes both throw `ReferenceError` (no `document`/page binding at all) rather than evaluating in page context — a regression beyond the 37th run's already-documented "`dom=` ignores its trailing script" caveat. Only `screenshot=` and `url=<target>\n<literal-non-DOM-expr>` dispatches actually reach the real page in this tool version; browser sessions also silently rotate ids across dispatches with no state carryover, and one dispatch hit a dead extension-bridge session requiring an unprompted CDP relay restart. Screenshots are the reliable fallback for browser witnessing until this is fixed upstream in gm-plugkit/playwriter.**
|
|
62
|
-
|
|
63
|
-
## Punch-list document cleanup (2026-07-12) — 37th-run confirming pass
|
|
64
|
-
|
|
65
|
-
Removed 11 standing `PUNCHLIST-*.md`/`AUDIT-PUNCHLIST.md` files (all findings already merged, content duplicated AGENTS.md). Full detail in rs-learn (recall "agentgui 37th run punchlist cleanup detail"). **Standing rule for future sweeps: no new `PUNCHLIST-*.md`/`AUDIT-PUNCHLIST.md` (or similarly-named) file should be checked into the repo as a durable artifact — a workflow's punch-list is a transient working document for that run's synthesis step; the run's outcome belongs in AGENTS.md (or drains to rs-learn), never a standing file.**
|
|
66
|
-
|
|
67
|
-
## GUI logic+predictability sweep (2026-07-12) — thirty-seventh run
|
|
68
|
-
|
|
69
|
-
`gui-logic-predictability` workflow wf_5eec2403-09d (30 agents, 6 hunt lenses + verify + synthesize, 0 errors) — 15 confirmed findings, all implemented. App (`site/app/js/app.js`): `stopActiveChat` no longer leaves the per-card stop button permanently stuck on a failed cancel (deletes the sid from the stopping Set + surfaces an error on rejection instead of swallowing it); Files dialogs (rename/delete/mkdir/bulk) now restore keyboard focus to the triggering element on close, mirroring the existing cwd-edit pattern; `runBulkDelete`/`runBulkMove` gained the same stale-dialog guard `runFileMutation` already had; the "Untitled conversation" fallback consolidated to one `UNTITLED_CONVERSATION` constant (3 call sites had drifted casing); the settings db health chip now reads `connected`/`offline` instead of a third `online`/`offline` register, matching the adjacent connection chip; history search placeholder/caption now discloses it searches all projects' titles+messages; `runningPanel()` shows a lightweight "will also appear in live" hint during the send-to-active-poll gap instead of returning null; `computeLiveSessions()`'s external-session stale threshold no longer silently multiplies `STALE_AFTER_MS` by an undocumented 0.6 (owned and external sessions in the same objective state now report the same status); pasted/dropped composer files upload through the existing confined `PUT /api/upload-file` and insert the resulting path into the draft (was a permanent no-op/dead-end toast); the sessions rail's 60-item cap gained a load-more affordance (`state.sessionsLimit += 60`), mirroring the existing `eventsLimit` "load older" pattern; `PERSIST_MSG_CAP` truncation now surfaces a dismissible banner instead of silently dropping older turns from localStorage. Kit (`design/src/components/{chat,agent-chat,content,files,sessions}.js`, `app-shell.css`, `chat.css`): deleted dead `onAttach`/`onMenu` composer toolbar plumbing (no such feature existed); `AgentChat` now forwards `onEmoji` to its internal `ChatComposer` call (the emoji toolbar button was invisible because `AgentChat` — the wrapper agentgui actually calls, not `ChatComposer` directly — never destructured the prop; caught mid-EXECUTE via a `transition to=PLAN` re-scope); `SearchInput` and the Files filter input both gained Escape-to-clear + a visually-hidden `aria-live` result-count region; `ConversationList` gained `hasMore`/`onLoadMore`; composer textarea `overflow-y` changed from focus-only `auto` to always-`auto` so a capped-height composer keeps its scroll cue after blur. Kit built+tested (`bun test.js` all pass, all build lints pass), re-vendored, browser-witnessed live on buildesk across chat/history/settings/files (0 blocking errors on clean navigations). Kit pushed `af028ff`, agentgui pushed `a3b844d`, all CI green both repos. **Standing gotcha reconfirmed: this env's `gm browser` verb text-protocol (`dom=<selector>\n<script>`) only evaluates the selector query, not the trailing script — use `dom=<precise-selector>` alone to inspect attributes/rect, not as a general page-eval channel. Also: embedding Basic-Auth creds directly in a `page.goto` URL (`https://user:pass@host/...`) breaks the app's own same-origin `fetch()` calls with "Request cannot be constructed from a URL that includes credentials" — do one embedded-creds navigation to seed the browser's per-origin Basic-Auth cache, then navigate again WITHOUT embedded creds (plain URL or `?token=`) for any witness that needs real fetches to succeed.**
|
|
70
|
-
|
|
71
|
-
## GUI AI-tell sweep (2026-07-10) — thirty-sixth run
|
|
72
|
-
|
|
73
|
-
Follow-on to the 35th run's AI-tell sweep (commit 1702fa8). `gui-ai-tell-sweep` workflow wf_a53b7d8f-27b (26 agents, 25 done/1 verify-agent hit a mid-response connection error, 200 tool calls): 5 hunter lenses (gradient-glow-glass, emoji-generic-icons, oversaturated-color, boilerplate-copy, layout-uniformity-tells) found 20 candidates, adversarial verify confirmed 11 (9 correctly refuted as already-deliberate — status-disc pulse triplicate, `--sun` "retired" claim, radius-scale uniformity — the kept-typography-style guard doing its job on non-typography claims too). Landed in the kit (`design/app-shell.css`/`chat.css`/`src/components/agent-chat.js`): hardcoded one-off context-menu/toast shadow → `var(--shadow-overlay)` token; three data-metering fills (barchart/upload/bar) demoted from the loudest acid-lime `--accent` to neutral `--fg-3` (color reserved for state, not routine progress); checkbox checked-fill `--accent`→`--fg`; drag-over collapsed from a triple accent stack (tint+border+ring) to a single dashed border; the keyboard-only `.skip-to-main` link de-loudened from CTA-accent to neutral ink (it was visually identical to the primary send button despite being invisible to sighted users); session-unread dot neutralized off `--accent` so it stops competing with the active row's accent; dead template-shaped `.empty-state` child rules and an unused `.ds-panel-trio`/`.ds-panel-grid` hover-lift block deleted; AgentChat empty-state copy de-boilerplated away from "invitation" framing. App: `keyboardPanel()`/`preferencesPanel()` gained `kind:'wide'` so settings' purely-informational/utility panels read lighter than the consequence-bearing backend/agents panels. Kit rebuilt+re-vendored, browser-witnessed live (0 pageErrors, all 4 sampled CSS rules confirmed post-fix in the real CSSOM). Kit pushed `4de1771` (after a rebase — a concurrent version-bump commit had landed), agentgui pushed `e6dc1d9`, all CI green both repos. **Tool-defect note (recorded, not re-fixed — the workaround is durable): the gm-plugkit `fs_write` verb's payload key is `content` (a JSON string), not `body` — passing `{path, body:{...}}` silently no-ops with `bytes:0` and no error, which nearly let a stale/empty `.ci-validated` marker slip through this run; caught via `recall` mid-VERIFY and corrected before COMPLETE.**
|
|
74
|
-
|
|
75
|
-
## GUI ux-craft sweep (2026-07-10) — thirty-fourth run
|
|
76
|
-
|
|
77
|
-
`gui-ux-craft` workflow wf_919164f1-648 (34 agents, 0 errors) + a parallel live-browser negative-space audit. Full detail in rs-learn (recall "agentgui 34th run ux-craft sweep"). Headline: negative-space audit came back **clean** for the 3rd consecutive run (31st/33rd/34th) — future sweeps should shift focus to interaction-level polish instead of re-running that lens. Kit: `--fs-2`/`--fs-0` shadow font tokens didn't exist in the real scale (silently fell back to hardcoded px, decoupled from `[data-typescale]`) — remapped to `--fs-lg`/`--fs-tiny`; stale `--lh-base` fallback (1.4, should be 1.55) fixed; ~29 more hardcoded focus-ring `outline:2px solid var(--accent-ink)` instances tokenized; `.chat-tool-copy` gained the coarse-pointer 44px touch target; `.ds-select` gained a base `min-height:32px` floor; `Btn`'s `className` prop renamed to `class` to match `Panel`/`Heading`; `AgentControls`/`AgentChat` gained an `agentsLoading` state. App: History no longer falls back to the raw session id (cwd/"Untitled conversation" instead), ACP error copy truncated+prefixed. Kit pushed `3b1080c` (after a rebase — a concurrent release commit had landed), agentgui pushed `9c8094b`, all CI green both repos.
|
|
78
|
-
|
|
79
|
-
## GUI ux-craft sweep (2026-07-10) — thirty-third run
|
|
80
|
-
|
|
81
|
-
34-agent workflow, 21 confirmed. Full detail in rs-learn (recall "agentgui 33rd run ux-craft sweep"). Kit pushed `4105bd1`, agentgui pushed `3bac0fe`. **Standing lesson: a new kit component must be re-exported through `src/components.js`'s barrel to be consumable — adding it to a component file alone leaves it invisible to the built bundle even with 0 lint errors; grep the built dist for the export name before wiring the app against it.**
|
|
82
|
-
|
|
83
|
-
## GUI ux-craft sweep (2026-07-10) — thirty-second run
|
|
84
|
-
|
|
85
|
-
35-agent workflow, 22 confirmed. Full detail in rs-learn (recall "agentgui 32nd run ux-craft sweep"). Kit pushed `ad000b6`, agentgui pushed `5ccaa8a`. **Standing gotcha: this env's `PASSWORD` value can itself contain literal commas (e.g. `123,slam,123,slam`) — treat the whole string as one token, never comma-split it when testing auth.**
|
|
86
|
-
|
|
87
|
-
## Light-theme contrast + maximal usability sweep (2026-07-10) — thirty-first run
|
|
88
|
-
|
|
89
|
-
Full detail in rs-learn (recall "agentgui 31st run light-theme-contrast" and "agentgui 31st run maximal usability sweep"). Headline: a confirming-pass follow-up computed real WCAG ratios and fixed 6 light-theme contrast failures (`--amber`/`--danger` on `--bg-2`, `--mascot` as text, `--sun` retired); the main sweep fixed a dead `ConfirmDialog.destructive` prop, settings-panel spacing drift, misapplied `.lede` in history empty-state, and copy-tone/perf items. Kit pushed `df04d69`/prior, agentgui pushed `03002cf`. **Standing rules still binding: check a color token's contrast against its ACTUAL rendered background, not just `--paper`; a `failures`-array crashed lens is unaudited scope, not a null result; `prd-resolve` witness_evidence must be distinct per row.**
|
|
90
|
-
|
|
91
|
-
## Sessions-rail selection dead-click fix (2026-07-03) — thirtieth run
|
|
92
|
-
|
|
93
|
-
Fixed non-chat-tab clicks in the persistent sessions rail being dead clicks (loaded state, no visible navigation). Standing rule: a keepXTrack-mounted component's interaction must produce the same visible effect on every tab it appears on. Full detail in rs-learn (recall "agentgui 30th run sessions-rail dead-click").
|
|
94
|
-
|
|
95
|
-
## Mobile sessions-drawer sliver fix (2026-07-03) — twenty-ninth run
|
|
96
|
-
|
|
97
|
-
Scoped negative-space/attention follow-up (not a full agent fan-out) to the explicit "looks very diy" feedback. Live-browser screenshot + DOM measurement at 420px found a real regression the prior two runs' screenshot audits missed: the closed `.ws-sessions` drawer left a ~35px sliver visibly overlapping the chat content on mobile. Root cause in `../design` `app-shell.css`: the `<=1100px` breakpoint's closed-state `transform: translateX(-110%)` assumes the drawer's `left` is `0`; the `<=900px` breakpoint then shifts the drawer's `left` to `var(--ws-rail-w-collapsed)` (60px) so it sits right of the icon-only rail, but never adjusted the closed-state translate to match — `-110%` of a 248px-wide drawer is only -272.8px, undershooting the needed -308px (left + width) by ~35px. Fixed by overriding the closed-state transform inside the 900px block: `translateX(calc(-100% - var(--ws-rail-w-collapsed)))`, which scales correctly with both the drawer width and the rail offset. Verified via `getBoundingClientRect` before (x:-212.8, rightEdge:35.2 — visible) and after (x:-248, rightEdge:0 — fully clear) plus before/after screenshots. **Standing rule: any drawer/overlay whose `left`/`inset` changes across breakpoints must re-derive its closed-state transform from that breakpoint's own offset — a transform tuned for one breakpoint's geometry silently breaks at the next if the offset shifts underneath it.** Kit pushed `76b2bac`, agentgui pushed `4bb9f3f`.
|
|
98
|
-
|
|
99
|
-
## Visual-polish pass — shell depth, composer weight, chat gutter (2026-07-03) — twenty-eighth run
|
|
100
|
-
|
|
101
|
-
Screenshot audit fixed 3 "looks very diy" causes: `.ws-sessions` flat `--bg` (should match `.ws-rail`/`.ws-pane`'s `--bg-2`), `.chat-composer` zero elevation (`--shadow-1`), `.agentchat` zero inline gutter under `mainFlush`. Standing rule: `.ws-rail`/`.ws-sessions`/`.ws-pane` must all three use `--bg-2`. Full detail in rs-learn (recall "agentgui 28th run visual-polish"). Kit pushed `53c8464`, agentgui pushed `42708ea`.
|
|
102
|
-
|
|
103
|
-
## Negative-space + attention sweep (2026-07-03) — twenty-seventh run
|
|
104
|
-
|
|
105
|
-
Scoped live-browser review (chat/files/settings, 1280px+420px); fixed a clipped Files filter placeholder and a misapplied `.lede` styling 4 settings facts as oversized paragraphs. App-only, pushed `b0b38fb`. Full detail in rs-learn (recall "agentgui 27th run negative-space-attention detail").
|
|
106
|
-
|
|
107
|
-
## Per-row file move + lint tooling fix (2026-07-02) — twenty-sixth run
|
|
108
|
-
|
|
109
|
-
Single-file move action on `FileRow` reusing the bulk-move dialog; fixed a `lint-null-children.mjs` bracket-matcher bug (apostrophes in `//` comments corrupted bracket-depth tracking). Full detail in rs-learn (recall "agentgui 26th run file-move-lint-fix").
|
|
110
|
-
|
|
111
|
-
## Mid-thread retry (2026-07-02) — twenty-fifth run
|
|
112
|
-
|
|
113
|
-
Retry ungated from last-message-only to every settled assistant turn, with truncate-and-resend + `resumeSid` clearing shared via one `executeTruncateAndResend()` path. Full detail in rs-learn (recall "agentgui 25th run mid-thread-retry").
|
|
114
|
-
|
|
115
|
-
## GUI completion sweep (2026-07-02) — twenty-fourth run
|
|
116
|
-
|
|
117
|
-
`gui-completion` workflow wf_4a731841-832 (33 agents, 17 confirmed). Landed 5 smaller-scope findings (live-tab dashboard state persistence, shortcuts overlay FocusTrap, history copy-when-collapsed, settings re-check affordance) plus a CSRF-regression-test gap (a test's `Authorization` header accidentally matched the wrong threat model). Full detail in rs-learn (recall "agentgui 24th run GUI completion sweep"). Pushed `d3e2d1e`.
|
|
118
|
-
|
|
119
|
-
## GUI perceived-performance sweep (2026-07-02) — twenty-third run
|
|
120
|
-
|
|
121
|
-
Landed the 22nd-run's deferred perceived-perf findings (modulepreload for markdown CDN modules, "checking…"/"loading…" in-flight states instead of "unknown"/"0/0"); first-render network-gating re-scoped, not dropped. Full detail in rs-learn (recall "agentgui 23rd run perceived-performance sweep"). agentgui pushed `6a045ba`.
|
|
122
|
-
|
|
123
|
-
## GUI ux-craft sweep (2026-07-02) — twenty-second run
|
|
124
|
-
|
|
125
|
-
35-agent audit, 20 confirmed. Accent-on-paper contrast fix (`--accent`->`--accent-ink` for text/fills), typography-rhythm parity fixes, theme-flash-prevention script in index.html. Full detail in rs-learn (recall "agentgui 22nd run ux-craft sweep").
|
|
126
|
-
|
|
127
|
-
## GUI cohesion sweep (2026-07-02) — twenty-first run
|
|
128
|
-
|
|
129
|
-
25-agent audit, 12 confirmed. WorkspaceRail attention-dot tone, WorkspaceShell keepSessionsTrack (stable column count across tabs), mobile drawer focus-trap, ConversationList richer status, ContextPane recentFiles panel. **Standing rule: commit and push any inherited uncommitted work found dirty in the tree BEFORE starting new work at PLAN entry — never leave it stranded under a fresh, disjoint cover.** Full detail in rs-learn (recall "agentgui 21st run cohesion sweep").
|
|
130
|
-
|
|
131
3
|
## CRITICAL — ACP is managed ONLY by `lib/acp-sdk-manager.js`
|
|
132
4
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
##
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
78-agent workflow, 67 confirmed findings, all implemented (interaction lifecycles, realtime truth, input ergonomics, scale, consistency). **Escape ladder order: shortcuts overlay > file dialog > confirmingEdit > new-chat arm > stop-arms > stop generation** (still binding - later runs extend the ladder, never reorder it). Full detail in rs-learn (recall "agentgui 9th run logic predictability sweep").
|
|
185
|
-
|
|
186
|
-
## GUI completion sweep (2026-06-10) — eighth maximum-effort run
|
|
187
|
-
|
|
188
|
-
Coverage run reversing the prior scope cuts. Workflow `.claude/workflows/gui-completion.js` (6 lenses) -> 46 gaps (`PUNCHLIST-COMPLETION.md`), ALL implemented. Load-bearing remnants: Files is a FULL manager (confined `POST /api/rename,/api/delete,/api/mkdir`, `PUT /api/upload-file`, `GET /api/stat` via `fsAllowRoots()`/`sanitizeEntryName()`; CSRF guard on POST/PUT/DELETE; **run `scripts/validate-mutations.mjs` (17 checks) after touching the mutation surface**). Full hash routing `HASH_KEYS=[tab,sid,dir,file,q,project,section]` (popstate diffs the full set; `navTo(tab,{writeHash:false})`). `editAndResend` clears `resumeSid` on truncation (never --resume a diverged tail). `.ds-session-meta` was taken - the strip is `.ds-session-meta-strip`. One `SHORTCUTS` array feeds the ?-overlay + settings. Live selection Set deliberately NOT persisted (stale sids would arm stop-selected wrongly). Full detail in rs-learn (recall "agentgui GUI completion sweep").
|
|
189
|
-
|
|
190
|
-
## GUI cohesion sweep (2026-06-10) — seventh maximum-effort run
|
|
191
|
-
|
|
192
|
-
One-product feel sweep (61 agents -> 40 gaps, `PUNCHLIST-COHESION.md`, workflow `.claude/workflows/gui-cohesion.js`): per-block code copy, FilePreviewPane split view, SessionDashboard sort/filter/stale/stop-selected, stableFrame, one canonical `.status-dot-disc`, confined `/api/download`, per-entry `permissions`. Full detail in rs-learn (recall "agentgui GUI cohesion sweep 7th run"). Standing rule: **the app.js `C` destructure MUST list every kit component it calls** (a witness caught `Icon is not defined`).
|
|
193
|
-
|
|
194
|
-
## GUI predictability + polish sweep (2026-06-05) — fifth maximum-effort run
|
|
195
|
-
|
|
196
|
-
Superseded/extended by the 7th run. Load-bearing survivor: `confineToRoots()` in `lib/http-handler.js` applies `fs.realpathSync` re-confinement on `/api/list`, `/api/file`, `/api/image` — symlink-escape fails closed. Full detail in rs-learn (recall "agentgui-fifth-run-polish-detail").
|
|
197
|
-
|
|
198
|
-
## Claude-Desktop redesign + embedding fix (2026-06-05) — fourth maximum-effort run
|
|
199
|
-
|
|
200
|
-
Shipped the three-column **WorkspaceShell** + **WorkspaceRail** (kit `shell.js`, `.ws-*` in `app-shell.css`, collapse persisted `localStorage ds.ws.{rail,pane}`), the shared **ConversationList** rail (`sessions.js`), the **Files** view (server `/api/list` allowlist-confined + `backend.js listDir()` + `app.js filesMain()` with kit `BreadcrumbPath`/`FileGrid`, mirrors `c:\dev\fsbrowse`), and the **Live dashboard** (`SessionDashboard`/`SessionCard`). Also a no-compromises gm-plugkit WASM embedding fix (incremental re-embed, `rs-plugkit ab09ed0`). The 5th run (above) polished all of these. Full detail in rs-learn (recall "agentgui Claude-Desktop redesign").
|
|
201
|
-
|
|
202
|
-
**webjsx keying class-bug (load-bearing, still true).** Mixing keyed VElements with `null`/strings in any children array crashes `applyDiff` ("reading 'key'"). `ConversationList` uses a stable keyed body wrapper (loading/empty/populated diff children not container) + `[...].filter(Boolean)` on conditional row children; `app.js runningPanel` keys all three row children. `refreshHistory` keeps `render()` OUT of the try so a render exception doesn't masquerade as a history fetch error. See the webjsx note below.
|
|
203
|
-
|
|
204
|
-
## GUI-predictability sweep closure (2026-06-05) — third maximum-effort run
|
|
205
|
-
|
|
206
|
-
Override-elimination pass (index.html `!important` -> kit defaults) + 19 other PRD rows. Full detail in rs-learn (recall "agentgui 3rd run GUI-predictability sweep closure").
|
|
207
|
-
|
|
208
|
-
## GUI-audit closure (2026-06-04 fan-out) — second maximum-effort sweep
|
|
209
|
-
|
|
210
|
-
`.claude/workflows/gui-audit.js` ran a 64-agent fan-out (9 per-surface reviewers -> adversarial verify -> synthesize) -> 44 confirmed findings (`AUDIT-PUNCHLIST.md`, 38 deduped), all fixed across server/app/kit and pushed (agentgui `eb1eab3`/`951404e`, kit `anentrypoint-design` `bb776aa` -> CI publishes npm/unpkg). Per-finding detail + key learnings (ccsniff SSE `{sid,payload}` unwrap, CSP must allow Google Fonts, DS `Select` promotes `title`->`aria-label`, index.html now loads the kit from local `./vendor/`, kit publish flow) in rs-learn (recall "agentgui GUI-audit closure").
|
|
211
|
-
|
|
212
|
-
## Architecture (2026-05-19 pivot — single surface)
|
|
213
|
-
|
|
214
|
-
One surface. `server.js` serves `site/app/` under `BASE_URL` (default `/gm`) and mounts `ccsniff`'s `/v1/history/*` Express router in-process at both `/` and `BASE_URL`. The legacy `static/` tree and the legacy `lib/routes-*`/`lib/db-queries-*`/`lib/jsonl-watcher.js` modules are gone. `acptoapi` is no longer used by this project.
|
|
215
|
-
|
|
216
|
-
When `PASSWORD` env var is set, every HTTP route is gated by `lib/http-handler.js` accepting **Basic auth**, **`Authorization: Bearer <pwd>`**, OR **`?token=<pwd>`** query param (added 2026-05-26 so `EventSource` and direct deep-links work — neither can set headers). WS `/sync` requires `?token=` only. The HTML head script injects `window.__BASE_URL`, `window.__SERVER_VERSION`, and `window.__WS_TOKEN`; `site/app/js/backend.js` reads `__WS_TOKEN` and threads it onto every fetch (Bearer header) / EventSource (qs) / WebSocket (qs).
|
|
217
|
-
|
|
218
|
-
- `site/app/index.html` — shell + CSS; imports `anentrypoint-design` from the **local vendored copy** `./vendor/anentrypoint-design/247420.{js,css}` (re-vendored 2026-06-04 for a PREDICTABLE shipped UI that does not shift when upstream publishes, and offline operation — the markdown stack marked/dompurify/prismjs still fetches from jsdelivr on first chat render). Update flow: edit the kit at `c:\dev\anentrypoint-design`, `node scripts/build.mjs`, copy `dist/247420.{js,css}` into `site/app/vendor/anentrypoint-design/`, then publish the kit so unpkg stays in sync.
|
|
219
|
-
- `site/app/js/backend.js` — same-origin WS/HTTP client (`DEFAULT_BACKEND = ''`); the transport glue that wires the kit; `?backend=` query override for cross-origin debugging
|
|
220
|
-
- `site/app/js/app.js` — webjsx view + state; renders the `AgentChat` kit (from `anentrypoint-design`) for the chat surface and wires agentgui's WS/ccsniff state as kit callbacks; history/settings remain agentgui-local. Exposes `window.__agentgui`
|
|
221
|
-
|
|
222
|
-
The chat GUI lives in the design kit, not in agentgui. The reusable multi-agent chat surface is the `AgentChat` component in `anentrypoint-design` (`src/components/agent-chat.js`); agentgui keeps only the transport glue (WS `backend.js`, ccsniff history wiring, agent orchestration) and passes state + callbacks into the kit. To change chat UI, edit the kit and push it (CI publishes to npm -> unpkg `@latest`), not agentgui.
|
|
223
|
-
- `server.js` — initializes the ACP-SDK manager + agent registry, registers WS handlers (`ws-handlers-util.js`), mounts `createHistoryRouter()` from `ccsniff` at `/`, serves `site/app/` as static root. The `lib/plugins/` system was removed (2026-06-20, 20th run) — it was dead scaffolding (routes 404, wsHandlers never wired, api unconsumed); all server logic lives directly in `server.js` + `lib/ws-handlers-util.js` + `lib/http-handler.js` + `lib/routes-upload.js` + `database.js`.
|
|
5
|
+
ACP lifecycle lives in `lib/acp-sdk-manager.js` alone; no other module spawns or manages ACP agent processes. Every `spawn()` callsite needs a `proc.on('error', …)` handler (ENOENT surfaces async under Bun).
|
|
6
|
+
|
|
7
|
+
## CRITICAL — `authedFetch` must NOT set `Authorization: Bearer` behind an nginx Basic-Auth proxy
|
|
8
|
+
|
|
9
|
+
Same-origin app auth must never use the `Authorization` header when an upstream proxy may own Basic auth — a `Bearer` header overwrites the browser's cached `Authorization: Basic` credentials, and nginx `auth_basic` only accepts `Basic`, so the request is rejected at the proxy before it ever reaches agentgui. Use the **`?token=` query param** (`withToken()`, exactly like the WS / EventSource / image / download URLs) instead — it coexists with upstream Basic auth, and agentgui accepts `?token=` on every HTTP route, plus the `agentgui_token` cookie.
|
|
10
|
+
|
|
11
|
+
## Standing engineering rules
|
|
12
|
+
|
|
13
|
+
- **All GUI/design decisions live in the kit (`../design`), none in agentgui.** New surface styling is a kit CSS rule, never an inline `<style>` or `style=` prop in agentgui. A new kit component must be re-exported through `src/components.js`'s barrel to be consumable — adding it to a component file alone leaves it invisible to the built bundle even with 0 lint errors; grep the built dist for the export name before wiring the app against it. New CSS class tokens in the kit must carry a registered family prefix (`ds-`, `app-`, `ws-`, `chat-`, etc. — see `scripts/lint-classes.mjs`'s `PREFIXES`/`FROZEN` lists) or the build's lint-classes check fails; a legacy bare name like `chip` being grandfathered on the FROZEN list does not cover new sub-tokens off it (e.g. a new `chip-remove` class still needs a `ds-` prefix).
|
|
14
|
+
- **`confineToRoots()` in `lib/http-handler.js` applies `fs.realpathSync` re-confinement on `/api/list`, `/api/file`, `/api/image`** — a symlink pointing outside an allowed root fails closed rather than resolving through it.
|
|
15
|
+
- **Files is a full file manager, not a viewer**: confined `POST /api/rename`, `/api/delete` (soft-delete into a per-root `.agentgui-trash/` with a restore endpoint and a retention-window eviction cap, not a hard unlink), `/api/mkdir`, `/api/restore`, `PUT /api/upload-file`, `GET /api/stat`, all routed through `fsAllowRoots()`/`sanitizeEntryName()` and a CSRF guard on every POST/PUT/DELETE. Run `scripts/validate-mutations.mjs` after touching any part of this mutation surface. `RFC-5987` `Content-Disposition` encoding is required for non-ASCII filenames on download.
|
|
16
|
+
- Full hash routing state is `HASH_KEYS=[tab,sid,dir,file,q,project,section]`; `popstate` diffs the full set, and `navTo(tab,{writeHash:false})` navigates without pushing a new hash entry.
|
|
17
|
+
- The "Untitled conversation" fallback is one shared `UNTITLED_CONVERSATION` constant — never a locally re-typed literal (casing/wording drifts across call sites otherwise).
|
|
18
|
+
- Upload/mkdir/rename/list request bodies are scanned by `SECRET_RE` before being echoed into logs or responses.
|
|
19
|
+
- **webjsx keying:** mixing keyed VElements with `null`/strings/numbers in any children array crashes `applyDiff` ("reading 'key'"). Never pass a conditional `x?h():null` positionally — build the array and `.filter(Boolean)` it. `Btn` spreads array children. A kit component prop with an established narrow contract can silently corrupt an unrelated call site when a caller passes a richer value than the prop was designed for (e.g. a VElement where only a plain string was ever read) — grep every other use site of a prop before extending what a caller passes through it.
|
|
20
|
+
- **Escape ladder order (extend, never reorder):** shortcuts overlay > file dialog > confirmingEdit > new-chat arm > stop-arms > stop generation.
|
|
21
|
+
- **Status-disc shape:** live = solid+pulse, error = solid+halo, connecting = hollow ring, stale = muted solid.
|
|
22
|
+
- **Kit `Row` rail/rank contract:** the design-kit `Row` (`anentrypoint-design` `src/components/content.js`) renders a leading status rail from a `rail` prop (`green` | `purple` | `flame`, via `.row.rail-<tone>::before`) and accepts `rank` as an alias for the leading `code` index. `state: 'disabled'` is inert (no `onClick`/`role=button`/tab-stop, `aria-disabled=true`). Rail semantics are consistent everywhere: green = selected/ok, purple = subagent, flame = error/unavailable.
|
|
23
|
+
- **No decorative glyphs.** GUI source and output use ASCII words and CSS-drawn discs (`.status-dot-disc`) for status, never `●/◌/○/⌘/§/▶` etc. The middot separator `·`, ellipsis `…`, and em/en dashes in prose are kept as deliberate typographic product design, not tells — convert any other decorative glyph (arrows, box-drawing, bullets, checks) to ASCII on sight (`->`, `// --- x ---`, `-`/`*`). A dismiss control's own close icon on a dismissible Alert is a real DS icon affordance, exempt.
|
|
24
|
+
- **A `keepXTrack`-mounted component's interaction must produce the same visible effect on every tab it appears on** (e.g. the persistent sessions rail).
|
|
25
|
+
- **Any drawer/overlay whose `left`/`inset` changes across breakpoints must re-derive its closed-state transform from that breakpoint's own offset** — a transform tuned for one breakpoint's geometry silently breaks at the next if the offset shifts underneath it.
|
|
26
|
+
- **`.ws-rail`/`.ws-sessions`/`.ws-pane` must all three use `--bg-2`** for background — a mismatched flat `--bg` on any one reads as visually disjointed chrome.
|
|
27
|
+
- The app.js `C` destructure must list every kit component it calls (an undestructured component silently renders as `Icon is not defined` or similar).
|
|
28
|
+
- Commit and push any inherited uncommitted work found dirty in the tree before starting new work at PLAN entry — never leave it stranded under a fresh, disjoint cover.
|
|
29
|
+
- No new `PUNCHLIST-*.md`/`AUDIT-PUNCHLIST.md` (or similarly named) file is checked into the repo as a durable artifact. A workflow's punch-list is a transient working document for that run's synthesis step; the outcome belongs in AGENTS.md (compressed to a rule) or drains to recall, never a standing file.
|
|
30
|
+
- When origin advances mid-run with the same feature a concurrent writer already shipped, drop your version and adopt theirs, then re-apply only genuinely-distinct work — never a parallel implementation.
|
|
31
|
+
- Check a color token's contrast against its actual rendered background, not just the base paper token. A `failures`-array-shaped crash from a lint/audit lens means that scope is unaudited, not a null (clean) result. `prd-resolve` `witness_evidence` must be distinct per row, never a batch-shared string.
|
|
32
|
+
- This env's `PASSWORD` value can itself contain literal commas (e.g. `123,slam,123,slam`) — treat the whole string as one token, never comma-split it when testing auth.
|
|
33
|
+
- The `gm-plugkit` `fs_write` verb's payload key is `content` (a JSON string), not `body` — passing `{path, body:{...}}` silently no-ops with `bytes:0` and no error.
|
|
34
|
+
- Docstudio design-cue mining (`/config/docstudio`) is a recurring source of portable UI conventions to port into `../design`. When re-running this sweep, survey files not yet examined against the kit's actual current component list rather than trusting a prior "exhausted" verdict at face value — a narrow, genuinely new gap can still surface (e.g. `Chip.onRemove`, `RateCell`, `SpreadsheetPreview`, `ApprovalPrompt`, `PermissionMenu`, `CountdownDialog`, `withBusy` double-fire guard). Business logic with no portable visual surface (native OAuth pickers, drive integration, file-upload wiring) and app-specific cloud-provider wiring (observability deep-links) are not portable; the visual/interaction *convention* underneath sometimes still is.
|
|
35
|
+
|
|
36
|
+
## Browser-verb operating notes
|
|
37
|
+
|
|
38
|
+
- The `browser` spool verb's actual accepted JSON body shape is `{"code": "<script>"}`, evaluated directly in the currently-loaded page's `window`/`document` context — it is not a Puppeteer/Playwright `page`-scoped API (no `page.goto`/`page.title()`). Navigating via `window.location.href = '...'` inside one `{code}` dispatch throws `"Inspected target navigated or closed"` (expected — kills the CDP eval mid-navigation), but the session persists across dispatches, so a second `{code}` dispatch on the same session lands in the newly-navigated page. If the plain-text `url=`/`dom=`/`screenshot=`-prefixed body forms ever return empty/no-op in this environment, fall back to the two-dispatch `{code}` navigate-then-eval pattern rather than re-litigating the prefix forms.
|
|
39
|
+
- Zombie Chromium process trees left by earlier timed-out `browser` dispatches (under the project's own `.gm/browser-chrome-profile-` directory) can wedge every subsequent Chrome launch/reuse to full-timeout empty responses or intermittent `"plugin gm not loaded"` errors. Kill every chromium PID under that profile dir (never the daemon process itself) to unblock; this is a distinct failure mode from a genuinely stale/crash-looping supervisor process (also possible — check `.gm/exec-spool/.watcher.log` for a repeating respawn-crash-loop signature before assuming it's the Chrome-zombie case).
|
|
40
|
+
- Embedding Basic-Auth creds directly in a `page.goto`/navigation URL (`https://user:pass@host/...`) breaks the app's own same-origin `fetch()` calls with "Request cannot be constructed from a URL that includes credentials." Do one embedded-creds navigation to seed the browser's per-origin Basic-Auth cache, then navigate again WITHOUT embedded creds (plain URL or `?token=`) for any witness that needs real fetches to succeed.
|
|
41
|
+
- Combine creds + goto + wait + evaluate into ONE dispatch when the tool version's session ids rotate across separate dispatches; read results via `console.log('WITNESS:'+...)` and grep stdout rather than trusting a `capture`-prefix `result` field that can come back `null` on an otherwise successful dispatch.
|
|
42
|
+
- Writing a spool verb input file under a task-number that collides with an existing `out/<verb>-<N>.json` from an earlier turn in the same session can silently return the STALE cached output instead of running the fresh dispatch. Pick a task number confirmed absent from `out/` (e.g. jump to a clearly-unused block) rather than trusting sequential same-session numbering, especially after a long session with many prior dispatches.
|
|
43
|
+
|
|
44
|
+
## Architecture (single surface)
|
|
45
|
+
|
|
46
|
+
One surface. `server.js` serves `site/app/` under `BASE_URL` (default `/gm`) and mounts `ccsniff`'s `/v1/history/*` Express router in-process at both `/` and `BASE_URL`. There is no legacy `static/` tree and no `lib/plugins/` system — all server logic lives directly in `server.js` + `lib/ws-handlers-util.js` + `lib/http-handler.js` + `lib/routes-upload.js` + `database.js`. `acptoapi` is not used by this project.
|
|
47
|
+
|
|
48
|
+
When `PASSWORD` env var is set, every HTTP route is gated by `lib/http-handler.js` accepting **Basic auth**, **`Authorization: Bearer <pwd>`**, OR **`?token=<pwd>`** query param (the query-param path exists because `EventSource` and direct deep-links cannot set headers). WS `/sync` requires `?token=` only. The HTML head script injects `window.__BASE_URL`, `window.__SERVER_VERSION`, and `window.__WS_TOKEN`; `site/app/js/backend.js` reads `__WS_TOKEN` and threads it onto every fetch (Bearer header) / EventSource (qs) / WebSocket (qs).
|
|
49
|
+
|
|
50
|
+
- `site/app/index.html` — shell + CSS; imports `anentrypoint-design` from the local vendored copy `./vendor/anentrypoint-design/247420.{js,css}` (a predictable shipped UI that does not shift when upstream publishes, plus offline operation — the markdown stack marked/dompurify/prismjs still fetches from jsdelivr on first chat render). Update flow: edit the kit at `../design`, `node scripts/build.mjs`, copy `dist/247420.{js,css}` into `site/app/vendor/anentrypoint-design/`, then publish the kit so unpkg stays in sync.
|
|
51
|
+
- `site/app/js/backend.js` — same-origin WS/HTTP client (`DEFAULT_BACKEND = ''`); the transport glue that wires the kit; `?backend=` query override for cross-origin debugging.
|
|
52
|
+
- `site/app/js/app.js` — webjsx view + state; renders the `AgentChat` kit component for the chat surface and wires agentgui's WS/ccsniff state as kit callbacks; history/settings remain agentgui-local. Exposes `window.__agentgui`.
|
|
53
|
+
- The chat GUI lives in the design kit, not in agentgui. The reusable multi-agent chat surface is the `AgentChat` component in `anentrypoint-design` (`src/components/agent-chat.js`); agentgui keeps only the transport glue (WS `backend.js`, ccsniff history wiring, agent orchestration) and passes state + callbacks into the kit. To change chat UI, edit the kit and push it (CI publishes to npm -> unpkg `@latest`), not agentgui.
|
|
54
|
+
- `server.js` — initializes the ACP-SDK manager + agent registry, registers WS handlers (`ws-handlers-util.js`), mounts `createHistoryRouter()` from `ccsniff` at `/`, serves `site/app/` as static root.
|
|
224
55
|
|
|
225
56
|
Dependencies:
|
|
226
57
|
- `ccsniff` (>=1.1.0) — exports `createHistoryRouter({projectsDir})` mountable on Express; serves `/v1/history/{sessions,sessions/:sid/events,search,snapshot,reindex,stream}`. Reads `~/.claude/projects` (override via `CLAUDE_PROJECTS_DIR`).
|
|
227
|
-
- `anentrypoint-design` (>=0.0.119) — kit library, single-file ESM from unpkg
|
|
228
|
-
|
|
229
|
-
## GUI audit pass (2026-06-04) — structured chat, predictable presentation
|
|
230
|
-
|
|
231
|
-
Landed structured tool cards (toolPart/applyToolResult by id), multi-turn resume wiring (streaming_session -> state.chat.resumeSid), rAF-coalesced streaming, /api/image confinement, history eventsLimit + search-to-event flash. Largely superseded by runs 5-12; full detail in rs-learn (recall "agentgui GUI audit pass 2026-06-04 structured chat").
|
|
58
|
+
- `anentrypoint-design` (>=0.0.119) — kit library, single-file ESM, vendored locally (not loaded from unpkg at runtime).
|
|
232
59
|
|
|
233
60
|
## Orchestration agents
|
|
234
61
|
|
|
@@ -236,13 +63,13 @@ The four flagship agents the GUI drives are **Claude Code, OpenCode, Kilo, and A
|
|
|
236
63
|
|
|
237
64
|
Two runner protocols exist. **Direct** (`lib/claude-runner-direct.js`): claude-code and agy — spawn the CLI per turn, parse stdout. **ACP** (`lib/acp-sdk-manager.js`): opencode/kilo/codex — an on-demand long-lived server on ports 18100/18101/18102, health-checked via `/provider`. The on-demand start + restart-backoff is correct even when an ACP agent lacks provider auth (it reports running-not-healthy rather than crashing).
|
|
238
65
|
|
|
239
|
-
`agy` (Antigravity) is a Gemini-backed Go CLI. Its invocation is `agy --print "<prompt>" --dangerously-skip-permissions [--continue]` — `--print` is a **value flag** (the prompt is its argument; a positional prompt exits 2). It emits **plain text** (not stream-json) and prints no session id, so its `parseOutput` wraps each line into an assistant-text event and resume is `--continue`-only. A live model response needs an authenticated Antigravity session; without it `agy` returns empty (the direct runner resolves gracefully, no hang).
|
|
66
|
+
`agy` (Antigravity) is a Gemini-backed Go CLI. Its invocation is `agy --print "<prompt>" --dangerously-skip-permissions [--continue]` — `--print` is a **value flag** (the prompt is its argument; a positional prompt exits 2). It emits **plain text** (not stream-json) and prints no session id, so its `parseOutput` wraps each line into an assistant-text event and resume is `--continue`-only. A live model response needs an authenticated Antigravity session; without it `agy` returns empty (the direct runner resolves gracefully, no hang).
|
|
240
67
|
|
|
241
|
-
**The direct runner spawns with `shell:false` against a resolved binary path — never `shell:true`.** `shell:true` on Windows concatenates argv without escaping, so a chat prompt containing `&`/`|`/`>`/backticks executes as shell commands (arbitrary command execution). `lib/claude-runner.js` `resolveBinaryPath` resolves the command to an absolute `.exe`; `getSpawnOptions` only defaults `shell:true` when a caller passes no explicit `shell`.
|
|
68
|
+
**The direct runner spawns with `shell:false` against a resolved binary path — never `shell:true`.** `shell:true` on Windows concatenates argv without escaping, so a chat prompt containing `&`/`|`/`>`/backticks executes as shell commands (arbitrary command execution). `lib/claude-runner.js` `resolveBinaryPath` resolves the command to an absolute `.exe`; `getSpawnOptions` only defaults `shell:true` when a caller passes no explicit `shell`.
|
|
242
69
|
|
|
243
|
-
**Agent availability comes from `registry.isAvailable(id)`** (`lib/ws-handlers-util.js`, `agents.list`), which runs `where`/`which`. A binary installed outside the system PATH reads as "(not installed)"; the fix is an `npxPackage` on the registry entry so it falls back to bun/npx presence.
|
|
70
|
+
**Agent availability comes from `registry.isAvailable(id)`** (`lib/ws-handlers-util.js`, `agents.list`), which runs `where`/`which`. A binary installed outside the system PATH reads as "(not installed)"; the fix is an `npxPackage` on the registry entry so it falls back to bun/npx presence.
|
|
244
71
|
|
|
245
|
-
|
|
72
|
+
**`lib/tool-spawner.js`** iterates `BUNX_RUNNERS=['bun','npx']` and detects missing-command via regex on both `error.message` and stdout+stderr.
|
|
246
73
|
|
|
247
74
|
## Browser Witness
|
|
248
75
|
|
|
@@ -250,89 +77,40 @@ Two runner protocols exist. **Direct** (`lib/claude-runner-direct.js`): claude-c
|
|
|
250
77
|
|
|
251
78
|
## CI / GitHub Actions
|
|
252
79
|
|
|
253
|
-
**capture-screenshots must run under bun, not node.**
|
|
254
|
-
|
|
255
|
-
`npm install --ignore-scripts` in gh-pages.yml skips native compilation, leaving `better-sqlite3` without a compiled `.node` binding. `database.js` tries `bun:sqlite` first, then falls back to `better-sqlite3`. When the step runs under Node both fail and the server crashes silently within the 20s health-check window.
|
|
256
|
-
|
|
257
|
-
Fix: `bun run scripts/capture-screenshots.mjs` (not `node ...`).
|
|
258
|
-
|
|
259
|
-
Why it works: `process.execPath` becomes bun, so the spawned child server also runs under bun and loads `bun:sqlite` natively — no compiled binding needed.
|
|
260
|
-
|
|
261
|
-
Rule: any CI step that spawns the agentgui server (directly or via a script that inherits `process.execPath`) must invoke it with `bun`.
|
|
262
|
-
|
|
263
|
-
## Plugin system removed (2026-06-20 — 20th run)
|
|
264
|
-
|
|
265
|
-
The entire `lib/plugins/` system + `plugin-loader.js` was deleted as dead scaffolding (commits up to e73ed0e): plugin routes were unreachable (http-handler forwarded only a few prefixes -> 404), plugin `wsHandlers` were never wired (the real WS handlers come from `registerWsHandlers` in `ws-handlers-util.js`), plugin `api` objects were never consumed, and the inits were no-ops or managed local Maps nobody read. Removed across 7 commits (acp, files, agents, then database/stream/workflow/websocket + loader). The general lesson survives: any import under `lib/` must be a built-in (crypto, fs, path) or already in package.json — a missing dep crashes boot.
|
|
266
|
-
|
|
267
|
-
## Plugin Tool Provisioning on Windows
|
|
268
|
-
|
|
269
|
-
**`lib/tool-spawner.js` iterates `BUNX_RUNNERS=['bun','npx']` and detects missing-command via regex on both error.message and stdout+stderr.** Full detail in rs-learn (recall "agentgui windows tool-spawner bunx fallback").
|
|
80
|
+
**capture-screenshots must run under bun, not node.** `npm install --ignore-scripts` in gh-pages.yml skips native compilation, leaving `better-sqlite3` without a compiled `.node` binding; `database.js` tries `bun:sqlite` first, then falls back to `better-sqlite3`. Under Node both fail and the server crashes silently within the 20s health-check window. Fix: `bun run scripts/capture-screenshots.mjs` (not `node ...`) — `process.execPath` becomes bun, so the spawned child server also runs under bun and loads `bun:sqlite` natively. Rule: any CI step that spawns the agentgui server (directly or via a script that inherits `process.execPath`) must invoke it with `bun`.
|
|
270
81
|
|
|
271
82
|
## GM Plugin Autonomy Blocker
|
|
272
83
|
|
|
273
|
-
gm plugin's pre-tool-use hook gates multi-tool autonomy via a `.gm/needs-gm` marker; the hook content is
|
|
274
|
-
|
|
275
|
-
## History Integration via ccsniff (2026-05-21 — reverted from acptoapi)
|
|
84
|
+
gm plugin's pre-tool-use hook gates multi-tool autonomy via a `.gm/needs-gm` marker; the hook content is templated from the gm codebase, not `gm-starter/hooks/` — patching those files does not propagate.
|
|
276
85
|
|
|
277
|
-
|
|
86
|
+
## History Integration via ccsniff
|
|
278
87
|
|
|
279
|
-
`server.js` imports `createHistoryRouter` from the `ccsniff` package and mounts it on the internal Express app at `/`, exposing `GET /v1/history/{snapshot,sessions,sessions/:sid/events,search,reindex,stream}`. Reads `~/.claude/projects` by default; override with `CLAUDE_PROJECTS_DIR` env var.
|
|
88
|
+
agentgui mounts `ccsniff`'s history router in-process — no external proxy. `server.js` imports `createHistoryRouter` from the `ccsniff` package and mounts it on the internal Express app at `/`, exposing `GET /v1/history/{snapshot,sessions,sessions/:sid/events,search,reindex,stream}`. Reads `~/.claude/projects` by default; override with `CLAUDE_PROJECTS_DIR` env var. Browser client (`site/app/js/backend.js`) calls these same-origin via the agentgui server.
|
|
280
89
|
|
|
281
|
-
## buildSystemPrompt
|
|
90
|
+
## buildSystemPrompt for claude-code
|
|
282
91
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
The function previously returned "Model: X." when agentId was 'claude-code' and model was non-null. This caused `buildArgs` in lib/claude-runner-agents.js to pass `--append-system-prompt "Model: X."` to the claude CLI, which triggers "argument missing" error on conversation resume. Fix: return '' early when agentId is 'claude-code' or falsy. The model is already passed via `--model` flag; system prompt is only for non-claude-code agents.
|
|
92
|
+
`lib/provider-config.js` `buildSystemPrompt()` must return `''` for the claude-code agent — a non-empty return (e.g. `"Model: X."`) causes `buildArgs` in `lib/claude-runner-agents.js` to pass `--append-system-prompt` to the claude CLI, which triggers an "argument missing" error on conversation resume. The model is already passed via `--model`; system prompt is only for non-claude-code agents.
|
|
286
93
|
|
|
287
94
|
## WebSocket Sync Endpoint Testing
|
|
288
95
|
|
|
289
|
-
|
|
96
|
+
`/sync` sends `sync_connected`+clientId on connect; the legacy handler in `lib/ws-legacy-handlers.js` (ping/subscribe/get_subscriptions/unsubscribe/latency_report) runs via codec. Tests must register the message handler before sending.
|
|
290
97
|
|
|
291
98
|
## better-sqlite3 & Node v24 Startup
|
|
292
99
|
|
|
293
|
-
Node v24 lacks a prebuilt better-sqlite3 binary; the node path needs a from-source `postinstall` compile, and `start` is `bun server.js || node server.js`. `database.js` tries `bun:sqlite` first.
|
|
294
|
-
|
|
295
|
-
## webjsx applyDiff Array Keying (2026-05-04)
|
|
296
|
-
|
|
297
|
-
**Rule still binding: mixing keyed VElements with raw strings/numbers in any webjsx array prop crashes `applyDiff`.** Full detail in rs-learn (recall "agentgui webjsx applyDiff array-keying rule").
|
|
298
|
-
|
|
299
|
-
## Live History Stream Wiring (2026-05-05)
|
|
100
|
+
Node v24 lacks a prebuilt better-sqlite3 binary; the node path needs a from-source `postinstall` compile, and `start` is `bun server.js || node server.js`. `database.js` tries `bun:sqlite` first.
|
|
300
101
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
## Runtime CDN: GUI loaded from unpkg — SUPERSEDED, do not trust
|
|
304
|
-
|
|
305
|
-
This 2026-05-29 unpkg-at-runtime approach was reverted; see "DS load = LOCAL vendor" below for the current truth (re-confirmed live on the 37th run, 2026-07-12). Historical detail in rs-learn (recall "agentgui unpkg superseded local vendor").
|
|
306
|
-
|
|
307
|
-
## Agent/model/session management (2026-05-28)
|
|
102
|
+
## Agent/model/session management
|
|
308
103
|
|
|
309
104
|
- `agents.list` (WS) returns `available` + `npxInstallable` per agent; `agents.models` returns model choices (claude-code -> sonnet/opus/haiku). The chat picker is **agent-then-model**, not a flat model list. Unavailable agents are disabled/gated.
|
|
310
105
|
- `chat.sendMessage` accepts `cwd` (defaults to STARTUP_CWD) and `model`/`agentId` separately. `chat.active` (WS) lists in-flight chats with agentId/model/cwd/startedAt/pid; the history tab polls it (3s) and shows a running panel with per-session stop.
|
|
311
106
|
- Client (`app.js`): chat transcript persists to `localStorage[agentgui.chat]` and restores on load; tool_use/result events render as chat parts; keyboard shortcuts (g+c/h/s, n, /, ?); settings has an agents-status panel from `health.acp[]`.
|
|
312
107
|
|
|
313
|
-
##
|
|
314
|
-
|
|
315
|
-
The design-kit `Row` (`anentrypoint-design` `src/components/content.js`) renders a leading status **rail** from a `rail` prop (`green` | `purple` | `flame`, via a `.row.rail-<tone>::before` bar) and accepts `rank` as an alias for the leading `code` index. A `state: 'disabled'` Row is inert — no `onClick`/`role=button`/tab-stop, `aria-disabled=true`. agentgui's history sessions, search results, and agents panel pass `rail` + `rank` and rely on this; the rendering reaches the live GUI only after the kit publishes to npm -> unpkg `@latest`. agentgui keeps the rail semantics consistent everywhere: **green = selected/ok, purple = subagent, flame = error/unavailable**.
|
|
316
|
-
|
|
317
|
-
## GUI glyph policy
|
|
318
|
-
|
|
319
|
-
GUI source keeps typographic product characters — the middot separator `·`, the ellipsis `…`, and em/en dashes in prose — as established design (AGENTS.md itself uses `·`). It carries **no** decorative tells: arrows, box-drawing, bullets, status dots, checks. Status is words + the CSS-drawn `.status-dot-disc`. Convert any arrow/box-drawing/bullet glyph to ASCII on sight (`->`, `// --- x ---`, `-`/`*`).
|
|
320
|
-
|
|
321
|
-
## DS CSS cascade — overriding component styles (2026-05-28)
|
|
322
|
-
|
|
323
|
-
**`installStyles()` injects DS CSS into a runtime `<style>` after the head `<style>`, so local overrides need `!important` or higher specificity than the DS's `.ds-247420`-prefixed rules.** Full detail (font vars `--ff-display`/`--ff-mono`, the `.chat-head .sub` "00 msgs" quirk, EventList `.row[role=button]`, `[data-prog-focus]` focus suppression, `projectLabel()` for cwd slugs) is in rs-learn (recall "agentgui GUI styling DS cascade installStyles").
|
|
324
|
-
|
|
325
|
-
## No decorative glyphs — ASCII-only GUI (2026-06-04)
|
|
326
|
-
|
|
327
|
-
**The GUI carries no decorative tell-tale glyphs; remaining non-ASCII is the deliberate typographic separator set.** The de-jank sweep removed every tell-tale (status dots `[CHAR]`, arrows, box-drawing dividers, checks) in favor of ASCII words + the CSS-drawn status disc. The middot separator `·` is kept as established product design (it reads as a real meta-separator, used consistently across rows/subs); ellipsis `…` and em/en dashes were converted to `...` / `-` on sight. Verified live on buildesk: `document.body.innerText` matches no decorative-glyph regex (excluding the kept middot) across chat/history/settings. The DS Alert dismiss control renders its own close glyph only on a dismissible alert (intentional DS icon affordance, exempt).
|
|
328
|
-
|
|
329
|
-
## DS SearchInput accessible name comes from `label`, not `aria-label` (2026-06-04)
|
|
330
|
-
|
|
331
|
-
**`anentrypoint-design`'s `SearchInput` (internal `De`) sets `aria-label = label || placeholder`; it ignores any `aria-label` prop you pass.** To give the search box a real accessible name, pass `label:` (and a matching `placeholder:` for the visible hint). Passing only `aria-label` leaves AT announcing the placeholder. A post-render `setAttribute` race-loses against the DS re-render, so the prop is the only durable fix.
|
|
108
|
+
## DS CSS cascade — overriding component styles
|
|
332
109
|
|
|
333
|
-
|
|
110
|
+
`installStyles()` injects DS CSS into a runtime `<style>` after the head `<style>`, so local overrides need `!important` or higher specificity than the DS's `.ds-247420`-prefixed rules.
|
|
334
111
|
|
|
335
|
-
|
|
112
|
+
## DS SearchInput accessible name comes from `label`, not `aria-label`
|
|
336
113
|
|
|
114
|
+
`anentrypoint-design`'s `SearchInput` sets `aria-label = label || placeholder`; it ignores any `aria-label` prop passed directly. To give the search box a real accessible name, pass `label:` (and a matching `placeholder:` for the visible hint) — a post-render `setAttribute` race-loses against the DS re-render, so the prop is the only durable fix.
|
|
337
115
|
|
|
338
116
|
@.gm/next-step.md
|