agentgui 1.0.962 → 1.0.964
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/.claude/workflows/gui-ux-craft.js +101 -0
- package/AGENTS.md +40 -38
- package/PUNCHLIST-PARITY.md +6 -0
- package/PUNCHLIST-UX.md +222 -0
- package/lib/http-handler.js +62 -1
- package/package.json +1 -1
- package/scripts/validate-mutations.mjs +39 -13
- package/site/app/index.html +14 -4
- package/site/app/js/app.js +296 -72
- package/site/app/js/backend.js +1 -0
- package/site/app/vendor/anentrypoint-design/247420.css +490 -123
- package/site/app/vendor/anentrypoint-design/247420.js +14 -14
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'gui-ux-craft',
|
|
3
|
+
description: 'Hunt UX-craft gaps the 11 prior sweeps never lensed: typography rhythm, copy tone, perceived performance, kit DX, light-theme contrast, interaction density; adversarially verify each against live source',
|
|
4
|
+
whenToUse: 'Run for the 12th maximum-effort agentgui run. Prior sweeps covered jank/redesign/polish/cohesion/completion/logic/parity/files; this one hunts the remaining craft dimensions. Kit lives at /config/workspace/design on this env.',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Hunt', detail: 'one hunter per craft lens against real source in both repos' },
|
|
7
|
+
{ title: 'Verify', detail: 'adversarial verifier per finding (kept-typography guard)' },
|
|
8
|
+
],
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const KIT = '/config/workspace/design'
|
|
12
|
+
const APP = '/config/workspace/agentgui'
|
|
13
|
+
|
|
14
|
+
const COMMON = `
|
|
15
|
+
You are auditing the agentgui GUI (a Claude-Code-web-class multi-agent chat product) and its design kit.
|
|
16
|
+
Repos: app at ${APP} (client: site/app/js/app.js, site/app/js/backend.js, site/app/index.html; server: lib/http-handler.js, server.js), kit at ${KIT} (src/components/*.js, src/styles/ or *.css at root, scripts/build.mjs; the kit is the published anentrypoint-design library and OWNS all visual CSS - the app only wires state/callbacks).
|
|
17
|
+
Reference bar: claude.ai/code (calm, content-first, quiet chrome, generous thread width).
|
|
18
|
+
HARD GUARDS:
|
|
19
|
+
- The middot separator, the ellipsis char, and em/en dashes in prose are KEPT product typography - never flag them.
|
|
20
|
+
- Status is words + CSS-drawn .status-dot-disc - never propose decorative glyphs.
|
|
21
|
+
- GUI fixes land in the KIT (CSS/components); app gets wiring only; index.html gets NO new !important.
|
|
22
|
+
- Already-filed findings you must NOT duplicate: chat column crush at moderate widths (pane collapse priority), loud PageHeader+lede on every tab, permanent DropZone band, double breadcrumb on files, stadium toolbar pills, duplicate New-chat buttons, cumulative flame rail on history rows, title==project dedupe, ccsniff/same-origin jargon purge, footer status-bar wrap, live empty-state CTA, theme-toggle 'auto (ink)' label, 420px rail sliver regression, composer dangling middot, select truncation, live running-count contradiction, live toolbar stacking, context-pane ungrouped action / zero stats.
|
|
23
|
+
Read the REAL source before claiming anything; every finding needs file:line evidence. Findings must be IMPLEMENTABLE this session (no rewrites).
|
|
24
|
+
`
|
|
25
|
+
|
|
26
|
+
const FINDINGS_SCHEMA = {
|
|
27
|
+
type: 'object',
|
|
28
|
+
required: ['findings'],
|
|
29
|
+
properties: {
|
|
30
|
+
findings: {
|
|
31
|
+
type: 'array',
|
|
32
|
+
items: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
required: ['id', 'title', 'evidence', 'fixLocation', 'fix', 'severity'],
|
|
35
|
+
properties: {
|
|
36
|
+
id: { type: 'string', description: 'kebab-case slug' },
|
|
37
|
+
title: { type: 'string' },
|
|
38
|
+
evidence: { type: 'string', description: 'file:line + what the source shows' },
|
|
39
|
+
fixLocation: { type: 'string', enum: ['kit', 'app', 'server', 'kit+app'] },
|
|
40
|
+
fix: { type: 'string', description: 'concrete implementable change' },
|
|
41
|
+
severity: { type: 'string', enum: ['high', 'medium', 'low'] },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const VERDICT_SCHEMA = {
|
|
49
|
+
type: 'object',
|
|
50
|
+
required: ['isReal', 'reason'],
|
|
51
|
+
properties: {
|
|
52
|
+
isReal: { type: 'boolean' },
|
|
53
|
+
reason: { type: 'string' },
|
|
54
|
+
refinedFix: { type: 'string' },
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const LENSES = [
|
|
59
|
+
{
|
|
60
|
+
key: 'typography-rhythm',
|
|
61
|
+
prompt: `Lens: TYPOGRAPHY + VERTICAL RHYTHM. Audit the kit's type scale, weights, line-heights, and spacing rhythm across app-shell.css and component CSS vs a calm claude.ai/code feel: heading sizes vs body (is the H1 too loud relative to content?), panel/section title treatment (the ALL-CAPS small-caps labels), monospace leakage into non-code UI (footer status bar, stats, crumb), inconsistent font-size tokens between sibling surfaces (rail labels vs list rows vs toolbar), margin/padding rhythm breaking between stacked blocks (header->roots->crumb->toolbar->content gaps on files), and any place two adjacent surfaces use different spacing for the same relationship. 4-8 highest-leverage findings.`,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: 'copy-tone',
|
|
65
|
+
prompt: `Lens: COPY TONE + MICROCOPY. Sweep EVERY user-facing string in ${APP}/site/app/js/app.js and kit component defaults (empty states, placeholders, dialog titles/labels, alerts, announce() calls, button labels, settings panel text): inconsistent case (Title vs lower), dev jargon beyond the already-filed ccsniff/same-origin items (sid, cwd shown raw, 'ws clients', 'EACCES', protocol names), unclear or scary error copy without recovery guidance, inconsistent vocabulary for the same concept across tabs (session vs conversation vs chat), placeholder text that states the obvious, dangling or doubled separators in composed strings. 4-8 findings with exact strings.`,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'perceived-performance',
|
|
69
|
+
prompt: `Lens: PERCEIVED PERFORMANCE. Audit loading/transition feel: which surfaces show NOTHING during their first load (files dir load? agents list? history events? settings health?), skeleton coverage vs spinner vs blank (ConversationList has skeletons - who else needs them), the first-paint sequence of the SPA (what does the user see between index.html and first render - blank? flash of unstyled?), optimistic updates on mutations (rename/delete/mkdir wait for server round-trip - do rows flash?), the markdown stack fetching from jsdelivr on FIRST chat render (visible stall? preload opportunity), tab-switch latency (does navTo re-fetch things it already has?), and streaming-render smoothness. 4-8 findings.`,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: 'kit-dx',
|
|
73
|
+
prompt: `Lens: KIT DX - the design SDK itself (${KIT}) as a published library a developer consumes. Audit: prop-naming consistency across components (onMark vs onSelect vs onAction vs onNav - is there a coherent convention?), components exporting inconsistent shapes (some take {children}, some positional), dead/unused exports in src/components.js, undocumented load-bearing props (the README/demo coverage of AgentChat, FileGrid, SessionDashboard, WorkspaceShell - does the demo show the flagship surfaces?), the null-children webjsx crash class (are there remaining unwrapped conditional children arrays in kit components - grep for '? h(' patterns NOT wrapped in filter(Boolean)), CSS class naming drift (.ds-* vs .ws-* vs .chat-* vs .agentchat-* - is the prefixing rule coherent?), and build/lint gaps (lint-tokens/lint-glyphs exist - what obvious lint is missing, e.g. the null-children pattern). 4-8 findings.`,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: 'light-theme-contrast',
|
|
77
|
+
prompt: `Lens: LIGHT (paper) THEME FIDELITY. The app has dark (ink) and light (paper) themes; prior runs witnessed almost exclusively dark. Audit the kit token definitions and component CSS for paper-theme issues: status tones (green/purple/flame rails, status-dot-disc variants) - do they meet WCAG 3:1 against the paper bg, code-block / pre backgrounds in light (is there a distinct token or does it reuse dark values), .chat-msg-flat assistant-turn tint visibility in light, scrim/overlay opacity in light, hover/active states that rely on lightening (invisible on light bg), selection tint, hairline visibility (--rule against rgb(246,245,241)), green accent button text contrast, and any hardcoded dark-only color in component CSS that bypasses tokens (grep hex literals in kit CSS). 4-8 findings.`,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: 'interaction-density',
|
|
81
|
+
prompt: `Lens: INTERACTION DENSITY + CONTROL CRAFT. Beyond the already-filed toolbar items, audit control sizing/shape coherence kit-wide: how many distinct button treatments exist (stadium pill, r-1 rect, ghost, icon, danger) and whether their usage follows a rule (primary vs secondary vs toolbar vs destructive); Select/SearchInput/filter input heights vs button heights on the same row (do they align?); checkbox/radio custom treatments vs native; dialog button order and destructive placement consistency (ConfirmDialog vs inline Alert confirms - same order?); list-row action affordances (reveal-on-hover vs always-visible - coherent rule incl. coarse pointer?); chip/tag/badge treatments (errors-only chip, permissions tag, status pill, count badge - coherent family?); focus ring consistency across all of these. 4-8 findings.`,
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
phase('Hunt')
|
|
86
|
+
const results = await pipeline(
|
|
87
|
+
LENSES,
|
|
88
|
+
l => agent(COMMON + '\n' + l.prompt + '\n\nReturn findings via the structured output schema; ids prefixed ' + l.key + '-.', { label: 'hunt:' + l.key, phase: 'Hunt', schema: FINDINGS_SCHEMA }),
|
|
89
|
+
(res, l) => {
|
|
90
|
+
if (!res || !res.findings || !res.findings.length) return []
|
|
91
|
+
return parallel(res.findings.map(f => () =>
|
|
92
|
+
agent(
|
|
93
|
+
COMMON + `\nYou are an ADVERSARIAL VERIFIER. A hunter claims:\nTITLE: ${f.title}\nEVIDENCE: ${f.evidence}\nPROPOSED FIX: ${f.fix}\nfixLocation: ${f.fixLocation}\n\nRead the cited source yourself. Refute it if: the evidence is wrong or stale, the behavior is intentional kept design (especially kept typography: middot/ellipsis/dash), it duplicates an already-filed finding from the guard list, the fix is not implementable this session, or the severity is inflated. Default isReal=false when uncertain. If real, refine the fix to the most concrete minimal change.`,
|
|
94
|
+
{ label: 'verify:' + f.id, phase: 'Verify', schema: VERDICT_SCHEMA }
|
|
95
|
+
).then(v => ({ ...f, verdict: v }))
|
|
96
|
+
))
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
const confirmed = results.flat().filter(Boolean).filter(f => f.verdict && f.verdict.isReal)
|
|
100
|
+
log(`confirmed ${confirmed.length} findings`)
|
|
101
|
+
return { confirmed: confirmed.map(f => ({ id: f.id, title: f.title, severity: f.severity, fixLocation: f.fixLocation, evidence: f.evidence, fix: f.verdict.refinedFix || f.fix, verifierReason: f.verdict.reason })) }
|
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
+
## UX-craft sweep + empirical-witness-first (2026-06-11) — twelfth run
|
|
4
|
+
|
|
5
|
+
Two-track run: EMPIRICAL baseline witnessing of the live page found 18 shipped janks BEFORE theorizing, then a fresh hunt workflow `.claude/workflows/gui-ux-craft.js` (6 lenses the 11 prior sweeps never used: typography-rhythm, copy-tone, perceived-performance, kit-DX, light-theme-contrast, interaction-density; 46 agents -> 40 confirmed, `PUNCHLIST-UX.md`). ALL 58 implemented. Server on this env runs `PORT=3009` (3000 owned by another app).
|
|
6
|
+
|
|
7
|
+
**Load-bearing shipped-bug discoveries (the live page as debugger).**
|
|
8
|
+
(1) **The live tab's "1 running over No-live-sessions" contradiction was a webjsx applyDiff CRASH** (reading 'key'), reproduced via `window.__agentgui.render()` in page.evaluate: SessionDashboard swapped its UNKEYED empty-state body for keyed group children, so the diff died mid-apply leaving the header updated and the body stale. Fix: ONE stable keyed `.ds-dash-groups` body across empty/grouped/flat (the ConversationList stable-keyed-body rule) + `Btn` now passes `key` through (it silently DROPPED it before) + no stop control when empty + kit `emptyAction` CTA prop. (2) **The mobile drawers were dead in production**: base `.ws-drawer-toggle/.ws-scrim { display:none }` sat AFTER the media blocks - same specificity, later source order wins regardless of media. CSS-order class of bug; base-hidden rules must PRECEDE their media reveals. (3) **The composer cwd bit was an invisible dead button**: app passes `{label}`, kit read only `.text` - the prop-name-contract failure mode AGENTS.md already warned about; ChatComposer now normalizes text||label and drops empty bits BEFORE separators (kills the dangling middot too). (4) **The 11th run's multi-select checkbox was hover-hidden/clipped in the shipped bundle**: a stale duplicate `.ds-file-check` absolute-overlay block later in app-shell.css clobbered the real in-flow rules. (5) `lint-null-children.mjs` (new build gate) immediately caught **14 latent crash sites in freddie.js**.
|
|
9
|
+
|
|
10
|
+
**Layout architecture: staged column yield.** `.ws-shell` now yields columns to the CONTENT in stages: pane track -> right overlay drawer at <=1480px, sessions track -> left drawer at <=1100px, rail -> fixed 60px icon strip below 900px (labels hidden UNCONDITIONALLY - a 60px rail showing clipped 'age'/'Ne' text was the witnessed 420px regression). The chat thread at 1304px went from ~245px (crushed by a 380px context pane) to 776px. Drawer width is a literal (not --ws-pane-w which is 0 when collapsed); `.ws-pane-open.ws-pane-collapsed` un-hides pane children via `display: revert`.
|
|
11
|
+
|
|
12
|
+
**Content-first surfaces.** `PageHeader` gained `dense` (one row: small h1 + one-line ellipsized lede; 24px instead of ~180px) - all five tabs use it. DropZone with children is a passive wrapper (dashed overlay ONLY during drag; `ds-dropzone--wrap`). Files: ONE breadcrumb (top crumb says just 'files'; in-page BreadcrumbPath navigates), compact ghost toolbar (`.ds-file-toolbar .btn` 32px/r-1), compact right-aligned filter, `.ds-files-stack` 16px rhythm wrapper in app. FileGrid skeleton only on COLD load; refresh dims in place (`is-refreshing`). History rail flame derives from error DENSITY (`sessionErrorDense`: errors>=3 AND >15% of events - tool errors are routine, every real session had 1-2%) and title==project rows drop the duplicate sub.
|
|
13
|
+
|
|
14
|
+
**Theme/token work.** `--flame`/`--amber` are now theme-tuned pairs (light #C53E00/#8A6512 pass AA on paper; dark keeps #FF5A1F/#D9A93A - they were dark-tuned only, 2.9:1/2.0:1 on paper); `--amber` was referenced 8x but NEVER DEFINED (hardcoded fallbacks). Five `--code-*` syntax-token aliases (light AA, dark brights) feed both Prism palettes + static pre. Destructive ACTIONS are warn; flame is exclusively error STATUS. `ThemeToggle` compact says 'theme: auto|light|dark' (ink/paper codenames only in title) + CSS half-disc for icon-only strips.
|
|
15
|
+
|
|
16
|
+
**Control craft.** One 32px/r-1 metric for agentchat-controls, dash-header, file toolbar, BulkBar (quiet warn-outline destructive; arm state goes loud); two compact-button tiers consolidated at chat.css END (later-file wins by order - chat.css loads after app-shell.css in the bundle); focus rings unified on inset accent; `.ds-select` ellipsizes + `:focus-visible`; cancel-before-destructive in app banners (matches ConfirmDialog); history subagent toggle is the kit Checkbox.
|
|
17
|
+
|
|
18
|
+
**Perceived perf.** index.html: 3x modulepreload + jsdelivr preconnect + static boot-splash in #app. AgentChat warms the markdown stack on mount; MdNode paints raw text synchronously while the loader is in flight (streamed tokens were invisible on cold start). EventList gained a loading skeleton (history events pane); agents panel has a loading/error/empty tri-state (`state.agentsLoading`).
|
|
19
|
+
|
|
20
|
+
**Server.** `POST /api/move` (dual realpath confinement, root/self-nesting refusal, 409-unless-overwrite, never overwrites a dir, EXDEV mapped) + `backend.js moveEntry` + BulkBar 'move selected' -> bulk-move PromptDialog -> `runBulkMove` (upfront dest stat, allSettled, failures stay marked). `validate-mutations.mjs` now 26 checks (9 move cases) - run it after touching the mutation surface.
|
|
21
|
+
|
|
22
|
+
**Kit DX.** COMPONENT_API.md gained a 'Workspace Surfaces' section documenting every flagship contract (AgentChat incl. the onPasteFiles-not-onPasteImage trap, WorkspaceShell stableFrame/mainFlush, SessionDashboard, FileGrid selection/density, BulkBar, DropZone wrapper semantics) + an honest CSS-taxonomy section. FileGrid accepts canonical `selected`/`onToggleSelect` (marked/onMark stay as aliases). `Icon`/`iconMarkup` accept the props-object form. 22 deprecated `Btn primary:true` call sites -> `variant:'primary'`; AgentChat `who` -> `role`. Build now runs FOUR lints: tokens, glyphs, null-children, classes (class-prefix taxonomy with a frozen bare-name allowlist).
|
|
23
|
+
|
|
24
|
+
**Witness caveats (this env).** The spool out/ dir keeps STALE responses from prior sessions - a Read racing the watcher's write returns old bytes; re-read when content doesn't match your probe. plugkit browser sessions expire between dispatches (a fresh session needs a full goto). The first git_status after heavy file churn can report stat-cache false positives (empty git_diff resolves them).
|
|
25
|
+
|
|
26
|
+
## Files command surface + PASSWORD-boot fix (2026-06-11) — eleventh run
|
|
27
|
+
|
|
28
|
+
Lands the 10th run's deferred batch + the janks a live witness surfaced on this env. **Kit path on this (linux) env is `../design` = `/config/workspace/design`** (same repo as `c:\dev\anentrypoint-design` on the windows env); update flow unchanged: edit kit -> `node scripts/build.mjs` -> copy `dist/247420.{js,css}` into `site/app/vendor/anentrypoint-design/` -> witness -> push both.
|
|
29
|
+
|
|
30
|
+
**CRITICAL fix - PASSWORD-gated deploys could never boot the SPA.** `/gm/?token=` served index.html but the static subresources (`gm/js/app.js`, `gm/vendor/247420.{js,css}`) carry no token -> 401 -> blank page forever (witnessed: `readyState` stuck `loading`, `hasAgentgui:false`). `lib/http-handler.js` now sets an HttpOnly SameSite=Lax `agentgui_token` cookie (URL-encoded) on any successful auth and the gate accepts it; WS keeps `?token=`. Lax + the CSRF guard keep cross-site mutations rejected (a cross-site form never carries the Lax cookie on POST).
|
|
31
|
+
|
|
32
|
+
**Files is a command surface.** Kit `FileGrid` gains multi-select (`selectable`/`marked` Set keyed by path/`onMark({range})` shift-ranges/`onSelectAll`/`onClearSelection`, tri-state `[x]/[-]/[ ]` header checkbox over SHOWN rows, EACCES rows unmarkable, Ctrl/Cmd+A in-grid) + density modes (`density` list/compact/thumb + `onDensity` radiogroup; thumb tiles via `FileCell` with lazy `thumbUrl` images) + new `BulkBar` export (`{count,noun,nounPlural,actions,onClear,busy}`, pluralizes `-y` nouns). App: `state.files.marked` (cleared on dir change, pruned on refresh), BulkBar -> armed `bulk-delete` ConfirmDialog -> `Promise.allSettled` over the confined delete (failures STAY selected + count in dialog), Escape clears selection (ladder slot after stop-arms), density persisted in `agentgui.files`. **thumbUrl uses `downloadUrl` (fsAllowRoots) NOT `imageUrl` - `/api/image` has its own narrower allowlist and 403s repo files; `<img>` ignores the attachment disposition.**
|
|
33
|
+
|
|
34
|
+
**Shipped-jank fixes the witness caught.** (1) `.ds-file-open` (run 5) never had CSS - FileRow's UA-styled button sat in a grid sized for the old flat children; row+open are now flex strips with a full button reset. (2) filesMain DROPPED `permissions` in its entry mapping - the EACCES/read-only affordances were dead on the files tab. (3) The Crumb narrow collapse keys on the `.app` @container which doesn't exist under WorkspaceShell -> `.crumb-right` overflowed 420px viewports (h-scroll); mirrored into the `.ws-*` 900px media block. (4) webjsx attr-diff can leave a null-valued attribute unset when toggling - `data-density` is now always concrete. (5) F3 elevation unification: `.panel` = bg-2 + hairline + r-2 (no `--panel-shadow`), seg-control is-on = inset ring, chat image/pdf/link hover lift shadows dropped; overlay shadows (modal, jump pill) stay.
|
|
35
|
+
|
|
36
|
+
**Env/tooling.** `scripts/validate-mutations.mjs` is now portable (ROOT from env/cwd, sep-aware joins, posix traversal targets, Bearer from PASSWORD; csrf case expects 401 under PASSWORD / 403 open) - 17/17 PASS on this env. Browser witnessing here: plugkit's chromium needs `--no-sandbox` (written to `/etc/chromium.d/no-sandbox`); `page.goto` waits on hung CDN subresources so use `waitUntil:'commit'` + `waitForSelector`; the witness body is shell-interpolated (NEVER use `$(...)`/backticks - use `page.locator(...)`); same-URL `goto` with only a hash change does NOT reload (use `page.reload()` after re-vendoring).
|
|
37
|
+
|
|
3
38
|
## GUI Claude-Code-web parity sweep (2026-06-11) — tenth maximum-effort run
|
|
4
39
|
|
|
5
40
|
Hunts the VISUAL + LAYOUT + MOTION design-language parity gap vs claude.ai/code (the user verdict: too primitive, layout jank). New workflow `.claude/workflows/gui-claude-code-parity.js` (6 design-language lenses: visual-language, layout-composition, chat-thread-craft, file-browser-fidelity, live-session-command, motion-microinteraction; hunt -> adversarial verify (kept-typography guard) -> plan). 66 agents -> 37 confirmed gaps (`PUNCHLIST-PARITY.md`). Pushed: kit `anentrypoint-design` 28387c3, agentgui 0a93fc6.
|
|
@@ -38,21 +73,7 @@ Coverage run reversing the prior scope cuts. Workflow `.claude/workflows/gui-com
|
|
|
38
73
|
|
|
39
74
|
## GUI cohesion sweep (2026-06-10) — seventh maximum-effort run
|
|
40
75
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
**Chat reads like a chat agent.** Every fenced code block has a per-block copy button: kit `chat.js` `injectCodeCopy()` wraps each rendered-markdown `<pre>` in `.chat-code-block` and injects a reveal-on-hover `.chat-code-copy` (idempotent via `data-copy-wired`, label flips copy->copied); the structured `CodeNode` head and `FilePreviewCode` header carry the same control. `ChatMessage` per-message actions render a text label beside the icon and use a real `copy` icon (not `page`). Mid-stream prose containing a code fence renders as a monospaced `<pre>` shell (`agent-chat.js` sets `preShell`, `chat.js` text renderer honors it) so it does not reflow prose->block on settle. `ChatComposer` shows a `context` line (agent · model · cwd) at the point of typing; `AgentChat` threads a stable per-agent `avatar` and `followups` chips after a settled turn.
|
|
44
|
-
|
|
45
|
-
**Files is an fsbrowse-grade browser.** Kit `files.js` `FileGrid` caps a large dir at `FILE_GRID_CAP=200` with a `shown`/`onShowMore` "show N more" row, uses `role=group` (NOT `listbox` — the rows host real action `<button>`s, which is invalid listbox/option semantics), `FileRow` shows a `permissions`/`locked` ASCII tag (`read-only`/`no access`) and disables open for EACCES, and a `RootsPicker` segmented control replaces the borrowed history `.pill`. `files-modals.js` ships `FilePreviewPane` (a non-modal split-view region for the shell pane) alongside the modal `FileViewer` (kept as the `<900px` fallback), both with an ASCII `prev`/`next` stepper (`onPrev`/`onNext` + ArrowLeft/Right). The app renders the preview INTO the WorkspaceShell pane when wide, modal only when narrow.
|
|
46
|
-
|
|
47
|
-
**All live sessions, managed at once.** Kit `sessions.js` `SessionCard` gains a `stale` status (`idle` word + non-pulsing `.status-dot-stale`, so a stuck agent differs from a busy one), a `selectable` checkbox (`role=checkbox`), and an `active` accent. `SessionDashboard` gains a sort `Select` (status/elapsed/activity/errors) + filter `SearchInput` + errors-only toggle, `stop-selected` bulk control, and a `streamState` line (the dashboard is listening even at 0 running). App `liveMain` derives `stale` (no activity >45s and no running tool), floats error-then-stale to the front, and keeps a per-sid `state.live.tally` incremented straight off the SSE stream so a brand-new chat shows motion before it lands in the history index.
|
|
48
|
-
|
|
49
|
-
**One shell, one visual system.** Kit `shell.js` `WorkspaceShell` `stableFrame` keeps the pane grid TRACK present (width 0) when a tab has no pane, so the column geometry does not re-flow across tabs. There is ONE canonical `.status-dot-disc` (`status-dot-live` pulses via `color-mix`, `-error`/`-connecting`/`-stale` static, reduced-motion guarded) — `index.html`'s `.status-dot`/`agentgui-pulse` override is deleted and the crumb dot uses the kit modifier classes. `.ds-session-row.rail-*` tones now match `.row.rail-*` (accent/purple-2/flame). The rail footer pins a `ThemeToggle`; page titles are sentence-case. Touch targets floor to 44px under `@media (pointer:coarse)`.
|
|
50
|
-
|
|
51
|
-
**Server.** `lib/http-handler.js` `/api/list` reports a per-entry `permissions` (`['read','write']` | `'EACCES'`) via `fs.accessSync`. New confined `/api/download` (raw bytes, `confineToRoots` realpath, 50MB cap, attachment disposition) — verified to 403 both out-of-roots and traversal. `backend.js` `listDir` carries `r.status` so the app maps 403/404 to plain copy; `downloadUrl()` is token-threaded.
|
|
52
|
-
|
|
53
|
-
**Scope cuts (documented in punch-list, not gaps).** File rename/delete (read-only browser, no mutation endpoints), upload/DropZone (legacy `routes-upload.js` is conversationId-keyed, not reusable), retry kept last-turn-only (mid-thread retry would destroy history).
|
|
54
|
-
|
|
55
|
-
**Witness.** localhost:3000/gm/ 0 console/page errors across chat/files/live/settings/history; per-block code copy + preview pane (opens with prev/next stepper) + dashboard stream line render; whole-DOM decorative-glyph count 0 (kept middot/ellipsis/dash); no h-scroll; a11y skip-link/`role=group`/`role=checkbox`/44px verified. Kit `lint-tokens`+`lint-glyphs` pass on build. **The app.js `C` destructure MUST list every kit component it calls (`Icon`/`RootsPicker`/`FilePreviewPane` were missing — the browser witness caught `Icon is not defined`).** Update flow unchanged: edit kit -> `node scripts/build.mjs` -> copy `dist/247420.{js,css}` into `site/app/vendor/anentrypoint-design/` -> witness -> push kit (rebase + rebuild dist when remote advances).
|
|
76
|
+
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`).
|
|
56
77
|
|
|
57
78
|
## GUI predictability + polish sweep (2026-06-05) — fifth maximum-effort run
|
|
58
79
|
|
|
@@ -96,17 +117,7 @@ Dependencies:
|
|
|
96
117
|
|
|
97
118
|
## GUI audit pass (2026-06-04) — structured chat, predictable presentation
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- **Structured tool cards in chat.** `app.js sendChat` now emits structured parts — `toolPart()` builds `{kind:'tool',name,label,args,status,_id}` and `applyToolResult()` matches a `tool_result` back to its `tool_use` by id (sets `result`+done/error status). The kit `AgentChat` passes structured `{kind,...}` parts straight through to `ChatMessage.renderPart` (only bare strings are wrapped as text), so the kit's collapsible `ToolCallNode` (args/result sections, status icons) renders instead of the old flattened `'-> '+text`. Full args/result live in the card (no 120/160-char truncation).
|
|
102
|
-
- **AgentChat kit additions** (`src/components/agent-chat.js`): empty state (`.agentchat-empty*`, title/sub/`suggestions`+`onSuggestionClick`), composer stop button while streaming (`busy`+`onCancel:onStop` into `ChatComposer`), a `working…` tail (`.agentchat-working`) when a content-bearing turn is still streaming (silent tool runs no longer read as frozen). CSS in `chat.css`.
|
|
103
|
-
- **Streaming render is rAF-coalesced** via `scheduleStreamRender()` (was render+scroll per token).
|
|
104
|
-
- **Multi-turn resume wired end-to-end.** Server `chat.sendMessage` is one-shot (new ephemeral `chat-` id per call); claude's real session id is `parsed.session_id` in the stream. `ws-handlers-util.js onEvent` now broadcasts `streaming_session{claudeSessionId}` once; `backend.js` yields `{type:'session'}`; `app.js` captures it into `state.chat.resumeSid` (claude-code only) + persists, so the next turn `--resume`s.
|
|
105
|
-
- **Skip link works.** Kit `AppShell` `<main id=app-main>` now has `tabindex=-1` so the skip-link moves focus, not just scrolls.
|
|
106
|
-
- **History:** `state.eventsLimit` (default 300, reset per session) + `load N older` control (no more silently-unreachable older events); expand-all/collapse-all; per-event rail tone (green=normal, purple=tool_use, flame=error) matching the GUI-wide rail semantics; search hits carry `{focusEventI,focusEventTs}` so a click scrolls to + flashes (`.event-flash`) the matched event; mobile drawer auto-closes on session select (`loadSession` removes `.side-open` since DS only auto-closes on `<a>` clicks).
|
|
107
|
-
- **Security** (`lib/http-handler.js`): `/api/image` confined to an allowlist root (`CLAUDE_PROJECTS_DIR`, home, `IMAGE_ROOTS`) — was arbitrary-file-read (the `..` check was a no-op after `path.normalize`); CORS no longer advertises `Access-Control-Allow-Origin:*` when `PASSWORD` is set (reflects `CORS_ORIGIN` if set, else same-origin only). Markdown XSS verified inert (DOMPurify strips script/onerror/`javascript:`).
|
|
108
|
-
- **Consistency:** unified ellipsis to `…` (kept set); settings health chip uses connection vocab (`connected/connecting/offline`) matching the crumb dot; running-chats panel now shows on chat tab too (extracted `runningPanel()`); aborted-empty turns pruned from persisted/restored chat; restored transcript reopens under its own agent (`restoredAgent`).
|
|
109
|
-
- **Workflow:** `.claude/workflows/gui-audit.js` — a reusable multi-agent GUI-audit workflow (per-surface reviewers -> adversarial verify -> synthesize, kit-vs-app fixLocation).
|
|
120
|
+
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").
|
|
110
121
|
|
|
111
122
|
## Orchestration agents
|
|
112
123
|
|
|
@@ -154,18 +165,7 @@ Pattern: all imports in lib/plugins/* must be either built-in (crypto, fs, path,
|
|
|
154
165
|
|
|
155
166
|
## GM Plugin Autonomy Blocker
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
The gm plugin enforces a gate via `.gm/needs-gm` marker that requires invoking `gm:gm` before any other tool use, which fragments multi-tool autonomous sessions in agentgui. A bypass patch was committed to c:/dev/gm (commit e300acf7, origin/main) in gm-starter/hooks/{pre-tool-use,prompt-submit}-hook.js to skip the gate when `.gm/prd.yml` exists, but it did NOT propagate after `/plugin update gm` (cache hash changed 495e36843d77 -> 075e64d58498 but hook content unchanged).
|
|
160
|
-
|
|
161
|
-
The actual hook content is generated/templated from c:/dev/gm, likely from `lib/cli-adapter.js` or `platforms/cli-config-shared.js` or `lib/template-builder.js`, not from gm-starter/hooks/. Next session must:
|
|
162
|
-
1. Locate the real hook generator in the gm codebase
|
|
163
|
-
2. Patch it to add `if (autonomous) { try { fs.unlinkSync(needsGmPath); } catch {} }` when `.gm/prd.yml` exists
|
|
164
|
-
3. Rebuild via `node c:/dev/gm/cli.js c:/dev/gm/gm-starter c:/dev/gm/build`
|
|
165
|
-
4. Push changes to c:/dev/gm origin/main
|
|
166
|
-
5. Run `/plugin update gm` in agentgui
|
|
167
|
-
|
|
168
|
-
Only after the real generator is patched will agentgui sessions run autonomously without per-tool ceremony.
|
|
168
|
+
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. Full diagnosis + fix path in rs-learn (recall "agentgui GM plugin autonomy blocker").
|
|
169
169
|
|
|
170
170
|
## History Integration via ccsniff (2026-05-21 — reverted from acptoapi)
|
|
171
171
|
|
|
@@ -248,3 +248,5 @@ GUI source keeps typographic product characters — the middot separator `·`, t
|
|
|
248
248
|
## DS load = LOCAL vendor (resolved — the earlier unpkg note is stale)
|
|
249
249
|
|
|
250
250
|
**`index.html` loads the DS kit from the local `./vendor/anentrypoint-design/247420.{js,css}`, NOT unpkg.** The prior "moved to unpkg @latest" note described a transient state that was reverted: the kit was re-vendored (with `AgentChat`) in `eb1eab3` and witnessed loading from `./vendor/` again (2026-06-04 and 2026-06-05 runs). The vendored copy IS the shipped UI — predictable, no upstream-publish drift. 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/`, browser-witness, then push the kit so unpkg stays in sync for other consumers. (The markdown stack marked/dompurify/prismjs still fetches from jsdelivr on first chat render.)
|
|
251
|
+
|
|
252
|
+
@.gm/next-step.md
|
package/PUNCHLIST-PARITY.md
CHANGED
|
@@ -34,3 +34,9 @@ build.mjs -> copy dist into site/app/vendor -> witness localhost:3000/gm/ (0 err
|
|
|
34
34
|
|
|
35
35
|
## Descoped
|
|
36
36
|
- `/api/move-confined` drag-to-move endpoint: checkbox + bulk-delete uses the existing delete loop; new endpoint cut unless drag-to-move lands.
|
|
37
|
+
|
|
38
|
+
## Landed by the 11th run (2026-06-11)
|
|
39
|
+
- G-multiselect + BulkBar: kit FileGrid selectable/marked/onMark(range)/tri-state select-all + BulkBar export; app marked Set + armed bulk-delete via allSettled (failures stay selected); Escape clears; Ctrl/Cmd+A.
|
|
40
|
+
- G-density: list/compact/thumb radiogroup + FileCell thumbnail tiles (confined downloadUrl), persisted in agentgui.files.
|
|
41
|
+
- F3 elevation unification: .panel hairline+bg-2+r-2, no panel/card/hover drop-shadows; overlays keep theirs.
|
|
42
|
+
- Toolbar up-button + grid keys in SHORTCUTS: landed previously in 503f66e.
|