agentgui 1.0.1053 → 1.0.1055
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-c7c5bc263850c332-1844.md +8 -0
- package/.gm/prd.yml +3 -0
- package/AGENTS.md +8 -0
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/site/app/js/app.js +26 -9
- package/site/app/js/backend.js +8 -2
- package/site/app/vendor/anentrypoint-design/247420.css +8 -7
- package/site/app/vendor/anentrypoint-design/247420.js +13 -13
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: mem-c7c5bc263850c332-1844
|
|
3
|
+
ns: default
|
|
4
|
+
created: 1783854998213
|
|
5
|
+
updated: 1783854998213
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
agentgui 38th run (2026-07-12): re-ran gui-logic-predictability workflow wf_186e2a2a-dfc (32 agents) one cycle after the 37th run, 18 confirmed findings all implemented. Key app fixes: stopAllActive now clears failed sids from state.live.stopping (was permanently stuck), copyText announces clipboard failures, title-fallback chains unified via projectLabel()+sid across search/history/rail, Live nav-badge stale-flame fixed via stream carve-out, computeLiveSessions gained a 5s reconnect grace window against status flapping, streamHistory EventSource gained exponential backoff mirroring the WS client. Kit fixes: follow-up chips lost aria-hidden (real buttons were AT-invisible), MdNode markdown-settle now preserves active text selection via a deferred selectionchange-gated innerHTML swap, SearchInput gained a visible clear button + working resultCount aria-live wiring. Kit pushed bed4036 (after a rebase with one dist-only conflict, resolved by rebuilding dist fresh rather than hand-merging generated code), agentgui pushed 159030f then b9d9d70 (docs), all CI green both repos. NEW STANDING TOOL DEFECT this run: the gm browser verb's dom= and capture prefixes both throw ReferenceError (no document/page binding at all) in this tool version - a regression beyond the previously-known 'dom= ignores trailing script' issue. Only screenshot= and url=<target>\n<literal-non-DOM-expr> dispatches actually reach the real page; browser session ids silently rotate across dispatches with no state carryover, and one dispatch hit a dead extension-bridge session requiring an unprompted CDP relay restart. Filed as PRD row tool-defect-browser-dom-capture-eval-broken with blockedBy:external since it's a gm-plugkit/playwriter defect, not fixable from agentgui/design repos. Screenshots remain the reliable witness fallback until fixed upstream.
|
package/.gm/prd.yml
CHANGED
|
@@ -3076,3 +3076,6 @@
|
|
|
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: 40th-run-push-ci-green
|
|
3080
|
+
subject: Push kit and agentgui changes, verify CI green on both repos before COMPLETE
|
|
3081
|
+
status: pending
|
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# AgentGUI — Agent Notes
|
|
2
2
|
|
|
3
|
+
## GUI logic+predictability sweep (2026-07-12) — fortieth run
|
|
4
|
+
|
|
5
|
+
`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.
|
|
6
|
+
|
|
7
|
+
## GUI logic+predictability sweep (2026-07-12) — thirty-ninth run
|
|
8
|
+
|
|
9
|
+
`gui-logic-predictability` workflow wf_88c431e5-931 (26 agents, 202 tool calls, 0 errors) — 6 confirmed findings after hunt+adversarial-verify, all implemented; a much thinner yield than the 37th/38th runs, consistent with the same lens converging after two straight passes. App (`site/app/js/app.js`): `runningPanel()`'s inline running-chat rows previously showed only agent+model+elapsed+cwd with no session title, reading nameless while the identical session shows a resolved title on the sessions rail/history rail/Live SessionCard — a new `runningRowTitle()` helper (wrapping the existing `resumeSidLabel()`) prepends the same resolved identity string; `stopActiveChat()` could wedge a stop button permanently disabled if the backend accepted the cancel but the underlying process outlived the immediate post-cancel `refreshActive()` call (the next 3s poll would silently re-add the sid to `state.active` while `stopping` never cleared) — a bounded 9s timeout now clears `stopping` and surfaces the same "conversation did not stop - try again" retry banner used on outright rejection; `computeLiveSessions()`'s per-sid SSE tally accumulated `tokens` but never `cost`, so every live/external session showed a blank cost field except the one open in-page in Chat — the tally now accumulates `total_cost_usd` from `result` events too, with the same tally-fallback pattern tokens already had; WorkspaceRail's footer gained a visible shortcuts-help `IconButton` (previously the `?`-overlay was 100% keyboard-only tribal knowledge with zero discovery path outside Settings). Kit (`design/src/components/{chat,content,shell}.js`): `CodeNode.refSink`'s syntax-highlight swap gained the same in-progress-text-selection guard `MdNode.refSink` already had (the two paths had drifted — code blocks still wiped an active selection mid-stream after the markdown path was fixed for the same bug); `Row.sub` gained a `title=` tooltip fallback for string values, matching every other long-text field in the app (agent-chat cwd, sessions rail title/sub/cwd/agent) — `Row` is used everywhere (history sessions rail, search results, context-pane cwd fact, agents panel) so this closes the gap at every call site at once; added a `help` icon path to `ICON_PATHS`/`Glyph` for the new rail affordance. Kit built+tested (`bun test.js` all pass), rebased cleanly on a concurrent `v0.0.316` release-bump commit (no source conflicts), dist rebuilt fresh post-rebase, pushed `00dae4c`. agentgui re-vendored, pushed `64f4466`, all 3 CI checks (Auto-Declaudeify/Publish and Release/Deploy GH Pages) green. Browser-witnessed live on buildesk via `page.context().setHTTPCredentials()` + `page.evaluate()`: help button found in `.ws-rail-foot`, clicking it opened the shortcuts overlay (`shortcutsTextPresent:true`), zero pageErrors; history rail `Row.sub` confirmed rendering `title="server default"` live. **New tool-defect note this run: this env's nginx Basic-Auth password contains a literal comma (`123,slam,123,slam` — see the 32nd-run standing gotcha), and embedding it directly in a `page.goto` URL (`https://user:pass@host/...`) throws `net::ERR_INVALID_AUTH_CREDENTIALS` at the Chromium URL-parser level even when percent-encoded (`%2C`) — this is a stricter failure than the previously-documented "breaks the app's own fetch()" caveat for comma-free creds. Working fix: `await page.context().setHTTPCredentials({username, password})` before `page.goto()` with a plain (no-embedded-creds) URL — this is the durable workaround for any future witness against this deploy, comma-password or not.** Also reconfirmed the 38th-run tool defect (`capture` prefix scripts run in a bare Node vm with no `document`/`page` binding unless the script itself calls `page.evaluate(() => {...})` — a raw top-level `document.querySelector(...)` throws `ReferenceError: document is not defined`; wrapping every DOM read/write in `page.evaluate()` inside the capture script is the reliable pattern, not a tool-side fix).
|
|
10
|
+
|
|
3
11
|
## GUI logic+predictability sweep (2026-07-12) — thirty-eighth run
|
|
4
12
|
|
|
5
13
|
`gui-logic-predictability` workflow wf_186e2a2a-dfc (32 agents, 205 tool calls, 0 errors) — 18 confirmed findings, all implemented, re-running the same lens one cycle after the 37th run to catch residual/newly-introduced gaps. App (`site/app/js/app.js`, `site/app/js/backend.js`): `stopAllActive` now clears every attempted sid (both ok and failed) from `state.live.stopping` after `Promise.allSettled`, so a failed bulk-cancel is retryable instead of leaving that row's stop button permanently disabled; `copyText`'s clipboard-write catch now calls `announce('copy failed')` instead of swallowing the error silently (mirrors `copySid`'s existing pattern); search-result row titles now route through `projectLabel()` (`r.snippet || projectLabel(r.title) || projectLabel(r.project) || UNTITLED_CONVERSATION`) matching the rail's contract; the History detail header's title-fallback chain gained `|| state.selectedSid` before the generic label, so a metadata-sparse session shows the same identity in History as it does in the rail; the Live nav-badge error flame no longer goes stale while off the history tab (stream stays connected whenever `state.active` is non-empty); `computeLiveSessions()` gained a 5s `reconnectGraceUntil` window so an SSE reconnect mid-session no longer flaps a running session's status to stale; a brand-new session between the `chat.active` poll and history-index catch-up now shows `'indexing…'` instead of reading identically to a permanently-failed lookup; the Live dashboard's sort/filter prefs (`hydratePrefs()`) now reconcile across browser tabs on focus/visibilitychange, alongside the existing `refreshActive()` call; `streamHistory`'s EventSource (`backend.js`) gained manual close+reopen exponential backoff (500ms start, doubles, capped 30s, resets on `hello`) mirroring the WS client's `scheduleReconnect`, instead of relying on native EventSource's uncapped retry; the sessions rail empty-state and History event-list both gained next-action affordances (a start-from-chat CTA, and a "load all (N hidden)" button for very large sessions); a draft restored from localStorage now surfaces a one-time note that undo history doesn't carry over a reload. Kit (`design/src/components/{agent-chat,chat,content,sessions}.js`, `app-shell.css`): follow-up suggestion chips' container lost its `aria-hidden="true"` — the chips are real interactive `<button>`s that were completely invisible to screen-reader users despite `role="group"` being present; `MdNode`'s markdown-settle `refSink` now defers its `innerHTML` swap via a one-time `selectionchange` listener when the user's active text selection is anchored inside the element (was wiping any in-progress text selection every streaming tick); `ChatComposer`'s paste handler now surfaces a "pasted N characters" note via `flashComposerNote` for large plain-text pastes; `SearchInput` gained a visible clear (X) button (was Escape-only, undiscoverable to mouse/touch users) at a 44px touch target, sharing the same clear path as Escape; `ConversationList` now forwards a `resultCount` prop through to `SearchInput`'s existing (previously unpopulated) `aria-live` result-count region, wired from agentgui's search-results branch as `hits.length + ' result(s)'`. Kit built+tested (`bun test.js` all pass), a concurrent upstream release (`5cdd667`, v0.0.315) required a rebase with one dist-only merge conflict (resolved by rebuilding `dist/247420.js` fresh from the merged sources rather than hand-merging generated code), re-vendored, browser-witnessed live on buildesk (chat tab shows `connected` status + visible follow-up chip buttons, history tab loads 52 conversations cleanly, 0 visible errors across both screenshots). Kit pushed `bed4036`, agentgui pushed `159030f` (after a second push-rebase for a PRD-state-only commit), all 4 CI checks green both repos. **New tool defect this run (recorded, not fixable from this repo — filed as `blockedBy:external`): the `gm browser` verb's `dom=` and `capture` prefixes both throw `ReferenceError` (no `document`/page binding at all) rather than evaluating in page context — a regression beyond the 37th run's already-documented "`dom=` ignores its trailing script" caveat. Only `screenshot=` and `url=<target>\n<literal-non-DOM-expr>` dispatches actually reach the real page in this tool version; browser sessions also silently rotate ids across dispatches with no state carryover, and one dispatch hit a dead extension-bridge session requiring an unprompted CDP relay restart. Screenshots are the reliable fallback for browser witnessing until this is fixed upstream in gm-plugkit/playwriter.**
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [Unreleased] - 39th-run gui-logic-predictability sweep: running-panel identity, stop-button wedge, live cost fallback, shortcuts affordance (kit 00dae4c, app 64f4466)
|
|
2
|
+
|
|
3
|
+
- app: `runningPanel()` rows now show the same resolved session title used on every other surface (sessions rail, history rail, Live SessionCard) instead of reading nameless; `stopActiveChat()` gains a bounded 9s timeout so a cancel that succeeds server-side but whose process lingers past the immediate refresh no longer wedges the stop button permanently disabled; `computeLiveSessions()`'s per-sid SSE tally now accumulates cost alongside tokens, so every live/external session shows a real cost figure, not just the one open in Chat; WorkspaceRail's footer gains a visible shortcuts-help icon button (the `?` overlay was previously 100% keyboard-only tribal knowledge with no discovery path outside Settings). Why: 39th `gui-logic-predictability` workflow (wf_88c431e5-931) confirmed these as real operating-logic gaps.
|
|
4
|
+
- kit: `CodeNode.refSink`'s syntax-highlight swap gains the same in-progress-selection guard `MdNode.refSink` already had (the two paths had drifted); `Row.sub` gains a `title=` tooltip fallback matching every other long-text field in the kit; new `help` icon path for the rail affordance.
|
|
5
|
+
- browser-witnessed live on buildesk via `page.context().setHTTPCredentials()` (embedded-URL Basic-Auth broke on this env's comma-containing password even percent-encoded) — help button + shortcuts overlay + Row.sub tooltip all confirmed working, zero pageErrors.
|
|
6
|
+
|
|
1
7
|
## [Unreleased] - 34th-run gui-ux-craft sweep: kit font-token fallbacks, focus-ring tokenization, agentsLoading state (kit 3b1080c, app 9c8094b)
|
|
2
8
|
|
|
3
9
|
- kit: `--fs-2`/`--fs-0` shadow font tokens (never defined in the real type scale) remapped to `--fs-lg`/`--fs-tiny`; stale `--lh-base` fallback fixed from 1.4 to 1.55; `.glyph`/`.ds-field-count`/`.ds-row-detail` hardcoded literals tokenized; ~29 more `outline: 2px solid var(--accent-ink)` focus rules converted to `var(--focus-w) solid var(--focus-color)`; `.chat-tool-copy` gained the coarse-pointer 44px touch target; `.ds-select` gained a base `min-height:32px` floor; `Btn`'s `className` prop renamed to `class` for consistency with `Panel`/`Heading`; `AgentControls`/`AgentChat` gained an `agentsLoading` disabled-select state. Why: 34th `gui-ux-craft` workflow (wf_919164f1-648) confirmed these as real, un-filed gaps.
|
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, TextField, Select, Btn, Icon, IconButton, 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;
|
|
6
|
+
const { AppShell, WorkspaceShell, WorkspaceRail, Topbar, Crumb, Side, Status, Chat, ChatComposer, AgentChat, ConversationList, SessionDashboard, Row, Panel, PageHeader, TextField, Select, Btn, Icon, IconButton, 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, flashComposerNote } = 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
|
|
@@ -1214,25 +1214,34 @@ async function uploadFiles(fileList) {
|
|
|
1214
1214
|
// the same confined endpoint the Files tab uses (into the chat's current cwd),
|
|
1215
1215
|
// then insert the resulting relative path into the draft. Falls back to an
|
|
1216
1216
|
// announce() if there's no cwd to upload into (chat hasn't picked one yet).
|
|
1217
|
+
function composerEl() {
|
|
1218
|
+
return document.querySelector('.chat-composer');
|
|
1219
|
+
}
|
|
1217
1220
|
async function pastedFilesToChat(files) {
|
|
1218
1221
|
const list = Array.from(files || []);
|
|
1219
1222
|
if (!list.length) return;
|
|
1220
1223
|
const dir = state.chatCwd;
|
|
1221
1224
|
if (!dir) { announce('set a working directory before pasting files'); return; }
|
|
1225
|
+
const el = composerEl();
|
|
1226
|
+
if (flashComposerNote && el) flashComposerNote(el, 'uploading ' + plural(list.length, 'file') + '…');
|
|
1222
1227
|
const inserted = [];
|
|
1223
1228
|
for (const f of list) {
|
|
1224
1229
|
try {
|
|
1225
1230
|
await B.uploadFile(state.backend, dir, f);
|
|
1226
1231
|
inserted.push(f.name);
|
|
1227
1232
|
} catch (e) {
|
|
1228
|
-
|
|
1233
|
+
const msg = 'paste upload failed: ' + fileMutationCopy(e);
|
|
1234
|
+
announce(msg);
|
|
1235
|
+
if (flashComposerNote && el) flashComposerNote(el, msg);
|
|
1229
1236
|
}
|
|
1230
1237
|
}
|
|
1231
1238
|
if (inserted.length) {
|
|
1232
1239
|
const draft = state.chat.draft || '';
|
|
1233
1240
|
state.chat.draft = draft + (draft && !draft.endsWith('\n') && !draft.endsWith(' ') ? ' ' : '') + inserted.join(' ');
|
|
1234
1241
|
debouncedPersistDraft();
|
|
1235
|
-
|
|
1242
|
+
const msg = 'pasted ' + plural(inserted.length, 'file') + ' into ' + pathBasename(dir) + ' - undo history does not include this insert';
|
|
1243
|
+
announce(msg);
|
|
1244
|
+
if (flashComposerNote && el) flashComposerNote(el, 'pasted ' + plural(inserted.length, 'file'));
|
|
1236
1245
|
render();
|
|
1237
1246
|
}
|
|
1238
1247
|
}
|
|
@@ -2079,10 +2088,13 @@ function chatMain() {
|
|
|
2079
2088
|
// silently loses prior context. Warn once the conversation is past its first
|
|
2080
2089
|
// turn so the user knows this agent is not carrying history forward.
|
|
2081
2090
|
{
|
|
2082
|
-
if (state.selectedAgent && state.selectedAgent !== 'claude-code' && userTurnCount > 1 && !state.chat.resumeSid) {
|
|
2091
|
+
if (state.selectedAgent && state.selectedAgent !== 'claude-code' && state.selectedAgent !== 'agy' && userTurnCount > 1 && !state.chat.resumeSid) {
|
|
2083
2092
|
banners.push(Alert({ key: 'nocontinuity', kind: 'info', title: (agentById(state.selectedAgent)?.name || state.selectedAgent) + ' does not resume across turns',
|
|
2084
2093
|
children: 'This agent starts fresh each message - it will not remember earlier turns in this chat. Use Claude Code for a continuous conversation.' }));
|
|
2085
2094
|
}
|
|
2095
|
+
// agy has a real --continue (most-recent-conversation) path wired via
|
|
2096
|
+
// resumeSid once this chat is past its first turn - it is NOT stateless
|
|
2097
|
+
// like opencode/kilo/codex, so it gets no "does not resume" warning.
|
|
2086
2098
|
}
|
|
2087
2099
|
if (state.chat.resumeSid && state.selectedAgent === 'claude-code') {
|
|
2088
2100
|
// The agent-switched note (if any) lives inside the resume banner rather
|
|
@@ -2690,9 +2702,13 @@ async function sendChat(textArg) {
|
|
|
2690
2702
|
// readable transcript rather than raw API objects they cannot process.
|
|
2691
2703
|
messages: state.chat.messages.slice(0, -1).map(m => ({ role: m.role, content: m.content || messageToText(m) })),
|
|
2692
2704
|
signal: ctrl.signal,
|
|
2693
|
-
//
|
|
2694
|
-
//
|
|
2695
|
-
|
|
2705
|
+
// claude-code consumes a literal --resume <sid>; agy's --continue is a
|
|
2706
|
+
// boolean 'resume most-recent conversation' flag (it ignores the sid
|
|
2707
|
+
// value entirely, see lib/claude-runner-agents.js), so any truthy value
|
|
2708
|
+
// is enough to opt agy into continuity once this chat has a prior turn.
|
|
2709
|
+
resumeSid: state.selectedAgent === 'claude-code'
|
|
2710
|
+
? (state.chat.resumeSid || undefined)
|
|
2711
|
+
: (state.selectedAgent === 'agy' && state.chat.messages.length > 2 ? true : undefined),
|
|
2696
2712
|
})) {
|
|
2697
2713
|
// After a stop, the iterator drains buffered events for a turn the user
|
|
2698
2714
|
// aborted - applying them would set resumeSid / accrue cost / write text
|
|
@@ -2859,13 +2875,13 @@ function historyMain() {
|
|
|
2859
2875
|
|
|
2860
2876
|
const sess = (Array.isArray(state.sessions) ? state.sessions : []).find(s => s.sid === state.selectedSid);
|
|
2861
2877
|
const lede = sess
|
|
2862
|
-
? (projectLabel(sess.project) || sess.cwd || 'unknown location') + ' · ' + plural(sess.events || 0, 'event') + ' · ' + plural(sess.userTurns || 0, 'turn') + ' · ' + fmtRelTime(sess.last)
|
|
2878
|
+
? (projectLabel(sess.project) || pathBasename(sess.cwd) || 'unknown location') + ' · ' + plural(sess.events || 0, 'event') + ' · ' + plural(sess.userTurns || 0, 'turn') + ' · ' + fmtRelTime(sess.last)
|
|
2863
2879
|
: UNTITLED_CONVERSATION;
|
|
2864
2880
|
|
|
2865
2881
|
const head = PageHeader({
|
|
2866
2882
|
compact: true,
|
|
2867
2883
|
dense: true,
|
|
2868
|
-
title: truncate(projectLabel(sess?.title) || projectLabel(sess?.project) || sess?.cwd || state.selectedSid || UNTITLED_CONVERSATION, 40, 80),
|
|
2884
|
+
title: truncate(projectLabel(sess?.title) || projectLabel(sess?.project) || pathBasename(sess?.cwd) || state.selectedSid || UNTITLED_CONVERSATION, 40, 80),
|
|
2869
2885
|
lede,
|
|
2870
2886
|
});
|
|
2871
2887
|
|
|
@@ -3999,6 +4015,7 @@ window.addEventListener('keydown', (e) => {
|
|
|
3999
4015
|
// backdrop listener covers in-dialog focus; this covers everything else).
|
|
4000
4016
|
if (state.files.dialog) { if (!state.files.dialog.busy) closeFileDialog(); return; }
|
|
4001
4017
|
if (state.chat.confirmingEdit) { state.chat.confirmingEdit = null; render(); announce('edit cancelled'); return; }
|
|
4018
|
+
if (state.confirmingClearData) { state.confirmingClearData = false; render(); announce('clear cancelled'); return; }
|
|
4002
4019
|
if (state.confirmingNewChat) { clearTimeout(_newChatArmTimer); state.confirmingNewChat = false; render(); announce('new chat cancelled'); return; }
|
|
4003
4020
|
if (state.live.confirmingStopAll || state.live.confirmingStopSelected) {
|
|
4004
4021
|
state.live.confirmingStopAll = false; state.live.confirmingStopSelected = false;
|
package/site/app/js/backend.js
CHANGED
|
@@ -351,10 +351,16 @@ function ensureWs(base) {
|
|
|
351
351
|
return _wsReady;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
function wsCall(base, method, params) {
|
|
354
|
+
function wsCall(base, method, params, timeoutMs = 15000) {
|
|
355
355
|
return ensureWs(base).then(() => new Promise((resolve, reject) => {
|
|
356
356
|
const r = _nextReqId++;
|
|
357
|
-
|
|
357
|
+
const timer = setTimeout(() => {
|
|
358
|
+
if (_pending.delete(r)) reject(new Error(method + ' timed out'));
|
|
359
|
+
}, timeoutMs);
|
|
360
|
+
_pending.set(r, {
|
|
361
|
+
resolve: (v) => { clearTimeout(timer); resolve(v); },
|
|
362
|
+
reject: (e) => { clearTimeout(timer); reject(e); },
|
|
363
|
+
});
|
|
358
364
|
_ws.send(encode({ m: method, r, p: params || {} }));
|
|
359
365
|
}));
|
|
360
366
|
}
|
|
@@ -2205,10 +2205,12 @@
|
|
|
2205
2205
|
.ds-247420 .ds-file-row[data-file-type="archive"] .ds-file-icon { color: var(--flame); }
|
|
2206
2206
|
.ds-247420 .ds-file-row[data-file-type="document"] .ds-file-icon { color: var(--amber, var(--sun)); }
|
|
2207
2207
|
|
|
2208
|
-
/* Row actions —
|
|
2208
|
+
/* Row actions — a faint baseline keeps them discoverable at rest (not fully
|
|
2209
|
+
hidden, which left mouse/trackpad users unable to find rename/move/delete
|
|
2210
|
+
without accidentally hovering a row), full opacity on hover/focus. */
|
|
2209
2211
|
.ds-247420 .ds-file-actions {
|
|
2210
2212
|
display: inline-flex; gap: 2px; align-items: center;
|
|
2211
|
-
opacity: 0; transition: opacity var(--dur-base) var(--ease);
|
|
2213
|
+
opacity: 0.35; transition: opacity var(--dur-base) var(--ease);
|
|
2212
2214
|
}
|
|
2213
2215
|
.ds-247420 .ds-file-row:hover .ds-file-actions,
|
|
2214
2216
|
.ds-247420 .ds-file-row:focus-within .ds-file-actions { opacity: 1; }
|
|
@@ -7668,14 +7670,13 @@
|
|
|
7668
7670
|
windowed thread, dashboard stopping/external states, cwd validation.
|
|
7669
7671
|
============================================================================ */
|
|
7670
7672
|
|
|
7671
|
-
/* Enter-to-send hint: visible
|
|
7672
|
-
|
|
7673
|
+
/* Enter-to-send hint: visible at rest so a new user with an empty composer
|
|
7674
|
+
can discover Enter-vs-Shift+Enter without having to focus it first;
|
|
7675
|
+
hidden under 420px to save rows. */
|
|
7673
7676
|
.ds-247420 .chat-composer-hint {
|
|
7674
|
-
display:
|
|
7677
|
+
display: block; width: 100%; order: 5; padding: 2px var(--space-1) 0;
|
|
7675
7678
|
font-size: var(--fs-micro); color: var(--fg-3);
|
|
7676
7679
|
}
|
|
7677
|
-
.ds-247420 .chat-composer:focus-within .chat-composer-hint,
|
|
7678
|
-
.ds-247420 .chat-composer.has-draft .chat-composer-hint { display: block; }
|
|
7679
7680
|
@media (max-width: 420px) {
|
|
7680
7681
|
.ds-247420 .chat-composer .chat-composer-hint { display: none; }
|
|
7681
7682
|
}
|