agentgui 1.0.1022 → 1.0.1023
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/memories/.flat-export-done +1 -1
- package/.gm/memories/mem-0131ff4869d86085-370.md +10 -0
- package/.gm/memories/mem-08a4a9e050a4deff-3048.md +8 -0
- package/.gm/memories/mem-09597ee0df9c9224-965.md +8 -0
- package/.gm/memories/mem-0993d156f571b619-1059.md +8 -0
- package/.gm/memories/mem-0d1408fa048b9923-1159.md +8 -0
- package/.gm/memories/mem-1781870426883-0-2340.md +8 -0
- package/.gm/memories/mem-1781943679146-0-1577.md +8 -0
- package/.gm/memories/mem-1781943722930-1-2318.md +8 -0
- package/.gm/memories/mem-1781943733304-2-2135.md +8 -0
- package/.gm/memories/mem-1781946701659-3-1665.md +8 -0
- package/.gm/memories/mem-1781952323283-0-2146.md +8 -0
- package/.gm/memories/mem-1781961165110-1-2041.md +8 -0
- package/.gm/memories/mem-1781966495635-2-1606.md +8 -0
- package/.gm/memories/mem-39a7cc2f887a90b1-1079.md +8 -0
- package/.gm/memories/mem-4bafafa47a0e4b6c-3237.md +8 -0
- package/.gm/memories/mem-4c06c45b4d31bc60-1202.md +8 -0
- package/.gm/memories/mem-4ecd3b713e384170-122.md +10 -0
- package/.gm/memories/mem-51d8992a3c6f6c9c-1073.md +8 -0
- package/.gm/memories/mem-539eee7e8c6c10ee-2557.md +8 -0
- package/.gm/memories/mem-6224f8d185797f2b-1047.md +8 -0
- package/.gm/memories/mem-66b0947b946f3437-1155.md +8 -0
- package/.gm/memories/mem-6bdf783a1f6be7c2-1062.md +8 -0
- package/.gm/memories/mem-70d96acb736af2d7-685.md +8 -0
- package/.gm/memories/mem-7535f34f430fc196-1340.md +8 -0
- package/.gm/memories/mem-861a588d2773681a-1311.md +8 -0
- package/.gm/memories/mem-9329105b05b9c0f6-324.md +10 -0
- package/.gm/memories/mem-94f30cec3c283f97-782.md +10 -0
- package/.gm/memories/mem-956d4813319f65a3-1710.md +8 -0
- package/.gm/memories/mem-a52933cd6495e6f5-2624.md +8 -0
- package/.gm/memories/mem-a95b1d49d71133ce-1007.md +8 -0
- package/.gm/memories/mem-aaeae38d8eb01809-1076.md +8 -0
- package/.gm/memories/mem-b06b8c85b81663e6-1250.md +8 -0
- package/.gm/memories/mem-bdf466854032cac9-1509.md +8 -0
- package/.gm/memories/mem-cda639547932c796-713.md +8 -0
- package/.gm/memories/mem-cf8472c84d9e04c4-1883.md +8 -0
- package/.gm/memories/mem-d060480435f92eec-1146.md +8 -0
- package/.gm/memories/mem-d347c921b79e6d44-1099.md +8 -0
- package/.gm/memories/mem-d3c8ea6c861bfbb8-1457.md +8 -0
- package/.gm/memories/mem-d5e928c552cd87f9-214.md +10 -0
- package/.gm/memories/mem-d63bc3b8a0269844-406.md +10 -0
- package/.gm/memories/mem-da1c91acf63d81d3-863.md +8 -0
- package/.gm/memories/mem-dceeae20bc56d407-711.md +8 -0
- package/.gm/memories/mem-df74674eec7745ac-178.md +10 -0
- package/.gm/memories/mem-e1d5431ae2542872-961.md +8 -0
- package/.gm/memories/mem-ebbe6c0694c526f0-1392.md +8 -0
- package/.gm/memories/mem-ebf85becc23410b0-1633.md +8 -0
- package/.gm/memories/mem-ee8858162518f144-1252.md +8 -0
- package/.gm/memories/mem-f3f317c083d979ee-1210.md +8 -0
- package/.gm/memories/mem-f786bc1626d92845-204.md +10 -0
- package/.gm/memories/mem-ff8669e527e5c427-2788.md +8 -0
- package/.gm/prd.yml +96 -0
- package/AGENTS.md +4 -0
- package/package.json +1 -1
- package/site/app/index.html +4 -0
- package/site/app/js/app.js +56 -28
- package/site/app/vendor/anentrypoint-design/247420.css +1286 -213
- package/site/app/vendor/anentrypoint-design/247420.js +32 -33
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: mem-f786bc1626d92845-204
|
|
3
|
+
ns: default
|
|
4
|
+
created: 1781783463123
|
|
5
|
+
updated: 1781783463123
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Resolved mutable: server-3009-state
|
|
9
|
+
|
|
10
|
+
ss/netstat | grep 3009 = no listener; ps aux | grep -E 'bun server|node server' = no process. Must start PORT=3009 bun server.js (run_in_background) before witness.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: mem-ff8669e527e5c427-2788
|
|
3
|
+
ns: default
|
|
4
|
+
created: 1781786013354
|
|
5
|
+
updated: 1781786013354
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
agentgui 14th run (2026-06-18): design-maturity sweep + LAST residue (site/theme.mjs, the flatspace marketing renderer - NOT the SPA). theme.mjs had inline <style>+hex(#FBF6EB/#1F1B16), ~12 inline style=, deprecated C.Btn({primary}), 2x ↗ glyphs - ALL migrated to a NEW kit marketing.css .site-* family (.site-panel/.site-hero/.site-hero-h/.site-hero-body/.site-chip-row/.site-cta-row/.site-cli+.cli/.prompt/.cmd/.site-embed, pre-scoped .ds-247420, wired into build.mjs cssParts + lint-glyphs SCAN_ROOT_FILES). KEY: kit Panel/Heading only accepted `style` not `class` - added a `class` prop to both (content.js Panel, shell.js Heading) so consumers attach classes. Btn already had `variant` (primary->variant:'primary'). theme.mjs head now render-blocking-<link>s 247420.css (was JS-importmap-only, so inline <style> was its FOUC guard); kit already owns base surface at app-surfaces.css:27 '.ds-247420 body{background:var(--bg);color:var(--fg);font-family:var(--ff-display)}'. flatspace is NOT a dep on this env; theme.mjs is a pure render fn. Marketing tracks unpkg@latest, SPA ships pinned vendored dist (intentional). Workflow gui-design-14 (Workflow tool, NOT a .claude/workflows file this time - inline script): 46 agents, 39 findings, 28 confirmed (PUNCHLIST-DESIGN-14.md). Landed in kit: chat ThinkingNode base CSS (.chat-thinking* had zero base rules outside .agentchat-working), markdown table/th/td/hr (unstyled), dead .chat-tick rule, composer toolbar 32px/--r-1 (was 40px-round vs 36px-square), flat .chat-md rhythm, .chat-stream-pre chrome, tool/code :has() measure-breakout; files FileSkeleton container-bar->inner .ds-skel only, filter folded into one .ds-file-controls row, per-type cell tints, dead data-columns removed, .ds-file-check dead decls; sessions stale!=connecting disc tones+shapes, dead dup .ds-dash-status.is-running removed (running unified --accent), .seg.is-idle weight 600, reduced-motion live-disc static ring, mixed-tick 2px, cost as .ds-dash-stat-cost, conv-list unread hollow ring; shell resizers hidden past staging breakpoints (@media 1480/1100/900 - were dead handles), coarse 16px target, WS_RESIZE_CLAMP reconciled to CSS clamp, localStorage on pointerup not per-move, separator aria-valuemin/max/now; a11y voice vx-* reduced-motion guard, status discs non-colour SHAPE channels (live solid+pulse/error solid+halo/connecting hollow/stale muted), .ds-input-bare :focus->:focus-visible. Server PORT=3009 PASSWORD=123,slam,123,slam; run_in_background:true keeps it alive (setsid/nohup detached got exit 144 sandbox-killed). Witnessed via plugkit browser verb ?token=: 0 errors, body painted by kit (rgb 19,19,24 dark), 3 resizers, no h-scroll. Kit pushed 3704876 (rebased onto concurrent CI v0.0.211 bump); agentgui re-vendored dist + theme.mjs.
|
package/.gm/prd.yml
CHANGED
|
@@ -2454,3 +2454,99 @@
|
|
|
2454
2454
|
title: 'Verify zero legacy timestamp-keyed md files, flat JSON dirs byte-unchanged (23 flat: 22 default + 1 agentgui), engine writes md not flat JSON'
|
|
2455
2455
|
witness: 'exec_js 9015: md 23 (bad []), discipline md 1 (dbad []), flat_default 22 + flat_agentgui 1 byte-unchanged (flat_bytes 1352); md body embeds flat bytes verbatim under frontmatter; engine wrote only md on both memorize-fires'
|
|
2456
2456
|
status: completed
|
|
2457
|
+
- id: maxgui-run31-fanout-audit
|
|
2458
|
+
subject: Run maximal-effort multi-lens GUI critique workflow (usability, practicality, predictability, negative space, visual polish) across agentgui + kit
|
|
2459
|
+
witness: gui-ux-craft workflow (32 agents, 19 confirmed) + targeted negative-space live-browser audit agent both completed; findings triaged and highest-value fixes landed (ConfirmDialog destructive variant, settings double-gap, caps-label drift, copy-tone sidebar/external-session, mobile clipping x2, empty-state hierarchy, projects-folder copy btn)
|
|
2460
|
+
status: completed
|
|
2461
|
+
- id: maxgui-run31-verify-browser
|
|
2462
|
+
subject: Live-browser witness every landed fix at desktop+mobile widths, 0 console errors, screenshots before/after
|
|
2463
|
+
witness: 'Live browser session against localhost:3010/gm/ (no-PASSWORD instance) at 1280px+420px: settings panel gaps [24,24]px consistent (was 56px), history-empty title 18px > sub 16px (was inverted), delete ConfirmDialog button class btn-primary danger (was primary), PageHeader dense lede + chat composer-context wrap normally at 420px scrollWidth==clientWidth (was ellipsis-clipped), files checkbox select-all/individual/clear-selection + BulkBar functional after FileRow prop rename, 0 console errors throughout every navigation'
|
|
2464
|
+
status: completed
|
|
2465
|
+
- id: maxgui-run31-push-ci
|
|
2466
|
+
subject: Commit+push kit and app changes, watch CI green, write .ci-validated
|
|
2467
|
+
witness: standing CONSOLIDATE gate requirement
|
|
2468
|
+
status: pending
|
|
2469
|
+
- id: fix-chat-identity-repeat-mobile-clip
|
|
2470
|
+
subject: Chat tab identity repeated 3x (agent-chat.js h1 + composer context); mobile 420px composer-context clips text (278 vs 337 scrollWidth). Simplify duplication, fix clipping.
|
|
2471
|
+
witness: composer-context now wraps at <=480px instead of clipping (chat.css); browser-witnessed at 420px scrollWidth==clientWidth==278, text fully visible
|
|
2472
|
+
status: completed
|
|
2473
|
+
- id: fix-page-header-dense-lede-clip
|
|
2474
|
+
subject: ds-page-header-dense-lede overflow:hidden white-space:nowrap clips ~48-49% of text on History/Settings/Files/Live at 420px. Wrap or truncate gracefully.
|
|
2475
|
+
witness: app-shell.css lede wraps at <=480px instead of ellipsis-clipping; browser-witnessed settings/history/files/live all scrollWidth==clientWidth==296 at 420px, whiteSpace normal
|
|
2476
|
+
status: completed
|
|
2477
|
+
- id: fix-settings-projects-folder-copy-btn
|
|
2478
|
+
subject: Settings projects-folder fact lacks copy button unlike sibling root rows; clips at 420px with no recovery path. Add copy button matching root rows.
|
|
2479
|
+
witness: added onCopy to projects-folder fact in app.js serverPanel matching root rows
|
|
2480
|
+
status: completed
|
|
2481
|
+
- id: fix-search-filter-vocab-inconsistency
|
|
2482
|
+
subject: Inconsistent Search vs Filter vocabulary for identical client-side list-narrowing across sessions/files panels. Pick one term, apply consistently.
|
|
2483
|
+
witness: 'Investigated: search (762/814) is real server-side full-text search (2+ char, debouncedSearch); filter (files 1362/live 1730) is client-side substring narrowing of already-visible list. Different mechanics, correctly different verbs - not a bug. Resolved as reviewed-not-a-defect.'
|
|
2484
|
+
status: completed
|
|
2485
|
+
- id: fix-history-empty-state-hierarchy
|
|
2486
|
+
subject: History empty-state sub-line (.lede, 21px) renders larger than its own title (16.8px), inverting visual hierarchy. Use correct secondary-text style.
|
|
2487
|
+
witness: removed misapplied .lede class from history-empty-sub, fixed history-empty-title hardcoded 1.05rem to var(--fs-lg) token; browser-witnessed title 18px > sub 16px
|
|
2488
|
+
status: completed
|
|
2489
|
+
- id: wf-confirmdialog-destructive-danger
|
|
2490
|
+
subject: ConfirmDialog destructive prop was dead code; confirm button always rendered primary
|
|
2491
|
+
witness: landed and browser-witnessed live in this same run
|
|
2492
|
+
status: completed
|
|
2493
|
+
- id: wf-settings-double-gap-56px
|
|
2494
|
+
subject: Settings stacked panels had 56px gap (32px panel margin + 24px grid gap) vs 24px everywhere else
|
|
2495
|
+
witness: design/app-surfaces.css:161-166 .settings-grid > .panel margin-bottom:0 added; browser exec_js on live localhost:3010/gm/#tab=settings 1280px measured column-1 gaps [24,24]px (was 56px before fix)
|
|
2496
|
+
status: completed
|
|
2497
|
+
- id: wf-caps-label-size-drift
|
|
2498
|
+
subject: panel-head and table th used --fs-xs (14px) vs canonical .t-label --fs-tiny (13px) for same small-caps role
|
|
2499
|
+
witness: design/app-shell.css:583 panel-head font-size var(--fs-tiny) (was var(--fs-xs)), :898 table th font-size var(--fs-tiny) (was var(--fs-xs)); matches .t-label:76 canonical usage; kit build 0 lint errors
|
|
2500
|
+
status: completed
|
|
2501
|
+
- id: wf-copy-tone-sidebar-and-external-session
|
|
2502
|
+
subject: Error copy said sidebar (nowhere else used) instead of rail; agent label external session leaked internal jargon
|
|
2503
|
+
witness: agentgui/site/app/js/app.js:3470 changed retry via sidebar -> retry via the rail (matches rail vocabulary used at comments 291/345/594/683/818); app.js:1662 agent:external session -> agent:other tool
|
|
2504
|
+
status: completed
|
|
2505
|
+
- id: wf-copy-tone-conversation-vs-session
|
|
2506
|
+
subject: Same concept named conversation in rail/history and session in chat/live copy
|
|
2507
|
+
witness: agentgui/site/app/js/app.js:1547,1919-1923,2038,2666,2679 renamed session->conversation in all user-facing copy (resume banner, bulk-stop toast, export label, copy-id button, empty-state text)
|
|
2508
|
+
status: completed
|
|
2509
|
+
- id: wf-copy-tone-raw-sid-resume-banner
|
|
2510
|
+
subject: Resume banner surfaces raw truncated sid instead of human label
|
|
2511
|
+
witness: agentgui/site/app/js/app.js:2915-2921 new resumeSidLabel() helper (session title/project lookup, sid-slice fallback) wired into resume-banner text and follow-up chip text
|
|
2512
|
+
status: completed
|
|
2513
|
+
- id: wf-copy-tone-doubled-hyphen
|
|
2514
|
+
subject: Two string-composition styles both use inline hyphen separator, risking doubled hyphen
|
|
2515
|
+
witness: agentgui/site/app/js/app.js:1917-1923 resume-note now renders as a second .sub span instead of string-concatenated via hyphen delimiter
|
|
2516
|
+
status: completed
|
|
2517
|
+
- id: wf-perf-prism-preload
|
|
2518
|
+
subject: Prism CDN fetch has no resource hint unlike marked/dompurify
|
|
2519
|
+
witness: agentgui/site/app/index.html new link rel=preload as=script crossorigin for prism-core.min.js, matching design/src/highlight.js:9 PRISM_BASE URL
|
|
2520
|
+
status: completed
|
|
2521
|
+
- id: wf-perf-search-skeleton-flash
|
|
2522
|
+
subject: Search-mode ConversationList blows away visible results to skeleton on every debounced re-search
|
|
2523
|
+
witness: design/src/components/sessions.js:80 loading branch condition changed to (loading && !sessions.length), matches design/src/components/files.js:198 sibling pattern
|
|
2524
|
+
status: completed
|
|
2525
|
+
- id: wf-perf-file-mutation-roundtrip
|
|
2526
|
+
subject: Rename/delete/mkdir/bulk ops wait a second full dir fetch before row updates
|
|
2527
|
+
witness: agentgui/site/app/js/app.js runBulkDelete/runBulkMove splice completed entries from state.files.entries + render() immediately, loadDir() now fire-and-forget background reconcile instead of awaited before render; browser-witnessed select/deselect/BulkBar flow at localhost:3010/gm/#tab=files, 0 console errors
|
|
2528
|
+
status: completed
|
|
2529
|
+
- id: wf-perf-history-refetch
|
|
2530
|
+
subject: Every History tab entry unconditionally refetches full session list
|
|
2531
|
+
witness: agentgui/site/app/js/app.js:296 refreshHistory() now gated on !_historyLoadedOnce || staleness>5000ms; refreshHistory() stamps state._historyLoadedAt on success at line ~3339
|
|
2532
|
+
status: completed
|
|
2533
|
+
- id: wf-kit-filerow-move-undocumented
|
|
2534
|
+
subject: FileRow move action missing from COMPONENT_API.md docs
|
|
2535
|
+
witness: design/COMPONENT_API.md:112-113 added FileRow onAction enum line documenting download/rename/move/delete
|
|
2536
|
+
status: completed
|
|
2537
|
+
- id: wf-kit-readme-agentchat-flagship
|
|
2538
|
+
subject: README quickstart/feature list omits AgentChat/WorkspaceShell flagship surfaces
|
|
2539
|
+
witness: design/README.md what-in-the-box section adds multi-agent chat shell bullet (WorkspaceShell/WorkspaceRail/ConversationList/AgentChat/SessionDashboard) between the chat and file-browser bullets
|
|
2540
|
+
status: completed
|
|
2541
|
+
- id: wf-kit-freddie-exports-scope-note
|
|
2542
|
+
subject: components.js re-exports ~18 freddie.js page-builder functions with no doc of what/why
|
|
2543
|
+
witness: design/COMPONENT_API.md Overview section adds one-paragraph freddie.js re-export scope note (demo-site page builders, not general components)
|
|
2544
|
+
status: completed
|
|
2545
|
+
- id: wf-tag-family-perm-tag-tone
|
|
2546
|
+
subject: ds-file-perm-tag is-noaccess used bespoke border-mix instead of shared flame tone tokens
|
|
2547
|
+
witness: design/app-shell.css:1581-1585 ds-file-perm-tag.is-noaccess border-color changed from color-mix 40pct flame to solid var(--flame), plus doc comment on the 4-family tag-shape rule (badge/chip/perm-tag/pill)
|
|
2548
|
+
status: completed
|
|
2549
|
+
- id: wf-filerow-marked-selected-rename
|
|
2550
|
+
subject: FileRow native selection prop names (marked/onMark) diverge from shared selected/onToggleSelect contract
|
|
2551
|
+
witness: design/src/components/files.js FileRow+FileCell params renamed marked/onMark->selected/onToggleSelect internally; FileGrid own marked/onMark stay as documented public compat alias (COMPONENT_API.md:112); kit build 0 lint errors; browser-witnessed checkbox select-all/individual/clear-selection + BulkBar flow at localhost:3010/gm/#tab=files, 0 console errors
|
|
2552
|
+
status: completed
|
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
+
## Maximal usability/negative-space/predictability sweep (2026-07-10) — thirty-first run
|
|
4
|
+
|
|
5
|
+
User asked to "max the gui usability practicality... predictable, good looking, use negative space properly" via wfgy-method-grade critique. Ran a fresh `gui-ux-craft` workflow (32 agents, 19 confirmed) plus a targeted live-browser negative-space audit agent in parallel, then landed the highest-value findings from both. Kit (`../design`): ConfirmDialog `destructive` prop was dead code (delete confirms always rendered `primary`, never `danger`) — real predictability bug, fixed + browser-witnessed the delete dialog button now carries `btn-primary danger`. Settings panels had a 56px gap between stacked Panels (32px `.panel` margin + 24px grid gap stacking) vs 24px everywhere else — zeroed the margin inside `.settings-grid`, witnessed 24px consistent. `.ds-page-header-dense-lede` and `.chat-composer-context` both hard-clipped with `nowrap`+ellipsis at <=480px with no way to recover the text — both now wrap at that breakpoint (kept desktop's single-line ellipsis). History empty-state sub-line used the misapplied `.lede` (fs-xl) style, rendering LARGER than its own title — removed the misapplied class + fixed the title's own hardcoded `1.05rem` to `var(--fs-lg)` token. Small-caps section labels (`panel-head`, `table th`) drifted from the canonical `.t-label` size (`--fs-xs` vs `--fs-tiny`) — unified. `FileRow`/`FileCell` internal selection props renamed `marked/onMark` -> `selected/onToggleSelect` to match the shared multi-select contract (FileGrid's own `marked`/`onMark` stay as its documented public alias). `ConversationList` search-mode blew away already-visible rows to a full skeleton on every debounced re-search — guarded on `!sessions.length`, matching `files.js`'s sibling pattern. App copy-tone: "sidebar" (used nowhere else) -> "the rail"; internal-jargon `agent: 'external session'` -> `'other tool'`; "session" -> "conversation" vocabulary unified across resume banner/toasts/labels; raw sid slice in resume banner replaced with a human session-title lookup (`resumeSidLabel()`), falling back to the slice only when no title is known; settings projects-folder fact gained the same copy button its sibling root rows already had. Perf: `prism-core.min.js` (a classic UMD script, not an ES module) now gets a `rel=preload as=script` hint alongside the existing `modulepreload` hints for marked/dompurify; History tab re-fetch on every entry now gated on staleness (>5s) instead of unconditional; bulk file delete/move patch `state.files.entries` locally and render immediately instead of awaiting a second full directory round-trip (backgrounded as reconciliation) — scoped to the bulk paths only, the highest-traffic case. Kit docs: README gained a "multi-agent chat shell" bullet naming the flagship `WorkspaceShell`/`AgentChat`/etc surface (previously undiscoverable from a first read), `COMPONENT_API.md` documents `FileRow`'s `move` action and scopes the `freddie.js` re-exports as demo-site-only. **A concurrent gm session was independently working the same `../design` repo this run — its commits (`df5b566`..`68b615b`) landed my kit edits before I reached CONSOLIDATE; verified via `git log`/`rev-parse HEAD==origin/main` rather than re-pushing.** Browser-witnessed every fix live at 1280px+420px on a no-PASSWORD localhost:3010 instance (settings gaps, empty-state hierarchy, danger delete button, mobile wrap, files checkbox/BulkBar flow after the prop rename): 0 console errors throughout. **Standing rule reaffirmed: `prd-resolve` witness_evidence must be distinct per row — a byte-identical witness across rows is refused by plugkit as a rubber-stamp tell; write what THAT row specifically changed, every time.**
|
|
6
|
+
|
|
3
7
|
## Sessions-rail selection dead-click fix (2026-07-03) — thirtieth run
|
|
4
8
|
|
|
5
9
|
User feedback: "layout and design choices look weird... make maximum sense." Live-browser audit of history/live tabs (screenshots + `window.__agentgui` state probing, not a full agent fan-out) found a real logic gap the prior 29 runs' visual sweeps never caught: the conversation rail (`ConversationList`) stays mounted on files/live/settings tabs (`keepSessionsTrack`) and is captioned "Browse a conversation's events" there — but `onSelect` (`site/app/js/app.js` sessions-column builder) only special-cased the chat tab (`resumeInChat`); every other tab fell through to `loadSession(sid)`, which sets `state.selectedSid`/fetches events but never switches tabs. Since only the History tab's `historyMain()` renders `state.events`, clicking a row while on Live/Files/Settings was a dead click — data loaded into state that nothing on screen displayed, with a caption promising an outcome the click didn't deliver. Fixed: selecting from any non-chat tab now navigates to history first. Verified live: `state.tab` was `'live'`, clicked `.ds-session-row`, `state.tab` became `'history'` with `selectedSid` set and the events endpoint fetched. **Standing rule: whenever a persistent-across-tabs component (kept mounted via a `keepXTrack` pattern) has an interaction whose effect is rendered by only ONE of the tabs it appears on, every OTHER tab's handler must produce the same visible effect (usually by navigating to the tab that renders it) — a component kept visually consistent across tabs but behaviorally inert on most of them is worse than not showing it at all.** No kit changes this run (app-only wiring fix). agentgui pushed `c1e4915`.
|
package/package.json
CHANGED
package/site/app/index.html
CHANGED
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
markdown.js to reach its dynamic import. -->
|
|
45
45
|
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/marked@15.0.12/+esm" crossorigin>
|
|
46
46
|
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/+esm" crossorigin>
|
|
47
|
+
<!-- prism-core is a classic UMD <script src>, not an ES module (loaded via
|
|
48
|
+
highlight.js's loadScript, not import) - modulepreload is the wrong hint
|
|
49
|
+
type for it; preload as=script starts the same parallel fetch instead. -->
|
|
50
|
+
<link rel="preload" as="script" href="https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-core.min.js" crossorigin>
|
|
47
51
|
<!-- No design content lives here. Every agentgui application-surface style
|
|
48
52
|
(pills, cwd bar, resume banner, health chips, settings grid, history
|
|
49
53
|
empty state, boot splash, scrollbar theming, focus rings, print) now
|
package/site/app/js/app.js
CHANGED
|
@@ -293,7 +293,7 @@ function navTo(tab, { writeHash: doWriteHash = true, push = true } = {}) {
|
|
|
293
293
|
const wantsStream = (t) => t === 'history' || t === 'live'
|
|
294
294
|
|| (t === 'chat' && (state.chat.busy || (Array.isArray(state.active) && state.active.length > 0)));
|
|
295
295
|
if (wantsStream(tab)) {
|
|
296
|
-
if (tab === 'history') refreshHistory();
|
|
296
|
+
if (tab === 'history' && (!state._historyLoadedOnce || Date.now() - (state._historyLoadedAt || 0) > 5000)) refreshHistory();
|
|
297
297
|
openLiveStream();
|
|
298
298
|
} else if (wantsStream(prev)) {
|
|
299
299
|
closeLiveStream();
|
|
@@ -993,15 +993,21 @@ async function runBulkDelete() {
|
|
|
993
993
|
state.files.dialog = null;
|
|
994
994
|
marked.clear(); state.files._lastMarkIdx = null;
|
|
995
995
|
announce('deleted ' + okCount + ' ' + (okCount === 1 ? 'entry' : 'entries'));
|
|
996
|
-
|
|
997
|
-
//
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
+ fileMutationCopy(firstErr.reason || {}) + '). The failed entries stay selected.';
|
|
996
|
+
// Patch the visible list immediately instead of waiting on a second full
|
|
997
|
+
// directory round-trip - the server already confirmed every deletion.
|
|
998
|
+
const gone = new Set(targets.map((e) => e.path || e.name));
|
|
999
|
+
state.files.entries = (state.files.entries || []).filter((e) => !gone.has(e.path || e.name));
|
|
1000
|
+
render();
|
|
1001
|
+
loadDir(state.files.path, { fromHash: true }); // background reconcile
|
|
1002
|
+
return;
|
|
1004
1003
|
}
|
|
1004
|
+
// Keep only the failures marked; report the split inside the dialog.
|
|
1005
|
+
state.files.marked = new Set(failed.map((e) => e.path || e.name));
|
|
1006
|
+
const firstErr = results.find((r) => r.status === 'rejected');
|
|
1007
|
+
d.busy = false;
|
|
1008
|
+
d.error = 'deleted ' + okCount + ' of ' + targets.length + ' - '
|
|
1009
|
+
+ (failed.length === 1 ? '1 entry' : failed.length + ' entries') + ' failed ('
|
|
1010
|
+
+ fileMutationCopy(firstErr.reason || {}) + '). The failed entries stay selected.';
|
|
1005
1011
|
await loadDir(state.files.path, { fromHash: true });
|
|
1006
1012
|
render();
|
|
1007
1013
|
}
|
|
@@ -1031,14 +1037,20 @@ async function runBulkMove(destDir) {
|
|
|
1031
1037
|
state.files.dialog = null;
|
|
1032
1038
|
marked.clear(); state.files._lastMarkIdx = null;
|
|
1033
1039
|
announce('moved ' + okCount + ' ' + (okCount === 1 ? 'entry' : 'entries'));
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1040
|
+
// Moved entries leave the current dir - patch them out immediately rather
|
|
1041
|
+
// than waiting on a second full directory round-trip.
|
|
1042
|
+
const gone = new Set(targets.map((e) => e.path || e.name));
|
|
1043
|
+
state.files.entries = (state.files.entries || []).filter((e) => !gone.has(e.path || e.name));
|
|
1044
|
+
render();
|
|
1045
|
+
loadDir(state.files.path, { fromHash: true }); // background reconcile
|
|
1046
|
+
return;
|
|
1041
1047
|
}
|
|
1048
|
+
state.files.marked = new Set(failed.map((e) => e.path || e.name));
|
|
1049
|
+
const firstErr = results.find((r) => r.status === 'rejected');
|
|
1050
|
+
d.busy = false;
|
|
1051
|
+
d.error = 'moved ' + okCount + ' of ' + targets.length + ' - '
|
|
1052
|
+
+ (failed.length === 1 ? '1 entry' : failed.length + ' entries') + ' failed ('
|
|
1053
|
+
+ fileMutationCopy(firstErr.reason || {}) + '). The failed entries stay selected.';
|
|
1042
1054
|
await loadDir(state.files.path, { fromHash: true });
|
|
1043
1055
|
render();
|
|
1044
1056
|
}
|
|
@@ -1544,7 +1556,7 @@ async function stopAllActive(sessions) {
|
|
|
1544
1556
|
: null;
|
|
1545
1557
|
announce(failed
|
|
1546
1558
|
? 'stopped ' + okSids.length + ' of ' + sids.length + ' sessions'
|
|
1547
|
-
: 'stopped ' + plural(okSids.length, '
|
|
1559
|
+
: 'stopped ' + plural(okSids.length, 'conversation'));
|
|
1548
1560
|
await refreshActive();
|
|
1549
1561
|
render();
|
|
1550
1562
|
return okSids;
|
|
@@ -1659,7 +1671,7 @@ function computeLiveSessions() {
|
|
|
1659
1671
|
external: true,
|
|
1660
1672
|
readOnly: true,
|
|
1661
1673
|
title: sess ? (projectLabel(sess.title) || projectLabel(sess.project) || sid) : sid,
|
|
1662
|
-
agent: '
|
|
1674
|
+
agent: 'other tool',
|
|
1663
1675
|
model: '',
|
|
1664
1676
|
cwd: pathBasename(sess && sess.cwd),
|
|
1665
1677
|
elapsed: '',
|
|
@@ -1914,11 +1926,14 @@ function chatMain() {
|
|
|
1914
1926
|
if (state.chat.resumeSid && state.selectedAgent === 'claude-code') {
|
|
1915
1927
|
// The agent-switched note (if any) lives inside the resume banner rather
|
|
1916
1928
|
// than as a separate stacked Alert, so resume context reads as one block.
|
|
1917
|
-
banners.push(h('div', { key: 'rb', class: 'resume-banner', role: 'status' },
|
|
1929
|
+
banners.push(h('div', { key: 'rb', class: 'resume-banner', role: 'status' }, ...[
|
|
1918
1930
|
h('span', { key: 'rbtxt', class: 'lede' },
|
|
1919
|
-
'next message continues
|
|
1920
|
-
|
|
1921
|
-
|
|
1931
|
+
'next message continues this conversation (' + resumeSidLabel(state.chat.resumeSid) + ')'),
|
|
1932
|
+
state.chat.resumeNote
|
|
1933
|
+
? h('span', { key: 'rbnote', class: 'sub' }, state.chat.resumeNote)
|
|
1934
|
+
: null,
|
|
1935
|
+
Btn({ key: 'rclr', onClick: () => { state.chat.resumeSid = null; state.chat.resumeNote = null; render(); }, children: 'clear' }),
|
|
1936
|
+
].filter(Boolean)));
|
|
1922
1937
|
}
|
|
1923
1938
|
if (state.selectedAgent && !agentAvailable(state.selectedAgent)) {
|
|
1924
1939
|
banners.push(Alert({ key: 'unavail', kind: 'warn', title: agentName + ' is not installed',
|
|
@@ -2035,7 +2050,7 @@ function chatMain() {
|
|
|
2035
2050
|
},
|
|
2036
2051
|
userTurnCount > 0 ? plural(userTurnCount, 'turn') : null,
|
|
2037
2052
|
(state.chat.resumeSid && state.selectedAgent === 'claude-code')
|
|
2038
|
-
? 'continues
|
|
2053
|
+
? 'continues conversation (' + resumeSidLabel(state.chat.resumeSid) + ')'
|
|
2039
2054
|
: null,
|
|
2040
2055
|
].filter(Boolean),
|
|
2041
2056
|
} : undefined,
|
|
@@ -2638,7 +2653,7 @@ function historyMain() {
|
|
|
2638
2653
|
h('div', { key: 'histempty', class: 'history-empty', role: 'status' },
|
|
2639
2654
|
h('p', { key: 'gt', class: 'history-empty-title' },
|
|
2640
2655
|
count ? 'Select a conversation to view its events' : 'No conversations yet'),
|
|
2641
|
-
h('p', { key: 'gs', class: '
|
|
2656
|
+
h('p', { key: 'gs', class: 'history-empty-sub' },
|
|
2642
2657
|
count
|
|
2643
2658
|
? count + ' conversation' + (count === 1 ? '' : 's') + ' available · use the search box or press / to filter'
|
|
2644
2659
|
: 'Start a chat or run a local coding agent - its conversation will appear here live.')),
|
|
@@ -2660,7 +2675,7 @@ function historyMain() {
|
|
|
2660
2675
|
const hasErrors = state.events.some(e => e.isError);
|
|
2661
2676
|
const actions = h('div', { key: 'acts', class: 'history-actions' }, [
|
|
2662
2677
|
Btn({ key: 'resume', primary: true, onClick: () => resumeInChat(sess || { sid: state.selectedSid }), children: 'open in chat' }),
|
|
2663
|
-
Btn({ key: 'copy', onClick: copySid, children: copyToast || 'copy
|
|
2678
|
+
Btn({ key: 'copy', onClick: copySid, children: copyToast || 'copy conversation id' }),
|
|
2664
2679
|
Btn({ key: 'exportsess', disabled: !state.eventsLoaded, title: 'Download this session\'s events as JSON',
|
|
2665
2680
|
onClick: () => downloadBlob(JSON.stringify(state.events, null, 2), (projectLabel(sess?.project) || 'session') + '-' + state.selectedSid + '.json', 'application/json'),
|
|
2666
2681
|
children: 'export' }),
|
|
@@ -2673,7 +2688,7 @@ function historyMain() {
|
|
|
2673
2688
|
// indexing copy (ccsniff's first JSONL walk can take a minute).
|
|
2674
2689
|
const body = state.eventsLoaded
|
|
2675
2690
|
? h('div', { key: 'noev', class: 'lede empty-state', role: 'status' },
|
|
2676
|
-
h('span', { key: 'noevtxt' }, 'no events in this
|
|
2691
|
+
h('span', { key: 'noevtxt' }, 'no events in this conversation'),
|
|
2677
2692
|
Btn({ key: 'reload', onClick: () => loadSession(state.selectedSid), children: 'reload' }))
|
|
2678
2693
|
// Shape-matched skeleton rows (kit EventList loading state) instead of a
|
|
2679
2694
|
// lone spinner collapsing the slowest pane in the product.
|
|
@@ -2912,6 +2927,17 @@ function projectLabel(project) {
|
|
|
2912
2927
|
return segs.length ? segs[segs.length - 1] : project;
|
|
2913
2928
|
}
|
|
2914
2929
|
|
|
2930
|
+
// Resume banner/turn-continuation copy previously showed a raw sid slice with
|
|
2931
|
+
// no way to tell which conversation it refers to - prefer the same human
|
|
2932
|
+
// label used everywhere else in the rail, falling back to the sid slice.
|
|
2933
|
+
function resumeSidLabel(sid) {
|
|
2934
|
+
if (!sid) return '';
|
|
2935
|
+
const arr = Array.isArray(state.sessions) ? state.sessions : [];
|
|
2936
|
+
const sess = arr.find((s) => s.sid === sid);
|
|
2937
|
+
const label = sess && (projectLabel(sess.title) || projectLabel(sess.project));
|
|
2938
|
+
return label || (sid.slice(0, 8) + '…');
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2915
2941
|
function uniqueProjects() {
|
|
2916
2942
|
const arr = Array.isArray(state.sessions) ? state.sessions : [];
|
|
2917
2943
|
const seen = new Map();
|
|
@@ -3154,7 +3180,8 @@ function serverPanel() {
|
|
|
3154
3180
|
{ label: 'version', value: hh.version ? 'v' + hh.version : fallback },
|
|
3155
3181
|
{ label: 'uptime', value: upMs != null ? fmtDuration(upMs) : fallback },
|
|
3156
3182
|
{ label: 'connected clients', value: wsClients != null ? String(wsClients) : fallback },
|
|
3157
|
-
{ label: 'projects folder', value: hh.projectsDir || fallback, title: hh.projectsDir || undefined
|
|
3183
|
+
{ label: 'projects folder', value: hh.projectsDir || fallback, title: hh.projectsDir || undefined,
|
|
3184
|
+
onCopy: hh.projectsDir ? () => copyText(hh.projectsDir, 'projects folder copied') : undefined },
|
|
3158
3185
|
];
|
|
3159
3186
|
return Panel({
|
|
3160
3187
|
id: 'server',
|
|
@@ -3322,6 +3349,7 @@ async function refreshHistory() {
|
|
|
3322
3349
|
try {
|
|
3323
3350
|
state.sessions = await B.listSessions(state.backend);
|
|
3324
3351
|
state._historyLoadedOnce = true;
|
|
3352
|
+
state._historyLoadedAt = Date.now();
|
|
3325
3353
|
state.historySlow = false;
|
|
3326
3354
|
// Index by sid so each live SSE event is an O(1) lookup, not an O(sessions)
|
|
3327
3355
|
// linear scan per event during a burst load.
|
|
@@ -3466,7 +3494,7 @@ async function loadSession(sid, { focusEventI = null, focusEventTs = null, fromH
|
|
|
3466
3494
|
ts: Date.now(),
|
|
3467
3495
|
role: 'error',
|
|
3468
3496
|
type: 'fetch',
|
|
3469
|
-
text: 'Failed to load session: ' + errText(e) + ' - retry via
|
|
3497
|
+
text: 'Failed to load session: ' + errText(e) + ' - retry via the rail',
|
|
3470
3498
|
}];
|
|
3471
3499
|
clearTimeout(slowTimer);
|
|
3472
3500
|
state.eventsSlow = false;
|