agentgui 1.0.1056 → 1.0.1058
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/mem-c4aaec5c4e6f80c2-920.md +8 -0
- package/.gm/memories/mem-eae1e383927854fb-2649.md +8 -0
- package/.gm/prd.yml +6 -0
- package/AGENTS.md +5 -1
- package/package.json +1 -1
- package/site/app/js/app.js +51 -14
- package/site/app/vendor/anentrypoint-design/247420.css +6 -0
- package/site/app/vendor/anentrypoint-design/247420.js +12 -12
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: mem-c4aaec5c4e6f80c2-920
|
|
3
|
+
ns: default
|
|
4
|
+
created: 1783884935543
|
|
5
|
+
updated: 1783884935543
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
{"key":"agentgui-ds-load-local-vendor-detail","value":"agentgui DS (design kit) loading: index.html loads the DS kit from local ./vendor/anentrypoint-design/247420.{js,css}, NOT unpkg. Prior 'moved to unpkg @latest' note (2026-05-29) was a transient state reverted in eb1eab3 (re-vendored with AgentChat), witnessed loading from ./vendor/ again on the 2026-06-04/06-05 runs and reconfirmed live on the 37th (2026-07-12) and 40th (2026-07-12) runs via live network-trace browser dispatch. The vendored copy IS the shipped UI - predictable, no upstream-publish drift. Update flow: edit the kit at /config/workspace/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, unaffected by this vendoring."}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: mem-eae1e383927854fb-2649
|
|
3
|
+
ns: default
|
|
4
|
+
created: 1783884912840
|
|
5
|
+
updated: 1783884912840
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
{"key":"agentgui-40th-run-gui-logic-predictability-sweep","value":"agentgui 40th run (2026-07-12): gui-logic-predictability workflow wf_c0a8d954-547 (20 agents, 196 tool calls, 0 errors) - 11 confirmed findings, all implemented. App (site/app/js/app.js, backend.js): global Escape ladder gained confirmingClearData disarm (settings clear-local-data confirm was the one armed state missing from the ladder); History detail header title/lede now use pathBasename(cwd) fallback instead of raw path, matching every other headline surface; wsCall gained a 15s timeout+cleanup (previously a hung WS RPC left promises pending forever with zero indicator); agy (Antigravity) resumeSid now forwards true once past first turn so its already-implemented --continue path actually fires (was hardcoded to only forward for claude-code), and the 'does not resume' banner now excludes agy since it has real continuity; pastedFilesToChat now calls the newly-exported kit flashComposerNote for visible upload-progress/failure/success feedback plus an undo-history-loss note. Kit (design/src/components/{chat,content}.js, app-shell.css, chat.css, components.js barrel): Row's primary .title span gained a title= tooltip fallback (39th run only fixed .sub); .ds-file-actions resting opacity raised 0->0.35 for desktop-pointer discoverability without hover; chat-composer-hint now visible at rest (was focus/draft-gated) and no longer aria-hidden; insertEmoji gained a one-time sessionStorage-gated undo-loss note matching draft-restore's existing pattern; flashComposerNote exported through the components.js barrel. Kit built+tested clean, rebuilt, re-vendored. Kit pushed 541df4d (npm-publish auto-bump landed as 92422d8), agentgui pushed 53610a4 then 4a5d6e5 (PRD-resolve residual), all 4 CI checks green both repos. Browser-witnessed every finding live on buildesk using a NEW reliable pattern: combine setHTTPCredentials+goto+wait+evaluate into ONE dispatch (splitting across dispatches hits session-id rotation and reads a genuinely-blank document.body despite window.__agentgui resolving), and read results via console.log('WITNESS:'+JSON.stringify(...)) + grep stdout/debug.console rather than the capture prefix's result field (confirmed still returns undefined even though the evaluated code's side effects and console output are real). All witnesses: confirmingClearData Escape before:true/after:false; composer-hint display:block no aria-hidden; .ds-file-actions opacity 0.35; 16/16 Row .title elements carry title= in settings agents panel; deployed backend.js/app.js/247420.js curl-confirmed to contain every shipped fix string; 0 pageErrors throughout."}
|
package/.gm/prd.yml
CHANGED
|
@@ -3076,3 +3076,9 @@
|
|
|
3076
3076
|
- gm-plugkit/playwriter browser verb dom=/capture eval context defect - requires an upstream tool fix outside agentgui/design
|
|
3077
3077
|
status: completed
|
|
3078
3078
|
witness: 'External tool defect, not resolvable from this repo/session: the gm-plugkit/playwriter browser verb''s dom= and capture prefixes evaluate in a Node vm context with no page/document binding (ReferenceError on every attempt this session), unlike the screenshot= and url=<target> paths which do reach the real page. This is a defect in the upstream gm-plugkit/playwriter tool package itself, outside agentgui and design repo scope. Recorded per the false-completion rule as blockedBy:external rather than marked done - screenshots remain the working witness fallback and were used for all browser verification in this sweep.'
|
|
3079
|
+
- id: 41st-run-verify-buildesk-live
|
|
3080
|
+
subject: Live-verify all confirmed+implemented findings on https://buildesk.acc.l-inc.co.za/gm via browser witness using the reliable single-dispatch creds+goto+wait+evaluate pattern
|
|
3081
|
+
status: pending
|
|
3082
|
+
- id: 41st-run-push-ci-green
|
|
3083
|
+
subject: Push kit and agentgui changes, verify CI green on both repos before COMPLETE
|
|
3084
|
+
status: pending
|
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
+
## GUI logic+predictability sweep (2026-07-12) — forty-first run
|
|
4
|
+
|
|
5
|
+
`gui-logic-predictability` workflow wf_c645ba95-c6a (23 agents, 192 tool calls, 0 errors) — 10 confirmed findings, all implemented, plus one real kit bug found and fixed mid-verification (not from the workflow's own hunt). App (`site/app/js/app.js`): `runningPanel()`'s title read `'running · N'` with no scoping cue even though the panel always lists every in-flight session app-wide, not just ones related to the current chat — retitled `'all running sessions · N'`, and it now appends `'(refreshing…)'` while a backgrounded tab's poll is catching up after refocus (`refreshActive()` sets a `state._activeStale` flag while `document.hidden` skips the network call, cleared on the next real response) instead of silently painting stale data as fresh. `runningRowTitle()` fell straight to `UNTITLED_CONVERSATION` for a brand-new session with no index row yet, while the Live dashboard's `computeLiveSessions()` already had a 3s "indexing…" carve-out for the identical case — the same session read two contradictory identities in the same 0-3s window depending only on which panel you looked at; gave `runningRowTitle` the matching carve-out. Live dashboard cards sorted by `elapsed`/`activity` re-sort on every tick (both are continuously-changing values), which could reorder a card out from under a mid-click pointer (selecting a checkbox, clicking stop) — added a module-level `_livePointerDown` flag (set/cleared on document `pointerdown`/`pointerup`/`pointercancel`) that freezes the sort to the last-computed sid order while a pointer is held anywhere in the dashboard. agy's real `--continue` resume path (wired last run) had no composer disclosure the way claude-code's resume banner does — added a `'continues most recent conversation'` composerContext bit for agy past its first turn. History's `ConversationList` sessions mapper hardcoded `agent: undefined` while the Running-panel/Live-dashboard rows for the identical finished-vs-in-flight session both show an agent/model badge — traced to ccsniff's `Store.sessions()` never folding per-event `model` into the session record even though `flattenEvent` captures it; fixed upstream (see below) and wired `agent: agentById('claude-code').name + ' · ' + s.model` into the mapper (ccsniff only reads Claude Code's own JSONL, so the agent is always constant). Kit (`design/src/components/{chat,content}.js`, `design/chat.css`, `design/src/components/sessions.js`): per-message chat copy action (`ChatMessage`'s generic `actionRow`) had zero visible click feedback for sighted/mouse users — only an `aria-live` `announce()` — unlike the three sibling copy patterns already in the same file (code-block copy, `CodeNode`/`ToolCallNode` copy) which all self-manage a label/icon flip to "copied" for 1.6s; added the matching flip keyed off `a.label === 'copy'`. Follow-up chips (contextual, derived from the last turn) and empty-state seed chips (generic starter ideas) shared identical DOM shape/class with zero visual signal distinguishing them — `.agentchat-followup` gained a dashed border (same pill shape/size, no new color/shape language). `flashComposerNote`'s single shared DOM node silently overwrote an unread note if a second call landed before the first note's 2.6s timeout — now queues notes and drains them in order instead of dropping the first message. `SessionDashboard`'s filter `SearchInput` never forwarded `resultCount` to its `aria-live` region (the Live dashboard's own filtered session count was available but unused) — wired it through. **That last change surfaced a real, previously-latent kit bug independent of this run's own hunt: `SearchInput` (`design/src/components/content.js`) conditionally returned either a bare `<input>` VElement or a wrapping `<span>` VElement depending on whether `resultCount`/a clear button were present that render — since `resultCount` now toggles from `undefined` to a string as the Live filter's value changes, webjsx's `applyDiff` tried to morph one element type into another at the same keyed toolbar slot, producing a corrupted merged DOM node (a real `<select>` picked up `type=search`/`name=q`/`placeholder=...` attributes from the `SearchInput` render, and the actual `<input>` vanished entirely) — live-witnessed on buildesk before the fix (`hasInput:false` on the toolbar). Fixed by always returning the `.ds-search-input-wrap` shape (confirmed `display:contents` in CSS, so it's layout-transparent and safe for every existing call site).** ccsniff (separate repo, `github:AnEntrypoint/ccsniff#main`, cloned fresh to `/config/workspace/ccsniff-work`): `Store.sessions()` (`src/store.js`) folded in the most-recent-by-timestamp `model` per session (events aren't guaranteed in ts order since JSONL is read file-by-file); `index.js`'s assistant-event ingestion never actually populated `model` on pushed content blocks (only `system`/init events carried `e.model`) — real Claude Code JSONL carries the actually-used model at `message.model` on every assistant turn, so that's now inherited onto every block from that message. `node test.js`: ALL TESTS PASS both commits. Pushed `11f6c3b` then (after a remote-advanced rebase) `26bbfcc`/`beff5e7`, ccsniff CI (Publish/Auto-Declaudeify/Deploy GH Pages) green both pushes. Kit built+tested twice (once per round of edits — findings, then the SearchInput fix), re-vendored both times. Reinstalling the ccsniff dependency required removing `bun.lock`'s pinned commit hash entirely (`bun install ccsniff@github:...#main --force` alone kept resolving to the stale pinned sha even after a `rm -rf node_modules/ccsniff`) — deleting `bun.lock` and re-running `bun install` re-resolved `#main` to the actual latest commit. The local buildesk server process needed an explicit restart (`kill -TERM` on the `bun server.js` PID) for the new `node_modules/ccsniff` to load — Node/Bun caches modules in-process, so an npm/git dependency swap under a running process is invisible until restart; the env's custom Node supervisor (`/opt/gmweb-startup`, not a standard supervisord) auto-respawned it within ~20s of the health-check failing, re-launching via `bunx agentgui@latest` which correctly resolves to the local workspace's own `bin/gmgui.cjs` in this workspace-linked setup (confirmed by the "Workspace mode: skipping npm version checker" startup log line), not the published npm package. Browser-witnessed every finding live on buildesk: `.ds-dash-toolbar` filter input/select intact before AND after typing with the corruption fixed, `aria-live` region reading `'0 results'`; `.chat-msg-action.is-copied`/`.agentchat-followup` CSS rules present in the live CSSOM; History rail rows reading `'agentgui · 3s ago · Claude Code · claude-sonnet-5'` (18/18 sessions carrying a real model after the ccsniff fix + server restart); synthetic `pointerdown` dispatch confirmed no page error from the new listener. 0 pageErrors throughout.
|
|
6
|
+
|
|
3
7
|
## GUI logic+predictability sweep (2026-07-12) — fortieth run
|
|
4
8
|
|
|
5
9
|
`gui-logic-predictability` workflow wf_c0a8d954-547 (20 agents, 196 tool calls, 0 errors) — 11 confirmed findings, all implemented; the lens is still surfacing real gaps at run 40, contrary to the 39th run's thinning-yield note. App (`site/app/js/app.js`, `site/app/js/backend.js`): the global Escape ladder disarmed `confirmingEdit`/`confirmingNewChat`/`confirmingStopAll`/`confirmingStopSelected` but never `confirmingClearData` (settings' arm-then-confirm "clear all local data?" banner) — a keyboard user who armed it and pressed the ASCII-standard cancel gesture this app trains everywhere else got no response; added the matching disarm branch. History detail header title/lede fell back to the raw full `cwd` path instead of `pathBasename(cwd)` like every other headline surface (chat cwd label, files breadcrumb, resume banner) — wrapped both fallback sites; the unabbreviated path stays available via the labeled `SessionMeta` "directory" row's own `title=` tooltip. `wsCall` (the WS RPC helper every `backend.js` call goes through) had no timeout at all — a hung `chat.active`/any other response left its promise pending forever with zero indicator; added a 15s timeout that rejects and clears the pending map, `resolve`/`reject` wrapped to clear the timer on a real reply. agy (Antigravity) has a working `--continue` (most-recent-conversation) resume path server-side (`lib/claude-runner-agents.js`) that the client never triggered — `resumeSid` was hardcoded to only forward for claude-code, so agy always got the flattened-transcript preamble instead of true continuity, AND the "does not resume across turns" banner fired for agy exactly like the genuinely-stateless opencode/kilo/codex, misattributing a missing client wire as an agent limitation; now `resumeSid` forwards `true` for agy once the chat is past its first turn (agy's `--continue` ignores the sid value, boolean-truthy is sufficient) and the banner excludes agy. Pasted/dropped files into the composer only fired a screen-reader-only `announce()` during upload — zero visible feedback for sighted mouse users on progress or failure; now calls the kit's `flashComposerNote` (newly exported) on the real composer element for upload-start/failure/success, and the success announce text now discloses the undo-history caveat inline. Kit (`design/src/components/{chat,content}.js`, `design/app-shell.css`, `design/chat.css`, `design/src/components.js`): `Row`'s primary `.title` span had no `title=` tooltip fallback (only `.sub` got one in the 39th run) — the more commonly-truncated primary label was the bigger gap; fixed at the one shared render site so every `Row` consumer (settings agents panel, etc.) inherits it. `.ds-file-actions` (Files row rename/move/delete icons) were `opacity:0` by default on desktop mouse/trackpad pointers, fully invisible without an accidental hover — raised the resting baseline to `0.35` so the actions are discoverable without hover, full `1` still on hover/focus-within. The Enter-to-send composer hint was CSS-hidden except while focused or carrying a draft (and `aria-hidden`), so a brand-new user looking at an empty, unfocused composer had no in-UI way to learn Enter-vs-Shift+Enter — now visible at rest above 420px (still hidden under 420px to save rows) and no longer `aria-hidden` since it's real content, not decoration. `insertEmoji`'s direct `taEl.value=` assignment discards the native undo stack the same way draft-restore's `.value=` does, but only draft-restore surfaced an explanatory note — added a matching one-time (`sessionStorage`-gated) `flashComposerNote` call on first emoji insert per session. `flashComposerNote` exported from `chat.js` through the `components.js` barrel (33rd-run standing lesson: a kit function must clear the barrel to be consumable by the app). Kit built+tested (`bun test.js` all pass), rebuilt (`node scripts/build.mjs`, 0 lint errors), re-vendored into `site/app/vendor/anentrypoint-design/`. Browser-witnessed live on buildesk via the now-standard `page.context().setHTTPCredentials()` + single-dispatch (creds+goto+wait+evaluate, same session) pattern: `confirmingClearData` Escape-disarm before:true/after:false; composer hint `display:block` with `aria-hidden` absent; `.ds-file-actions` computed `opacity:"0.35"`; settings agents-panel `Row` `.title` elements 16/16 carry a `title=` attribute; deployed `backend.js`/`app.js`/`247420.js` all curl-confirmed to contain the shipped fix strings (`timeoutMs = 15000`, the agy banner-exclusion comment, `pathBasename(sess?.cwd)`, `undoNoteShown`, `ds-file-actions`); 0 pageErrors across every dispatch. **Reconfirmed standing tool defect, worse than previously documented: browser session ids silently rotate across SEPARATE dispatches even against the "same" nominal session, and a dispatch landing on a stale/rotated session reads an entirely blank `document.body` (0 children) despite `window.__agentgui` still resolving — the fix is to always combine credentials-set + goto + wait + evaluate into ONE single dispatch rather than splitting navigation and reading across dispatches.** Also reconfirmed the `capture` prefix's `page.evaluate` return value is NOT propagated back through the tool's `result` field (comes back `undefined` even though the evaluated expression itself runs correctly and its side effects land) — the reliable read pattern is `console.log("WITNESS:" + JSON.stringify(...))` inside the evaluated callback and grep the dispatch's `stdout`/`debug.console`, not the `result` field.
|
|
@@ -284,7 +288,7 @@ GUI source keeps typographic product characters — the middot separator `·`, t
|
|
|
284
288
|
|
|
285
289
|
## DS load = LOCAL vendor (resolved — the earlier unpkg note is stale)
|
|
286
290
|
|
|
287
|
-
|
|
291
|
+
`index.html` loads the DS kit from local `./vendor/anentrypoint-design/247420.{js,css}`, NOT unpkg — reconfirmed live on the 40th run. Full detail in rs-learn (recall "agentgui ds load local vendor detail").
|
|
288
292
|
|
|
289
293
|
|
|
290
294
|
@.gm/next-step.md
|
package/package.json
CHANGED
package/site/app/js/app.js
CHANGED
|
@@ -358,10 +358,13 @@ function activeSig(list) {
|
|
|
358
358
|
async function refreshActive() {
|
|
359
359
|
// A backgrounded tab still holds its interval timer, but polling every ~3.3s
|
|
360
360
|
// while hidden is needless server load across many left-open tabs - skip the
|
|
361
|
-
// network call (and let the next visible tick catch up).
|
|
362
|
-
|
|
361
|
+
// network call (and let the next visible tick catch up). Mark the currently
|
|
362
|
+
// held state.active as stale so a refocus render doesn't silently paint
|
|
363
|
+
// minutes-old data as fresh while the re-poll is still in flight.
|
|
364
|
+
if (typeof document !== 'undefined' && document.hidden) { state._activeStale = true; return; }
|
|
363
365
|
let next;
|
|
364
366
|
try { next = await B.listActiveChats(state.backend); } catch { return; }
|
|
367
|
+
state._activeStale = false;
|
|
365
368
|
const changed = activeSig(next) !== activeSig(state.active);
|
|
366
369
|
state.active = next;
|
|
367
370
|
if (changed) state._sessionGroupsCache = null;
|
|
@@ -845,7 +848,13 @@ function sessionsColumn() {
|
|
|
845
848
|
// carries only the time (and agent when present).
|
|
846
849
|
project: project === title ? '' : project,
|
|
847
850
|
time: fmtRelTime(s.last),
|
|
848
|
-
|
|
851
|
+
// ccsniff only reads Claude Code's own JSONL (see AGENTS.md), so the
|
|
852
|
+
// agent is always claude-code; ccsniff's sessions() now also folds in
|
|
853
|
+
// the session's most-recent model - surfacing both here matches the
|
|
854
|
+
// badge the running-panel/live-dashboard rows already show for the
|
|
855
|
+
// identical session while it's in-flight, instead of going blank the
|
|
856
|
+
// moment it finishes and drops into History.
|
|
857
|
+
agent: (agentById('claude-code')?.name || 'Claude Code') + (s.model ? ' · ' + s.model : ''),
|
|
849
858
|
running: runningSids.has(s.sid),
|
|
850
859
|
status: runningSids.has(s.sid) ? liveStatusBySid.get(s.sid) : undefined,
|
|
851
860
|
unread: false,
|
|
@@ -1724,6 +1733,14 @@ async function stopAllActive(sessions) {
|
|
|
1724
1733
|
// before it is treated as STALE - alive but not making progress, so a stuck
|
|
1725
1734
|
// agent reads differently from a busy one.
|
|
1726
1735
|
const STALE_AFTER_MS = 45000;
|
|
1736
|
+
// Tracks whether a pointer is currently held down anywhere in the document,
|
|
1737
|
+
// used to freeze Live-dashboard card sort order mid-click (see liveMain()).
|
|
1738
|
+
let _livePointerDown = false;
|
|
1739
|
+
if (typeof document !== 'undefined') {
|
|
1740
|
+
document.addEventListener('pointerdown', () => { _livePointerDown = true; });
|
|
1741
|
+
document.addEventListener('pointerup', () => { _livePointerDown = false; });
|
|
1742
|
+
document.addEventListener('pointercancel', () => { _livePointerDown = false; });
|
|
1743
|
+
}
|
|
1727
1744
|
// Rank for the error-then-stale-first ordering (W3).
|
|
1728
1745
|
const STATUS_RANK = { error: 0, stale: 1, running: 2 };
|
|
1729
1746
|
|
|
@@ -1879,15 +1896,26 @@ function liveMain() {
|
|
|
1879
1896
|
// external, and a deterministic sid tiebreaker so equal-rank cards never
|
|
1880
1897
|
// reshuffle with the server's return order.
|
|
1881
1898
|
const sortKey = lv.sort || 'status';
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
}
|
|
1899
|
+
// 'elapsed'/'activity' sort keys are continuously-ticking values (they change
|
|
1900
|
+
// every second), so re-sorting on every render can reorder a card out from
|
|
1901
|
+
// under a mid-click pointer (selecting a checkbox, clicking stop). While a
|
|
1902
|
+
// pointer is held down anywhere in the dashboard, freeze the sort to the
|
|
1903
|
+
// last-computed sid order instead of live-recomputing it.
|
|
1904
|
+
if (_livePointerDown && state._liveSortedOrder && state._liveSortedOrder.length) {
|
|
1905
|
+
const rank = new Map(state._liveSortedOrder.map((sid, i) => [sid, i]));
|
|
1906
|
+
sessions.sort((a, b) => (rank.has(a.sid) ? rank.get(a.sid) : 1e9) - (rank.has(b.sid) ? rank.get(b.sid) : 1e9));
|
|
1907
|
+
} else {
|
|
1908
|
+
sessions.sort((a, b) => {
|
|
1909
|
+
let d = (a.external ? 1 : 0) - (b.external ? 1 : 0);
|
|
1910
|
+
if (d) return d;
|
|
1911
|
+
if (sortKey === 'elapsed') d = (b.elapsedMs || 0) - (a.elapsedMs || 0);
|
|
1912
|
+
else if (sortKey === 'activity') d = (b.lastTs || 0) - (a.lastTs || 0);
|
|
1913
|
+
else if (sortKey === 'errors') d = (b.errors || 0) - (a.errors || 0);
|
|
1914
|
+
else d = (STATUS_RANK[a.status] ?? 9) - (STATUS_RANK[b.status] ?? 9);
|
|
1915
|
+
return d || String(a.sid).localeCompare(String(b.sid));
|
|
1916
|
+
});
|
|
1917
|
+
state._liveSortedOrder = sessions.map(s => s.sid);
|
|
1918
|
+
}
|
|
1891
1919
|
const selected = lv.selected instanceof Set ? lv.selected : new Set();
|
|
1892
1920
|
// The in-page chat's card accent matches on the real sid, but the kit
|
|
1893
1921
|
// compares activeSid against card.sid (the ephemeral id for owned cards).
|
|
@@ -2230,7 +2258,9 @@ function chatMain() {
|
|
|
2230
2258
|
userTurnCount > 0 ? plural(userTurnCount, 'turn') : null,
|
|
2231
2259
|
(state.chat.resumeSid && state.selectedAgent === 'claude-code')
|
|
2232
2260
|
? 'continues conversation (' + resumeSidLabel(state.chat.resumeSid) + ')'
|
|
2233
|
-
:
|
|
2261
|
+
: (state.selectedAgent === 'agy' && userTurnCount > 0)
|
|
2262
|
+
? 'continues most recent conversation'
|
|
2263
|
+
: null,
|
|
2234
2264
|
].filter(Boolean),
|
|
2235
2265
|
} : undefined,
|
|
2236
2266
|
// W15: contextual follow-up chips derived from the settled last turn
|
|
@@ -3164,6 +3194,13 @@ function resumeSidLabel(sid) {
|
|
|
3164
3194
|
// everywhere else.
|
|
3165
3195
|
function runningRowTitle(r) {
|
|
3166
3196
|
const realSid = r.claudeSessionId || r.sessionId;
|
|
3197
|
+
const arr = Array.isArray(state.sessions) ? state.sessions : [];
|
|
3198
|
+
const sess = arr.find((s) => s.sid === realSid);
|
|
3199
|
+
// A brand-new session (started <3s ago) with no index row yet is still
|
|
3200
|
+
// BEING indexed, not permanently untitled - same carve-out and threshold
|
|
3201
|
+
// computeLiveSessions() uses, so the identical session doesn't read
|
|
3202
|
+
// "Untitled conversation" here and "indexing…" on the Live dashboard.
|
|
3203
|
+
if (!sess && r.startedAt && (Date.now() - r.startedAt < 3000)) return 'indexing…';
|
|
3167
3204
|
return resumeSidLabel(realSid);
|
|
3168
3205
|
}
|
|
3169
3206
|
|
|
@@ -3200,7 +3237,7 @@ function runningPanel() {
|
|
|
3200
3237
|
const stopping = state.live.stopping || new Set();
|
|
3201
3238
|
return Panel({
|
|
3202
3239
|
key: 'runningPanel',
|
|
3203
|
-
title: 'running · ' + running.length,
|
|
3240
|
+
title: 'all running sessions · ' + running.length + (state._activeStale ? ' (refreshing…)' : ''),
|
|
3204
3241
|
children: [
|
|
3205
3242
|
// A discoverable path from "this running chat" to the management surface.
|
|
3206
3243
|
h('div', { key: 'runall', class: 'resume-banner', role: 'group' },
|
|
@@ -7130,6 +7130,7 @@
|
|
|
7130
7130
|
.ds-247420 .chat-msg-action-label { font-size: var(--fs-tiny); }
|
|
7131
7131
|
.ds-247420 .chat-msg-action:hover { background: var(--bg-2); color: var(--fg); }
|
|
7132
7132
|
.ds-247420 .chat-msg-action:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; opacity: 1; }
|
|
7133
|
+
.ds-247420 .chat-msg-action.is-copied { color: var(--accent-ink); opacity: 1; }
|
|
7133
7134
|
|
|
7134
7135
|
/* Empty state: a fresh thread is an invitation, not a void. */
|
|
7135
7136
|
.ds-247420 .agentchat-empty {
|
|
@@ -7164,6 +7165,11 @@
|
|
|
7164
7165
|
}
|
|
7165
7166
|
.ds-247420 .agentchat-empty-suggestion:hover, .ds-247420 .chat-empty-suggestion:hover { background: color-mix(in srgb, var(--accent, var(--fg)) 12%, transparent); }
|
|
7166
7167
|
.ds-247420 .agentchat-empty-suggestion:focus-visible, .ds-247420 .chat-empty-suggestion:focus-visible { outline: 2px solid var(--accent, var(--fg)); outline-offset: var(--focus-offset); }
|
|
7168
|
+
/* Follow-up chips (contextual, based on the last turn) vs empty-state seed
|
|
7169
|
+
chips (generic starter ideas) previously shared identical DOM shape with no
|
|
7170
|
+
visual signal distinguishing them - a dashed border reads as "derived from
|
|
7171
|
+
context" without introducing a new color/shape language. */
|
|
7172
|
+
.ds-247420 .agentchat-followup { border-style: dashed; }
|
|
7167
7173
|
|
|
7168
7174
|
/* Guided install path in the empty state: copy line + monospaced command rows
|
|
7169
7175
|
(each with its own copy button) + a recheck button. No animation. */
|