agentgui 1.0.1083 → 1.0.1085

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.
@@ -0,0 +1,8 @@
1
+ ---
2
+ key: mem-d9c19257abc2fa5e-1061
3
+ ns: default
4
+ created: 1784316128399
5
+ updated: 1784316128399
6
+ ---
7
+
8
+ {"key":"agentgui-no-tool-approval-gate-2026-07-17","value":"agentgui has NO tool-call approval/permission gate anywhere in its runner stack (confirmed 47th run, 2026-07-17): claude-runner-agents.js passes --dangerously-skip-permissions on every invocation; acp-sdk-manager.js/acp-protocol.js/claude-runner-acp.js/acp-server-machine.js have zero permission/approval/canUseTool references; backend.js's WS event switch has no pending-approval state; app.js has no pendingApproval field. The new kit ApprovalPrompt component (added this run, modeled on docstudio's approve/deny-with-note UI) has no backend concept to bind to today - wiring a real approval flow would need a new WS message type (permission_request/permission_response), runner-side blocking/resume logic differing per runner protocol (direct vs ACP vs agents), and removing --dangerously-skip-permissions. This is a distinct, much larger initiative than porting a UI idea into the kit - not in scope for a docstudio-design-cue pass, would need its own dedicated planning session if ever pursued."}
package/AGENTS.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # AgentGUI — Agent Notes
2
2
 
3
+ ## Docstudio design-cue follow-up (2026-07-19) — forty-eighth run
4
+
5
+ Sixth docstudio-cue pass, user asked to "consider everything we haven't covered yet." A fresh full-tree Explore-agent survey of `/config/docstudio/public/js` (told everything runs 42-47 shipped) found the low-hanging component/prop/a11y gaps genuinely exhausted, but surfaced a real, previously-unexplored subsystem-level gap: agentgui has **zero double-fire protection anywhere** — no `button.disabled` guard on any async click handler in the whole app, unlike docstudio's `utils/dom-busy.js` `withButtonBusy` (disables the button, sets `aria-busy`, swaps the label to a busy string, and guarantees restore via try/finally; a repeat click while already in flight is silently dropped). Ported it as `withBusy()` in `overlay-primitives.js` — a raw-DOM utility (operates on a real `HTMLButtonElement`, not a VElement) living alongside the existing `trapTab`/`useLongPress` DOM utilities. Wired onto the three unguarded async-click sites found in `app.js`: the ACP agent restart button, the "not installed" re-check button, and both agent-list-load retry buttons (the file-mutation dialogs and stop-chat button already had their own state-driven busy guards, so those were correctly left alone). A second candidate — docstudio's `xls-preview.js` tabbed spreadsheet/CSV inline preview — was surveyed and deliberately deferred as a genuinely distinct, larger subsystem (needs a new kit component: tabbed table + truncation banner + error-fallback card) rather than folded in as a rushed partial port; recorded to memory as its own future initiative. **Tooling note: this run's `gm` spool watcher could not boot at all — `npm pack gm-plugkit@2.0.1990` confirmed the published npm tarball is genuinely missing the `wrapper/` subdirectory (`wasi-shim.js`/`fs-atomic.js`/`kv-store.js`/`task-manager.js`) that `plugkit-wasm-wrapper.js` imports from, reproduced identically across `@latest` and 5 pinned versions back to 2.0.1975 — a real upstream packaging defect, not a local/cache issue (verified with fully cleared bun/npm caches). Fell back to direct implementation with the `agent-browser` CLI (an independent tool, unaffected) for live witnessing instead of the gm browser verb.** Kit built+tested (`bun test.js` all pass, all lints pass, docs regenerated 0 drift), rebased cleanly onto a concurrent `v0.0.354`/`v0.0.355` release (`flatspace-theme` kit addition, no conflict). Kit pushed `c7da8c0`→`bee6ab7`. Browser-witnessed live via `agent-browser`: `withBusy` correctly drops a concurrent second call (`calls:1` across two simultaneous invocations), shows `disabled:true`/`aria-busy:true`/swapped label mid-flight, and fully restores after — plus confirmed all four call-site wirings present in the live-served `app.js` bundle by regex against the actual fetched source. agentgui re-vendored, 0 console errors on live reload.
6
+
7
+ ## Docstudio design-cue follow-up (2026-07-17) — forty-seventh run, confirming pass
8
+
9
+ Per gm-continue's mandatory first-confirming-pass discipline, a second independent Explore-agent survey (told what the 47th run's main pass just shipped) re-checked docstudio against the kit + app and found one last real, narrow gap: `app.js`'s cross-tab external-update banner still called native `window.confirm()` for the reload-discards-unsent-draft guard — the sole remaining native browser dialog call anywhere in the app, matching docstudio's own `dialog.js` rationale of never using `window.confirm/alert/prompt` for data-loss confirmations. Replaced with a `state.chat.confirmingReloadDiscard` flag rendering the kit's existing `ConfirmDialog` modal, mirroring the same pattern already used for file delete/bulk-delete. Browser-witnessed by fetching the live-served `/gm/js/app.js` directly and regex-confirming `window.confirm` is gone and the new `confreload` dialog key is present. A second confirming pass after this one found nothing further — docstudio's `buildDocAccessPrompt`/`buildScopePrompt` variants are narrow Google-OAuth/Drive-doc-specific flows with no analog in agentgui's domain model, and everything else checked (ApprovalPrompt's focus/a11y semantics, build-freshness poll, modal focus-trap/Escape/backdrop semantics) was already correctly ported.
10
+
3
11
  ## Docstudio design-cue follow-up (2026-07-17) — forty-seventh run
