agentgui 1.0.1031 → 1.0.1032
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gm/prd.yml +166 -0
- package/package.json +1 -1
- package/site/app/js/app.js +30 -20
- package/site/app/vendor/anentrypoint-design/247420.css +284 -81
- package/site/app/vendor/anentrypoint-design/247420.js +15 -15
package/.gm/prd.yml
CHANGED
|
@@ -2719,3 +2719,169 @@
|
|
|
2719
2719
|
subject: Adversarially verify every landed fix live in the browser (0 console errors), push kit + app, watch CI green, mark complete only on real transition to COMPLETE.
|
|
2720
2720
|
status: completed
|
|
2721
2721
|
witness: 'Live agent-browser session against http://localhost:3010/gm/?token=... after kit rebuild+re-vendor+server restart: 0 console errors on load and after theme switch to dark; confirmed .btn-primary letter-spacing computed as ''normal'' (was var(--tr-caps)); confirmed .btn:focus-visible rule now reads ''outline: var(--focus-w) solid var(--focus-color)'' via live stylesheet query; confirmed pre .n color computed as rgb(148,99,0) (#946300 = --code-num, was --green-2''s 3.18:1-failing value); confirmed --amber root value #7C570F matches paper-theme override (drift fixed); confirmed ds-icon-btn-danger/btn-primary.danger hover rules both now brightness(0.92) (darkening, AA-safe) via live stylesheet query.'
|
|
2722
|
+
- id: run33-gui-ux-craft-workflow
|
|
2723
|
+
title: Run gui-ux-craft workflow (33rd sweep) for fresh usability/predictability/negative-space findings on top of 31st/32nd run fixes
|
|
2724
|
+
notes: user re-requested max usability/practicality/predictable/negative-space via wfgy-method critique; dispatch Workflow gui-ux-craft
|
|
2725
|
+
status: completed
|
|
2726
|
+
witness: 'Workflow wf_7f1a513c-2a3 completed: 33/34 agents succeeded, 21 confirmed findings, all implemented and resolved as individual PRD rows; 1 crashed lens (kit-dx) re-run separately.'
|
|
2727
|
+
- id: run33-wfgy-negative-space-audit
|
|
2728
|
+
title: Targeted live-browser negative-space/attention audit in parallel with workflow (screenshots+DOM measurement at 1280px and 420px)
|
|
2729
|
+
notes: per established pattern from 27th/29th/31st runs, catches regressions workflow fan-out misses
|
|
2730
|
+
status: completed
|
|
2731
|
+
witness: Dispatched parallel live-browser negative-space audit agent; found 2 real issues (health-chip contrast, history empty-state void) both fixed and resolved separately as run33-health-chip-connected-contrast and run33-history-empty-state-dead-void.
|
|
2732
|
+
- id: run33-kit-rebuild-revendor
|
|
2733
|
+
title: Rebuild kit (node scripts/build.mjs) and re-vendor dist into agentgui site/app/vendor if kit changes land
|
|
2734
|
+
notes: standing update flow
|
|
2735
|
+
status: completed
|
|
2736
|
+
witness: Kit rebuilt via node scripts/build.mjs multiple times across the fix batches (final rebuild at 12:2x with AgentListSkeleton addition); lint-glyphs/lint-null-children/lint-classes/lint-inline-styles all OK each time; dist/247420.{js,css} copied into agentgui site/app/vendor/anentrypoint-design/ as the final step.
|
|
2737
|
+
- id: run33-browser-witness-fixes
|
|
2738
|
+
title: Browser-witness every fix live (0 console errors) before VERIFY
|
|
2739
|
+
notes: standing rule, exec via browser dispatch
|
|
2740
|
+
status: completed
|
|
2741
|
+
witness: 'Browser-witnessed live at localhost:3012/gm/?token=... via agent-browser: health-chip connected color rgb(78,122,0) on tinted bg, history-empty-hints present, agentchat-cwd-text font-family mono, --focus-w token set, tone-success rule present in live stylesheet, 0 console errors across chat/history/settings tabs.'
|
|
2742
|
+
- id: run33-push-ci
|
|
2743
|
+
title: Push kit + agentgui changes, watch CI green on both repos
|
|
2744
|
+
notes: standing CONSOLIDATE requirement
|
|
2745
|
+
status: pending
|
|
2746
|
+
- id: run33-health-chip-connected-contrast
|
|
2747
|
+
title: Fix near-invisible connected health-chip text in Settings BACKEND panel
|
|
2748
|
+
notes: 'design/app-surfaces.css .ds-247420 .health-summary.health-ok .health-chip:first-child uses raw --accent (lime #B6FF1B) as text color on near-paper bg, measured rgb(182,255,27) vs sibling rgb(31,31,38) - give it an accent background + dark text per --accent-ink contrast pattern'
|
|
2749
|
+
status: completed
|
|
2750
|
+
witness: 'Browser-witnessed at localhost:3011/gm/ Settings tab: computed style of .health-chip:first-child ''connected'' text now rgb(78,122,0) on lime-tinted color(srgb .71 1 .11 /.16) bg, legible vs siblings rgb(31,31,38); before fix it was raw rgb(182,255,27) on near-invisible near-paper bg. Kit rebuilt (node scripts/build.mjs) and re-vendored into site/app/vendor/anentrypoint-design/.'
|
|
2751
|
+
- id: run33-history-empty-state-dead-void
|
|
2752
|
+
title: Fix large dead-space void in History empty state (~300px blank at 1280px, >50% viewport blank at 420px)
|
|
2753
|
+
notes: app.js History tab empty state vertically centers in full pane height leaving huge blank void below the message - collapse to natural height or surface useful content (shortcuts, recent-events preview)
|
|
2754
|
+
status: completed
|
|
2755
|
+
witness: 'Browser-witnessed at localhost:3011/gm/ History tab: .history-empty getBoundingClientRect height=353.8px (natural, top-aligned with new .history-empty-hints ShortcutList filling reclaimed space) vs prior fixed min-height:50vh centered void; 0 console errors.'
|
|
2756
|
+
- id: typography-rhythm-cwd-fact-font-family-inconsistent
|
|
2757
|
+
title: The 'working directory / cwd path' fact renders in mono in the Live dashboard but in the body sans font everywhere else
|
|
2758
|
+
notes: '[kit] In the kit (design/chat.css), align the composer and context-pane cwd renderings to the existing mono convention rather than stripping it from the dashboard: add `font-family: var(--ff-mono);` to `.agentchat-cwd-text` (chat.css:90 block) and to the context-pane cwd row selector `.ds-context .row .sub` at chat.css:474 (or a more targeted `.ds-context .row[data-cwd] .sub` if a cwd-specific hook exists) — matching `.ds-dash-cwd`, `.ds-session-agent`, and `.ds-dash-model`, all of which already use `--ff-mono` for this class of technical/path metadata.'
|
|
2759
|
+
status: completed
|
|
2760
|
+
witness: 'Browser-witnessed at localhost:3012/gm/ chat tab: getComputedStyle(.agentchat-cwd-text).fontFamily = ''ui-monospace, Menlo, Consolas, monospace'' (was inheriting sans body font before fix); context-pane cwd row scoped via new .ds-context-cwd-row wrapper.'
|
|
2761
|
+
- id: typography-rhythm-agent-name-font-family-inconsistent
|
|
2762
|
+
title: Agent name renders in mono in the session list row but in the sans display font on the Live dashboard card
|
|
2763
|
+
notes: '[kit] In design/chat.css:417, remove `font-family: var(--ff-mono);` from `.ds-session-agent`, leaving `font-size: var(--fs-tiny); color: var(--fg-3);` so it inherits the sans display font like `.ds-dash-agent`. No app or index.html changes needed.'
|
|
2764
|
+
status: completed
|
|
2765
|
+
witness: chat.css .ds-session-agent font-family:var(--ff-mono) declaration removed, now inherits sans display font matching .ds-dash-agent; confirmed via source diff in rebuilt chat.css.
|
|
2766
|
+
- id: typography-rhythm-chat-md-paragraph-margin-untokenized
|
|
2767
|
+
title: Chat markdown paragraph spacing is a hardcoded pixel value instead of a --space token
|
|
2768
|
+
notes: '[kit] In design/chat.css:814, change `.chat-msg-flat .chat-md p { margin: 8px 0; }` to `.chat-msg-flat .chat-md p { margin: var(--space-2) 0; }`.'
|
|
2769
|
+
status: completed
|
|
2770
|
+
witness: chat.css .chat-msg-flat .chat-md p margin changed from hardcoded 8px 0 to var(--space-2) 0; confirmed via source read of rebuilt chat.css.
|
|
2771
|
+
- id: typography-rhythm-panel-stack-margin-vs-files-stack-gap
|
|
2772
|
+
title: Stacked Panel sections (settings) use a 32px bottom-margin rhythm while the equivalent stacked-band rhythm on Files uses 16px, for the same 'sibling content blocks' relationship
|
|
2773
|
+
notes: '[kit] In design/app-shell.css, change .panel''s margin-bottom from var(--space-5) to var(--space-4) (24px) to sit closer to the .ds-files-stack rhythm without a large layout-affecting rewrite, since settings'' Panel list isn''t wrapped in a shared flex container (app.js just calls Panel(...) back-to-back) and switching to a wrapper+gap pattern would require added app.js markup changes beyond a pure kit CSS fix. Minimal one-line change: `.panel { margin: 0 0 var(--space-4); }`.'
|
|
2774
|
+
status: completed
|
|
2775
|
+
witness: app-shell.css .panel margin-bottom changed from var(--space-5) to var(--space-4), aligning settings panel rhythm with files-stack gap; confirmed via source read.
|
|
2776
|
+
- id: copy-tone-session-vs-conversation-vocab
|
|
2777
|
+
title: Same concept called 'session' on Live tab but 'conversation' on History tab
|
|
2778
|
+
notes: |
|
|
2779
|
+
[app] In site/app/js/app.js: (1) line 1766 change PageHeader title/lede on the Live tab from 'Live sessions'/'...agent sessions.' to 'Live conversations'/'Watch, open, and stop running agent conversations.'; (2) lines 1585-1590 in stopAllActive, make both branches say 'conversation(s)' consistently: change 1586 to `failed + ' conversation' + (failed === 1 ? '' : 's') + ' did not stop - try again'` and 1589 to `'stopped ' + okSids.length + ' of ' + sids.length + ' conversations'`; (3) line 1761 Alert title 'Some sessions did not stop' -> 'Some conversations did not stop'. Keep 'sid'/'session id' only as the internal technical identifier (e.g. variable names, activeSid prop) - do not rename those.</refinedFix>
|
|
2780
|
+
</invoke>
|
|
2781
|
+
status: completed
|
|
2782
|
+
witness: app.js Live tab PageHeader title/lede changed to 'Live conversations'/'Watch, open, and stop running agent conversations.'; stopAllActive messages and Alert title unified to 'conversation(s)' vocabulary; node --check app.js passed.
|
|
2783
|
+
- id: copy-tone-folders-cannot-be-dropped-duplicated
|
|
2784
|
+
title: Identical 'folders cannot be dropped' announce string duplicated verbatim at two call sites, one already slightly diverging as the two evolve independently
|
|
2785
|
+
notes: '[app] In site/app/js/app.js, inside the DropZone onDrop handler (around line 1476-1487), hoist the message to a single local const right before the `if (items)` check, e.g. `const FOLDER_DROP_MSG = ''folders cannot be dropped - use new folder to create one'';` and replace both `announce(''folders cannot be dropped - use new folder to create one'')` calls (lines 1483 and 1485) with `announce(FOLDER_DROP_MSG)`. No new module-level export needed since it''s only used within this one handler.'
|
|
2786
|
+
status: completed
|
|
2787
|
+
witness: app.js DropZone onDrop handler now uses single FOLDER_DROP_MSG const referenced at both announce() call sites instead of duplicated literal strings; node --check app.js passed.
|
|
2788
|
+
- id: copy-tone-jump-to-root-label-jargon
|
|
2789
|
+
title: '''Jump to an allowed root'' exposes internal server-confinement terminology (''allowed root'') as user-facing microcopy'
|
|
2790
|
+
notes: '[app] In site/app/js/app.js replace the phrase ''allowed root(s)'' with ''accessible folder(s)'' at all occurrences: line 880 (''That folder is outside the accessible folders, or access is denied.''), line 942 (''...or the target is outside the accessible folders.''), lines 1220/2161/2610 (''outside the accessible folders''), line 1443 aria-label (''Jump to an accessible folder''), and line 3226 (''accessible folders: none configured''). Keep wording consistent across all sites since they''re the same user-facing concept.'
|
|
2791
|
+
status: completed
|
|
2792
|
+
witness: app.js all 6 user-facing 'allowed root(s)' strings replaced with 'accessible folder(s)' (file-list error, fileMutationCopy 403, cwd-probe errors, RootsPicker aria-label, settings none-configured line); internal fsAllowRoots fn name and code comments left untouched per scope; node --check app.js passed.
|
|
2793
|
+
- id: perceived-performance-boot-render-gated-on-health-probe
|
|
2794
|
+
title: First real render is gated behind the health-probe network round-trip, so the app shell paints nothing until it resolves
|
|
2795
|
+
notes: '[app] In app.js init(), set `state.health = { status: ''unknown'' }` and call `render()` once synchronously before the `const r = await B.probeBackend(...)` line (i.e. as the first statements inside init(), ahead of the try block). Leave the existing try/catch + second render() (line 3620) unchanged so the health banner/agent list still update in place once the probe resolves.'
|
|
2796
|
+
status: completed
|
|
2797
|
+
witness: app.js init() now sets state.health={status:'unknown'} and calls render() synchronously before awaiting B.probeBackend(...); existing try/catch + post-resolve render() unchanged; node --check app.js passed.
|
|
2798
|
+
- id: perceived-performance-agents-list-spinner-not-skeleton
|
|
2799
|
+
title: Agent list uses a bare spinner+text loading state while Files/History/Sessions use shape-matched skeleton rows
|
|
2800
|
+
notes: '[kit+app] In design (kit): add an `AgentListSkeleton({rows = 5})` export near FileSkeleton/EventList''s skeleton, rendering `rows` Row-shaped ghost items (reuse `.ds-skel-icon`/`.ds-skel-title`/`.ds-skel-meta` placeholder spans already styled for FileSkeleton, wrapped to match Row''s visual footprint) with `aria-hidden=true`, plus a single `role=status aria-live=polite` text node like EventList''s `loadingText` pattern. In app.js: replace the `state.agentsLoading` branch at ~3355-3357 (`h(''div'', {class:''t-meta empty-state'', role:''status'', ''aria-live'':''polite''}, Spinner(...), ''loading agents…'')`) with `AgentListSkeleton({rows: 5})`, keeping the row-array key discipline (`key:''agload''` wrapper, all children keyed) already used elsewhere in this file.'
|
|
2801
|
+
status: completed
|
|
2802
|
+
witness: Added new AgentListSkeleton export in kit sessions.js (re-exported via components.js barrel), CSS in chat.css using existing ds-skel shimmer primitive; wired into app.js agentsLoading branch replacing bare Spinner+text; browser-witnessed rebuilt bundle contains AgentListSkeleton (grep count=1), 0 console errors live.
|
|
2803
|
+
- id: perceived-performance-upload-progress-no-percent-during-transfer
|
|
2804
|
+
title: Upload rows show 0% until the whole file finishes (fetch has no chunk progress) with no indeterminate-progress affordance
|
|
2805
|
+
notes: '[kit+app] Switch the in-flight (not-done, not-error) row to the kit''s indeterminate/marquee progress-bar state (if `UploadProgress` doesn''t have one yet, add it) instead of a static 0% fill, so the row visibly communicates ''working'' rather than ''stuck'' during the transfer.'
|
|
2806
|
+
status: completed
|
|
2807
|
+
witness: kit files.js UploadProgress gained indeterminate prop + ds-upload-marquee CSS animation (with prefers-reduced-motion fallback); app.js UploadProgress call site sets indeterminate:true for in-flight zero-percent rows; grep of rebuilt app-shell.css confirms 2 ds-upload-marquee occurrences; node --check app.js passed.
|
|
2808
|
+
- id: light-theme-contrast-accent-fill-hover-brightness
|
|
2809
|
+
title: Send button and rail primary-action hover use brightness(1.08) lightening on an already near-max-lightness accent fill in paper theme
|
|
2810
|
+
notes: '[kit] In app-shell.css, change both hover rules to darken via brightness(0.92) (consistent with the already-fixed ghost/danger pattern and with the existing `.send:active { filter: brightness(0.94); }` which already darkens): line ~2634 `.chat-composer .send:hover { filter: brightness(1.08); }` -> `filter: brightness(0.92);`, and line ~3743 `.ws-rail-action:hover { filter: brightness(1.08); }` -> `filter: brightness(0.92);`. This keeps the hover visible regardless of how saturated --accent is in the active theme/data-accent variant, and stays consistent with :active already darkening rather than lightening.'
|
|
2811
|
+
status: completed
|
|
2812
|
+
witness: app-shell.css .chat-composer .send:hover and .ws-rail-action:hover changed from brightness(1.08) lightening to brightness(0.92) darkening, consistent with already-fixed ghost/danger pattern; confirmed via source read of rebuilt app-shell.css.
|
|
2813
|
+
- id: light-theme-contrast-editor-primitives-hover-lighten-missed
|
|
2814
|
+
title: editor-primitives.css dialog-button hover states still use the lightening pattern the kit already fixed elsewhere
|
|
2815
|
+
notes: '[kit] In /config/workspace/design/editor-primitives.css replace lines 654 and 658: change `.ds-ep-dialog-btn.kind-primary:hover { filter: brightness(1.08); }` and `.ds-ep-dialog-btn.kind-danger:hover { filter: brightness(1.1); }` to `filter: brightness(0.92);` each, matching the darkening convention used elsewhere in the kit for AA compliance on light theme.'
|
|
2816
|
+
status: completed
|
|
2817
|
+
witness: editor-primitives.css .ds-ep-dialog-btn.kind-primary/.kind-danger:hover changed from brightness(1.08)/brightness(1.1) to brightness(0.92) each; confirmed via source read.
|
|
2818
|
+
- id: light-theme-contrast-community-green-2-text
|
|
2819
|
+
title: community.css server-back/add icon still colored with the AA-failing --green-2 token
|
|
2820
|
+
notes: '[kit] In community.css:134, change `color: var(--green-2);` to `color: var(--green);` in the shared `.cm-server-back, .cm-server-add` rule. This only visibly affects `.cm-server-add` (the only one of the two whose resting-state color isn''t already overridden downstream by the `.cm-server-back { color: var(--fg-2); }` rule at line 147), bringing it to ~5.2:1 on --bg-2, matching the token already used for the other 4 fixed instances. No other lines need changes (the hover rule at 149-153 sets background to green-2 with paper text, a different, already-passing contrast pair, and is out of scope).'
|
|
2821
|
+
status: completed
|
|
2822
|
+
witness: community.css .cm-server-back, .cm-server-add color changed from var(--green-2) to var(--green); confirmed via source read of rebuilt community.css.
|
|
2823
|
+
- id: light-theme-contrast-selection-tint-weak
|
|
2824
|
+
title: ::selection highlight is far less visible in paper theme than in ink theme because it blends the same light accent into an already-light background
|
|
2825
|
+
notes: '[kit] In app-shell.css, add a light-theme-specific override right after the base ::selection rule (paper theme is the default/root, so target it explicitly): `:root[data-theme="paper"] ::selection, :root:not([data-theme]) ::selection { background: color-mix(in oklab, var(--accent) 45%, var(--bg-2)); color: var(--fg); }` — or simpler, key off the existing light-theme selector pattern already used in colors_and_type.css (mirror however light vs ink is scoped there, e.g. `[data-theme="paper"]`/default vs `[data-theme="ink"]`) and raise the accent share to ~45-50% only in the light branch, leaving the ink theme''s existing 24% mix untouched.'
|
|
2826
|
+
status: completed
|
|
2827
|
+
witness: colors_and_type.css ::selection base rule raised to 46% accent mix for light/default theme; explicit 24%-preserving overrides added for [data-theme=ink/dark] and prefers-color-scheme dark auto block so dark theme selection is unaffected; confirmed via source diff.
|
|
2828
|
+
- id: light-theme-contrast-accent-tint-active-states
|
|
2829
|
+
title: --accent-tint active/selected-state background is tuned for dark theme and reads faint on paper across many shared components
|
|
2830
|
+
notes: '[kit] In colors_and_type.css, keep the dark/ink/auto-dark theme''s --accent-tint exactly as-is (re-declare the current raw formula explicitly inside the existing [data-theme="ink"],[data-theme="dark"] block at ~line 309-311, and the prefers-color-scheme dark auto block at ~350-352, so dark behavior is pinned and unaffected), then change only the :root (light/paper default) definition at line 93 from `color-mix(in oklab, var(--accent) 30%, var(--bg))` to blend the darker, already-AA-tuned --accent-ink (acid-deep, #4E7A00) instead of the raw light --accent, e.g. `--accent-tint: color-mix(in oklab, var(--accent-ink) 22%, var(--bg));`. This gives light theme a visibly tinted, higher-contrast selection wash (matching the darker tone already used for accent text) while leaving the dark-theme highlight, which already reads well, untouched. Also apply the same light-tuned value in the [data-theme'
|
|
2831
|
+
status: completed
|
|
2832
|
+
witness: colors_and_type.css :root --accent-tint now blends --accent-ink at 22% (was raw --accent 30%); prior dark-theme value explicitly restated in ink/dark and auto-dark blocks so dark behavior is pinned; [data-theme=paper] block also carries the light-tuned value; confirmed via source diff.
|
|
2833
|
+
- id: interaction-density-cwdbar-order-reversed
|
|
2834
|
+
title: Inline CwdBar save/cancel action order is reversed from ConfirmDialog's cancel/confirm order
|
|
2835
|
+
notes: '[kit] In design/src/components/agent-chat.js CwdBar editing branch (~line 124-125), swap the order to render Btn(cancel) first, then Btn(save, variant:''primary''), matching ConfirmDialog/PromptDialog''s cancel-then-primary order. No prop/behavior changes, just reordering the two Btn(...) calls in the h(''div'', ...) children list.'
|
|
2836
|
+
status: completed
|
|
2837
|
+
witness: agent-chat.js CwdBar editing branch reordered to cancel-then-save Btn order matching ConfirmDialog/PromptDialog convention; confirmed via source read.
|
|
2838
|
+
- id: interaction-density-focus-ring-hardcoded
|
|
2839
|
+
title: File-surface controls hardcode outline:2px/var(--accent-ink) instead of the --focus-w/--focus-color/--focus-offset tokens the button family already uses
|
|
2840
|
+
notes: '[kit] In /config/workspace/design/app-shell.css, for the 11 cited selectors (.ds-file-grid, .ds-file-sort-btn, .ds-file-open, .ds-file-check, .ds-file-selectall, .ds-density-btn, .ds-file-cell-open, .ds-upload-act, .ds-modal-input, .ds-segmented .ds-seg-btn, .ds-file-act), replace `outline: 2px solid var(--accent-ink)` with `outline: var(--focus-w) solid var(--focus-color)` and replace each rule''s hardcoded `outline-offset: Npx` with `outline-offset: var(--focus-offset)`, keeping each rule''s own border-radius override untouched. (Optionally extend the same mechanical replacement to the other now-discovered hardcoded instances at lines 33,250,286,328,1004,2640,3182,3192,3585,3679,3731,3744,3754,3827,3951,3976,3989,4324 in the same pass, since they''re the identical bug, but the 11 cited are sufficient to resolve this finding.) Then run `node scripts/build.mjs` and re-vendor per the kit upd'
|
|
2841
|
+
status: completed
|
|
2842
|
+
witness: 'app-shell.css: all 30 matching hardcoded outline:2px solid var(--accent-ink) focus rules replaced with var(--focus-w) solid var(--focus-color), positive outline-offset values replaced with var(--focus-offset) (negative inset-ring offsets deliberately preserved); browser-witnessed getPropertyValue(''--focus-w'') is set and non-empty on live page.'
|
|
2843
|
+
- id: interaction-density-chip-badge-tone-sprawl
|
|
2844
|
+
title: Two near-duplicate tone-* families (.chip and .ds-badge) each carry 3-4 synonymous tone names for the same visual, with no canonical name documented
|
|
2845
|
+
notes: '[kit] In app-shell.css, replace the per-class repeated declarations with grouped selectors per semantic, keeping all existing class names as accepted aliases (no API break) but writing the rule once: e.g. `.ds-badge.tone-green, .ds-badge.tone-live, .ds-badge.tone-success, .ds-badge.tone-ok, .chip.tone-green, .chip.tone-live, .chip.tone-success, .chip.tone-ok { background: var(--green-tint); color: var(--green-deep); }` and similarly one combined rule for `.tone-flame/.tone-error/.tone-miss` across both `.ds-badge` and `.chip`, plus one for the neutral/wip/disabled group and one for blue/sun/yellow/orange/mascot/purple where identical. Add a one-line comment above naming `tone-success`/`tone-error`/`tone-neutral` as canonical for new callers, with the rest listed as legacy aliases kept for back-compat.'
|
|
2846
|
+
status: completed
|
|
2847
|
+
witness: app-shell.css tone-success/tone-error/tone-neutral families consolidated into single grouped declarations across .chip and .ds-badge, all legacy class-name aliases preserved, canonical-name comment added; browser-witnessed live stylesheet query confirms a rule with selectorText including 'tone-success' exists (toneSuccessExists:true).
|
|
2848
|
+
- id: interaction-density-iconbtn-primary-hover-mismatch
|
|
2849
|
+
title: Icon-button primary/ghost hover uses full fg/bg invert while the equivalent text-button primary hover uses fg background + accent-ink text
|
|
2850
|
+
notes: |-
|
|
2851
|
+
[kit] In /config/workspace/design/app-shell.css, change line 502 from
|
|
2852
|
+
.ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
|
|
2853
|
+
to
|
|
2854
|
+
.ds-icon-btn-primary:hover { background: var(--fg); color: var(--accent-ink); }
|
|
2855
|
+
matching .btn-primary:hover's two-tone-flip color so primary-role hover reads identically across labeled and icon-only buttons.
|
|
2856
|
+
status: completed
|
|
2857
|
+
witness: app-shell.css .ds-icon-btn-primary:hover color changed from var(--bg) to var(--accent-ink), matching .btn-primary:hover two-tone-flip; confirmed via source read of rebuilt app-shell.css.
|
|
2858
|
+
- id: run33-kit-dx-lens-crashed-rerun
|
|
2859
|
+
title: hunt:kit-dx lens crashed mid-run (API connection error) in the 33rd gui-ux-craft workflow - unaudited scope, not a null result
|
|
2860
|
+
notes: 'per standing rule from 31st run: a crashed lens goes into confirming pass as its own row - re-run a targeted kit-dx audit'
|
|
2861
|
+
status: completed
|
|
2862
|
+
witness: 'Re-ran kit-dx audit via subagent: found 3 real doc gaps (voice.js/theme-toggle.js/data-density.js undocumented, SessionMeta undocumented, 6 utility exports undocumented). Filed as kit-dx-undocumented-component-files, kit-dx-sessionmeta-undocumented, kit-dx-utility-exports-undocumented.'
|
|
2863
|
+
- id: typography-rhythm-caps-letterspacing-drift
|
|
2864
|
+
title: All-caps micro-labels in the chat surface use three different letter-spacing values instead of the --tr-caps token
|
|
2865
|
+
notes: '[kit] In design/chat.css replace the hardcoded letter-spacing values with var(--tr-caps): line 449 `.03em`->`var(--tr-caps)`, line 777 `.03em`->`var(--tr-caps)`, line 869 `.04em`->`var(--tr-caps)`, line 901 `.04em`->`var(--tr-caps)`. No HTML/JS changes needed; rebuild kit dist and re-vendor per the standard update flow.'
|
|
2866
|
+
status: completed
|
|
2867
|
+
witness: chat.css lines 449/777/869/901 letter-spacing values replaced with var(--tr-caps); kit rebuilt, lint-glyphs/lint-null-children/lint-classes/lint-inline-styles all OK, re-vendored into agentgui.
|
|
2868
|
+
- id: typography-rhythm-chat-md-lineheight-oneoff
|
|
2869
|
+
title: Chat markdown body copy uses a bespoke line-height (1.65) that matches neither of the two body-text tokens
|
|
2870
|
+
notes: '[kit] In design/chat.css:813, change `.chat-msg-flat .chat-md { line-height: 1.65; }` to `.chat-msg-flat .chat-md { line-height: var(--lh-long); }`.'
|
|
2871
|
+
status: completed
|
|
2872
|
+
witness: chat.css .chat-msg-flat .chat-md line-height changed from 1.65 to var(--lh-long); confirmed via grep of rebuilt chat.css source.
|
|
2873
|
+
- id: kit-dx-undocumented-component-files
|
|
2874
|
+
title: voice.js, theme-toggle.js, data-density.js components have zero entries in COMPONENT_API.md
|
|
2875
|
+
notes: add prop-table sections for PttButton/VadMeter/WebcamPreview/VoiceSettingsModal/VoiceControls/AudioQueue, ThemeToggle, PhaseWalk/TreeNode/BarRow/StatTile/StatsGrid/SubGrid/SessionRow/DevRow/LiveLogEntry/LiveLog
|
|
2876
|
+
status: completed
|
|
2877
|
+
witness: git status --porcelain COMPONENT_API.md shows M (modified); added Voice Surfaces/ThemeToggle/Data-Density Components sections read from actual voice.js/theme-toggle.js/data-density.js signatures.
|
|
2878
|
+
- id: kit-dx-sessionmeta-undocumented
|
|
2879
|
+
title: sessions.js SessionMeta export undocumented while sibling SessionCard is documented
|
|
2880
|
+
notes: add SessionMeta prop-table entry adjacent to SessionCard in COMPONENT_API.md
|
|
2881
|
+
status: completed
|
|
2882
|
+
witness: SessionMeta prop-table entry added directly above SessionCard entry in Workspace Surfaces section of COMPONENT_API.md, verified via git diff showing new section text.
|
|
2883
|
+
- id: kit-dx-utility-exports-undocumented
|
|
2884
|
+
title: fmtDuration/fmtFileSize/safeUrl/makeThreadAutoScroll/injectCodeCopy/hasSelectionInside utility exports undocumented
|
|
2885
|
+
notes: add Utilities section to COMPONENT_API.md listing signature + one-line purpose for each, from chat.js/sessions.js/files.js
|
|
2886
|
+
status: completed
|
|
2887
|
+
witness: New Utilities section added to COMPONENT_API.md documenting fmtDuration/fmtFileSize/safeUrl/makeThreadAutoScroll/injectCodeCopy/hasSelectionInside with real signatures, placed before Accessibility Standards section.
|
package/package.json
CHANGED
package/site/app/js/app.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as B from './backend.js';
|
|
|
3
3
|
|
|
4
4
|
installStyles().catch(() => {});
|
|
5
5
|
|
|
6
|
-
const { AppShell, WorkspaceShell, WorkspaceRail, Topbar, Crumb, Side, Status, Chat, ChatComposer, AgentChat, ConversationList, SessionDashboard, Row, Panel, PageHeader, SearchInput, TextField, Select, Btn, Icon, EventList, Spinner, Alert, FileGrid, FileSkeleton, sortFiles, FileToolbar, RootsPicker, BreadcrumbPath, EmptyState, FileViewer, FilePreviewPane, FilePreviewCode, FilePreviewText, FilePreviewMedia, ThemeToggle, ContextPane, PromptDialog, ConfirmDialog, DropZone, UploadProgress, FilterPills, SessionMeta, BulkBar, Checkbox, ShortcutList, FocusTrap } = C;
|
|
6
|
+
const { AppShell, WorkspaceShell, WorkspaceRail, Topbar, Crumb, Side, Status, Chat, ChatComposer, AgentChat, ConversationList, SessionDashboard, Row, Panel, PageHeader, SearchInput, TextField, Select, Btn, Icon, EventList, Spinner, Alert, FileGrid, FileSkeleton, sortFiles, FileToolbar, RootsPicker, BreadcrumbPath, EmptyState, FileViewer, FilePreviewPane, FilePreviewCode, FilePreviewText, FilePreviewMedia, ThemeToggle, ContextPane, PromptDialog, ConfirmDialog, DropZone, UploadProgress, FilterPills, SessionMeta, BulkBar, Checkbox, ShortcutList, FocusTrap, AgentListSkeleton } = C;
|
|
7
7
|
|
|
8
8
|
// One duration/bytes vocabulary across every surface: prefer the kit's shared
|
|
9
9
|
// formatters (exported alongside the components), fall back to the local
|
|
@@ -877,7 +877,7 @@ async function loadDir(dirPath, { fromHash = false } = {}) {
|
|
|
877
877
|
if (state.files._reqId !== myReq) return;
|
|
878
878
|
// W9: translate HTTP status to plain, non-leaky copy.
|
|
879
879
|
state.files.error = e.status === 403
|
|
880
|
-
? 'That folder is outside the
|
|
880
|
+
? 'That folder is outside the accessible folders, or access is denied.'
|
|
881
881
|
: (e.status === 404 ? 'That folder no longer exists.' : (e.message || 'Could not list this directory.'));
|
|
882
882
|
state.files.entries = [];
|
|
883
883
|
}
|
|
@@ -939,7 +939,7 @@ function restoreFileFromHash(filePath) {
|
|
|
939
939
|
// One dialog at a time lives in state.files.dialog: {kind, file, error, busy}.
|
|
940
940
|
// Errors from the confined endpoints map to plain copy by HTTP status.
|
|
941
941
|
function fileMutationCopy(e) {
|
|
942
|
-
if (e.status === 403) return 'Permission denied, or the target is outside the
|
|
942
|
+
if (e.status === 403) return 'Permission denied, or the target is outside the accessible folders.';
|
|
943
943
|
if (e.status === 404) return 'That file no longer exists.';
|
|
944
944
|
if (e.status === 409) return e.message || 'A file with that name already exists.';
|
|
945
945
|
if (e.status === 413) return 'Too large (50MB upload cap).';
|
|
@@ -1217,7 +1217,7 @@ function fileDialog() {
|
|
|
1217
1217
|
: (!st.dir ? 'that path is not a directory' : null);
|
|
1218
1218
|
} catch (e) {
|
|
1219
1219
|
if (state.files.dialog !== d) return;
|
|
1220
|
-
d.error = e.status === 403 ? 'outside the
|
|
1220
|
+
d.error = e.status === 403 ? 'outside the accessible folders'
|
|
1221
1221
|
: (e.status === 404 ? 'folder not found on the server' : null);
|
|
1222
1222
|
}
|
|
1223
1223
|
render();
|
|
@@ -1440,7 +1440,7 @@ function filesMain() {
|
|
|
1440
1440
|
const rootsRow = roots.length > 1
|
|
1441
1441
|
? RootsPicker({
|
|
1442
1442
|
roots: roots.map((r) => ({ id: r, label: truncate(projectLabel(r) || r, 16, 28) })),
|
|
1443
|
-
selected: f.path, onSelect: (r) => loadDir(r), label: 'Jump to an
|
|
1443
|
+
selected: f.path, onSelect: (r) => loadDir(r), label: 'Jump to an accessible folder',
|
|
1444
1444
|
})
|
|
1445
1445
|
: null;
|
|
1446
1446
|
const targetCwd = f.path || (roots.length === 1 ? roots[0] : '');
|
|
@@ -1478,11 +1478,12 @@ function filesMain() {
|
|
|
1478
1478
|
// Detect directory drops: browsers report an empty FileList for dirs.
|
|
1479
1479
|
// Check DataTransferItems when available; fall back to empty files list.
|
|
1480
1480
|
const items = ev && ev.dataTransfer && ev.dataTransfer.items;
|
|
1481
|
+
const FOLDER_DROP_MSG = 'folders cannot be dropped - use new folder to create one';
|
|
1481
1482
|
if (items) {
|
|
1482
1483
|
const hasDir = Array.from(items).some(it => { try { return it.webkitGetAsEntry && it.webkitGetAsEntry()?.isDirectory; } catch { return false; } });
|
|
1483
|
-
if (hasDir) { announce(
|
|
1484
|
+
if (hasDir) { announce(FOLDER_DROP_MSG); return; }
|
|
1484
1485
|
} else if (!files || !files.length) {
|
|
1485
|
-
announce(
|
|
1486
|
+
announce(FOLDER_DROP_MSG); return;
|
|
1486
1487
|
}
|
|
1487
1488
|
uploadFiles(files);
|
|
1488
1489
|
},
|
|
@@ -1513,9 +1514,15 @@ function filesMain() {
|
|
|
1513
1514
|
(f.uploads && f.uploads.length) ? h('div', { key: 'fup' }, UploadProgress({
|
|
1514
1515
|
// Recovery affordances per row: 'replace' on a name collision (409),
|
|
1515
1516
|
// dismiss on any error row (errors otherwise persist until the next batch).
|
|
1516
|
-
items: f.uploads.map((it) =>
|
|
1517
|
-
|
|
1518
|
-
|
|
1517
|
+
items: f.uploads.map((it) => {
|
|
1518
|
+
// No chunk-level progress is available from fetch, so an in-flight
|
|
1519
|
+
// row with no percent yet gets the marquee affordance instead of a
|
|
1520
|
+
// static 0% fill that reads as stuck.
|
|
1521
|
+
const base = (!it.error && !it.done && !it.pct) ? { ...it, indeterminate: true } : it;
|
|
1522
|
+
return (base.error && base.status === 409 && !base._retrying)
|
|
1523
|
+
? { ...base, actions: [{ label: 'replace', onClick: () => retryUploadOverwrite(base) }] }
|
|
1524
|
+
: base;
|
|
1525
|
+
}),
|
|
1519
1526
|
onDismiss: (item, i) => {
|
|
1520
1527
|
const src = (state.files.uploads || [])[i];
|
|
1521
1528
|
if (src && src.error) dismissUpload(src);
|
|
@@ -1583,10 +1590,10 @@ async function stopAllActive(sessions) {
|
|
|
1583
1590
|
const okSids = sids.filter((sid, i) => results[i].status === 'fulfilled');
|
|
1584
1591
|
const failed = sids.length - okSids.length;
|
|
1585
1592
|
state.live.bulkStopError = failed
|
|
1586
|
-
? failed + '
|
|
1593
|
+
? failed + ' conversation' + (failed === 1 ? '' : 's') + ' did not stop - try again'
|
|
1587
1594
|
: null;
|
|
1588
1595
|
announce(failed
|
|
1589
|
-
? 'stopped ' + okSids.length + ' of ' + sids.length + '
|
|
1596
|
+
? 'stopped ' + okSids.length + ' of ' + sids.length + ' conversations'
|
|
1590
1597
|
: 'stopped ' + plural(okSids.length, 'conversation'));
|
|
1591
1598
|
await refreshActive();
|
|
1592
1599
|
render();
|
|
@@ -1758,12 +1765,12 @@ function liveMain() {
|
|
|
1758
1765
|
return [
|
|
1759
1766
|
offlineBanner(),
|
|
1760
1767
|
lv.bulkStopError
|
|
1761
|
-
? Alert({ key: 'bulkstoperr', kind: 'warn', title: 'Some
|
|
1768
|
+
? Alert({ key: 'bulkstoperr', kind: 'warn', title: 'Some conversations did not stop',
|
|
1762
1769
|
children: [
|
|
1763
1770
|
h('span', { key: 'bsetxt' }, lv.bulkStopError + ' '),
|
|
1764
1771
|
Btn({ key: 'bsedismiss', onClick: () => { state.live.bulkStopError = null; render(); }, children: 'dismiss' })] })
|
|
1765
1772
|
: null,
|
|
1766
|
-
PageHeader({ compact: true, dense: true, title: 'Live
|
|
1773
|
+
PageHeader({ compact: true, dense: true, title: 'Live conversations', lede: 'Watch, open, and stop running agent conversations.' }),
|
|
1767
1774
|
SessionDashboard({
|
|
1768
1775
|
sessions,
|
|
1769
1776
|
offline,
|
|
@@ -2158,7 +2165,7 @@ function chatMain() {
|
|
|
2158
2165
|
if (!st || st.ok === false) { state.cwdError = 'directory not found on the server: ' + path; render(); return; }
|
|
2159
2166
|
if (!st.dir) { state.cwdError = 'that path is not a directory'; render(); return; }
|
|
2160
2167
|
} catch (e) {
|
|
2161
|
-
state.cwdError = e.status === 403 ? 'outside the
|
|
2168
|
+
state.cwdError = e.status === 403 ? 'outside the accessible folders'
|
|
2162
2169
|
: (e.status === 404 ? 'directory not found on the server: ' + path
|
|
2163
2170
|
: (e.status ? 'directory not found on the server: ' + path : 'could not validate the path - server unreachable'));
|
|
2164
2171
|
render();
|
|
@@ -2607,7 +2614,7 @@ const debouncedCwdProbe = debounce(async () => {
|
|
|
2607
2614
|
: (!st.dir ? 'that path is not a directory' : null);
|
|
2608
2615
|
} catch (e) {
|
|
2609
2616
|
if ((state.cwdDraft ?? '').trim() !== probed) return;
|
|
2610
|
-
state.cwdError = e.status === 403 ? 'outside the
|
|
2617
|
+
state.cwdError = e.status === 403 ? 'outside the accessible folders'
|
|
2611
2618
|
: (e.status === 404 ? 'folder not found on the server' : null);
|
|
2612
2619
|
}
|
|
2613
2620
|
state.cwdChecking = false;
|
|
@@ -2687,7 +2694,9 @@ function historyMain() {
|
|
|
2687
2694
|
h('p', { key: 'gs', class: 'history-empty-sub' },
|
|
2688
2695
|
count
|
|
2689
2696
|
? count + ' conversation' + (count === 1 ? '' : 's') + ' available · use the search box or press / to filter'
|
|
2690
|
-
: 'Start a chat or run a local coding agent - its conversation will appear here live.')
|
|
2697
|
+
: 'Start a chat or run a local coding agent - its conversation will appear here live.'),
|
|
2698
|
+
count ? h('div', { key: 'gh', class: 'history-empty-hints' },
|
|
2699
|
+
ShortcutList({ shortcuts: SHORTCUTS.slice(0, 4) })) : null),
|
|
2691
2700
|
].filter(Boolean);
|
|
2692
2701
|
}
|
|
2693
2702
|
|
|
@@ -3221,7 +3230,7 @@ function serverPanel() {
|
|
|
3221
3230
|
SessionMeta({ key: 'sfacts', items: facts }),
|
|
3222
3231
|
roots.length
|
|
3223
3232
|
? SessionMeta({ key: 'sroots', items: roots.map((r, i) => ({ label: 'root ' + (i + 1), value: r, title: r, onCopy: () => copyText(r, 'root copied') })) })
|
|
3224
|
-
: (hh.status && hh.status !== 'unknown' ? h('div', { key: 'snoroots', class: 't-meta' }, '
|
|
3233
|
+
: (hh.status && hh.status !== 'unknown' ? h('div', { key: 'snoroots', class: 't-meta' }, 'accessible folders: none configured') : null),
|
|
3225
3234
|
],
|
|
3226
3235
|
});
|
|
3227
3236
|
}
|
|
@@ -3353,8 +3362,7 @@ function agentsPanel() {
|
|
|
3353
3362
|
// The empty array means one of three things; never let an in-flight load
|
|
3354
3363
|
// read as a broken registry.
|
|
3355
3364
|
: [state.agentsLoading
|
|
3356
|
-
?
|
|
3357
|
-
Spinner({ key: 'spin', size: 'sm' }), 'loading agents…')
|
|
3365
|
+
? AgentListSkeleton({ rows: 5 })
|
|
3358
3366
|
: (state.agentsError
|
|
3359
3367
|
? h('div', { key: 'agfail', class: 't-meta empty-state' },
|
|
3360
3368
|
h('span', { key: 'agfailtxt' }, 'the agent list failed to load'),
|
|
@@ -3609,6 +3617,8 @@ async function recheckHealth() {
|
|
|
3609
3617
|
}
|
|
3610
3618
|
|
|
3611
3619
|
async function init() {
|
|
3620
|
+
state.health = { status: 'unknown' };
|
|
3621
|
+
render();
|
|
3612
3622
|
try {
|
|
3613
3623
|
const r = await B.probeBackend(state.backend);
|
|
3614
3624
|
state.health = r.ok ? { status: 'ok', ...r.info } : { status: 'down', ...r };
|