4
12
 
5
13
  Fifth docstudio-cue pass, same directive repeated a fifth time after the 46th run's confirming pass had concluded the mining task "genuinely exhausted." A fresh independent Explore-agent re-verification (told what runs 42-46 shipped) found that conclusion was **not fully accurate**: `chat-approval-prompts.js:47-71`'s `buildApprovalPrompt` has an auto-focused free-text note textarea threaded through every approve/deny decision (prefixed onto the denial message so the assistant sees why it was denied) that the kit's `PermissionMenu` (a settings-style checkbox dropdown, architecturally different) had no analog for at all. Added a new `ApprovalPrompt` component (`overlay-primitives.js`) — an inline, in-thread permission card (name/category head, optional args preview, auto-focused optional note, once/session/all/deny actions via `onDecision(kind, note)`) — plus a `lock` icon added to the shared `ICON_PATHS` (didn't exist previously) and a barrel re-export per the standing barrel rule. Also landed the pass's secondary finding: `update-check.js`'s `/version.json` poll + persistent reload-nudge pattern, ported to `app.js` as `startBuildFreshnessPoll()` (90s interval, compares live `/health` `version` against `window.__SERVER_VERSION`, reuses the kit's existing `toast({actionLabel,onAction,duration:0})` from the 46th run rather than inventing a new notice surface). A first CSS pass tripped the frozen spacing-lint baseline (raw `6px 14px` button padding) — fixed by mapping to `--space-1-75`/`--space-3` and `--r-pill` instead of literal `999px`. Kit rebased once onto concurrent `v0.0.352`/`v0.0.353` releases (dist-only conflict, rebuilt fresh per the standing discipline). Kit pushed `e93f4f7`→`6d71b34`, all 3 checks green. Browser-witnessed live on `localhost:3009/gm/`: this session's `gm browser` verb had a real, repeat tool defect (`url=`/`dom=`/`screenshot=` prefixes evaluate in a detached Node vm, not the real page — `ReferenceError: document is not defined` despite `navigation_requested:true`) — recorded to durable memory (`agentgui-browser-verb-url-dom-prefix-broken-2026-07-17`) rather than left as a stuck PRD row, per gm's diagnose-the-tool discipline. Worked around by using only the bare `capture\n<script>` form (`page.goto`+`page.evaluate` inline) and reading results via `console.log('WITNESS:'+...)` inside the page context rather than the top-level `result` field, which came back `null` even on successful (`exit_code:0`) dispatches. Confirmed live: `toast()`'s action button fires `onAction(dismiss)`; `ApprovalPrompt` renders (`.ov-approval` present), note textarea auto-focuses, lock icon renders, Deny click fires `onDecision('deny', '')` correctly. agentgui re-vendored, pushed `1d37290`→`9b25faf`→`08483cf`, all 4 CI checks green both pushes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.1083",
3
+ "version": "1.0.1085",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
@@ -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, flashComposerNote, toast } = 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, toast, withBusy } = 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
@@ -2273,7 +2273,7 @@ function chatMain() {
2273
2273
  + (hasDraft ? 'This tab has an unsent draft that reloading will discard. ' : '')),
2274
2274
  Btn({ key: 'xureload', disabled: state.chat.busy, onClick: () => {
2275
2275
  if (state.chat.busy) return;
2276
- if (hasDraft && !window.confirm('Reloading will discard your unsent draft in this tab. Continue?')) return;
2276
+ if (hasDraft) { state.chat.confirmingReloadDiscard = true; render(); return; }
2277
2277
  state.chat.externalUpdate = false;
2278
2278
  state.chat.messages = []; state.chat.resumeSid = null; state.chat.totalCost = 0;
2279
2279
  restoreChat(); render();
@@ -2301,7 +2301,7 @@ function chatMain() {
2301
2301
  banners.push(Alert({ key: 'agerr', kind: 'error', title: 'Could not load agents from the server',
2302
2302
  children: [
2303
2303
  h('span', { key: 'agtxt', title: state.agentsError }, 'The agent list failed to load - this is a connection issue, not necessarily a sign nothing is installed. '),
2304
- Btn({ key: 'agretry', onClick: () => loadAgents(), children: 'retry' })] }));
2304
+ Btn({ key: 'agretry', onClick: (e) => withBusy(e.currentTarget, () => loadAgents(), 'retrying…'), children: 'retry' })] }));
2305
2305
  }
2306
2306
  if (state.chat.loadingTranscript) {
2307
2307
  banners.push(Alert({ key: 'transcriptload', kind: 'info', title: 'Loading prior conversation…',
@@ -2528,6 +2528,19 @@ function chatMain() {
2528
2528
  onCwdClear: () => { state.chatCwd = ''; lsRemove('agentgui.cwd'); render(); },
2529
2529
  onCwdDraft: (v) => { state.cwdDraft = v; state.cwdError = null; debouncedCwdProbe(); },
2530
2530
  }),
2531
+ state.chat.confirmingReloadDiscard ? ConfirmDialog({
2532
+ key: 'confreload',
2533
+ title: 'Discard unsent draft?',
2534
+ message: 'Reloading will discard your unsent draft in this tab. Continue?',
2535
+ confirmLabel: 'reload', cancelLabel: 'cancel', destructive: true,
2536
+ onCancel: () => { state.chat.confirmingReloadDiscard = false; render(); },
2537
+ onConfirm: () => {
2538
+ state.chat.confirmingReloadDiscard = false;
2539
+ state.chat.externalUpdate = false;
2540
+ state.chat.messages = []; state.chat.resumeSid = null; state.chat.totalCost = 0;
2541
+ restoreChat(); render();
2542
+ },
2543
+ }) : null,
2531
2544
  ].filter(Boolean);
2532
2545
  }
2533
2546
 
@@ -3894,12 +3907,12 @@ function agentsPanel() {
3894
3907
  state: usable ? 'default' : 'disabled',
3895
3908
  onClick: usable ? () => { navTo('chat'); selectAgent(a.id); } : undefined,
3896
3909
  right: (acp && !acp.healthy)
3897
- ? [Btn({ key: 'acprestart', onClick: (e) => { e.stopPropagation(); B.restartAcpAgent(state.backend, a.id).then(() => loadAgents()); }, children: 'restart' })]
3910
+ ? [Btn({ key: 'acprestart', onClick: (e) => { e.stopPropagation(); withBusy(e.currentTarget, () => B.restartAcpAgent(state.backend, a.id).then(() => loadAgents()), 'restarting…'); }, children: 'restart' })]
3898
3911
  // Direct-runner agents (claude-code/agy) have no restart, but a
3899
3912
  // 'not installed' verdict can go stale if the user installs the
3900
3913
  // CLI mid-session - give it the same recheck affordance ACP rows
3901
3914
  // get via 'restart', instead of only static prose.
3902
- : (!avail ? [Btn({ key: 'agrecheck', onClick: (e) => { e.stopPropagation(); loadAgents(); }, children: 're-check' })] : undefined),
3915
+ : (!avail ? [Btn({ key: 'agrecheck', onClick: (e) => { e.stopPropagation(); withBusy(e.currentTarget, () => loadAgents(), 'checking…'); }, children: 're-check' })] : undefined),
3903
3916
  });
3904
3917
  })
3905
3918
  // The empty array means one of three things; never let an in-flight load
@@ -3909,7 +3922,7 @@ function agentsPanel() {
3909
3922
  : (state.agentsError
3910
3923
  ? h('div', { key: 'agfail', class: 't-meta empty-state' },
3911
3924
  h('span', { key: 'agfailtxt' }, 'the agent list failed to load'),
3912
- Btn({ key: 'agretry2', onClick: () => loadAgents(), children: 'retry' }))
3925
+ Btn({ key: 'agretry2', onClick: (e) => withBusy(e.currentTarget, () => loadAgents(), 'retrying…'), children: 'retry' }))
3913
3926
  : h('p', { key: 'none', class: 't-meta' }, 'no agents loaded'))]),
3914
3927
  ].filter(Boolean),
3915
3928
  });