You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MCP: ack dialog-close on mcp-dialog-closed, not pane gen
Real-MCP testing of the ack contract caught two false negatives the
unit + Playwright coverage missed:
- `dialog close <confirmation>` (mkdir / mkfile / transfer / delete):
the close path waited on `GenerationAdvanced`, but cancelling a
confirmation dialog doesn't touch pane state, so the bump never
arrives. Every cancel returned `ActionNotAcknowledged` even though
the dialog actually closed.
- `dialog close settings`: the Rust side emitted `mcp-settings-close`
to the settings webview but `routes/settings/+page.svelte` had no
listener. Tool returned `ActionNotAcknowledged` AND the window
stayed open — straight-up broken, not a false negative.
Add a new `AckSignal::SoftDialogDisappeared(id)` that waits for the
`SoftDialogTracker` membership to drop (the `notifyDialogClosed` IPC
from `ModalDialog.svelte` is the trustworthy signal). Wire the
soft-dialog-close path in `dialogs.rs` to it. Add the missing
`mcp-settings-close` listener with the same two-rAF defer as the
production Escape handler, so the close behaves consistently regardless
of trigger.
Verified end-to-end via the real MCP transport: settings open/close
in ~150 ms; mkdir/mkfile/transfer/delete confirmation cancels in
~130–170 ms; all 176 MCP unit tests + clippy + rustfmt + oxfmt +
svelte-check green.
|`GenerationAdvanced`|`PaneStateStore.generation` is strictly greater than the captured value | Anything that mutates pane state (`select`, `set_view_mode`, `sort`, `toggle_hidden`, `tab`, `nav_*`, auto-confirmed `copy`/`move`/`delete`, `dialog confirm`). NOT `refresh` — see TODO note below. |
69
69
|`SoftDialogAppeared(id)`| A soft dialog with that ID is in `SoftDialogTracker`| Confirmation dialogs from `copy`/`move`/`delete` (autoConfirm: false), `mkdir`, `mkfile`; `dialog open about`|
70
+
|`SoftDialogDisappeared(id)`| A soft dialog with that ID is no longer in `SoftDialogTracker`|`dialog close <confirmation>` — the FE `ModalDialog` fires `notifyDialogClosed` on unmount, so the tracker reflects the close even when cancel doesn't bump pane generation |
70
71
|`WindowAppeared(label)`| A `webview_windows()` entry matches the label (exact, or `viewer-*`) | `dialog open settings|file-viewer`, `dialog focus` |
71
72
|`WindowDisappeared`| The matching `webview_windows()` entry is gone | `dialog close settings|file-viewer|about` |
72
73
|`Any([...])`| Logical OR — any inner signal fires |`open_under_cursor` (directory case bumps generation, file case opens a viewer window) |
73
74
74
-
The polling cadence is 250 ms for state-driven signals (matching the existing `await` tool) and 100 ms for window/dialog appearance signals (windows show up faster than full pane state pushes).
75
+
The polling cadence is 250 ms for state-driven signals (matching the existing `await` tool) and 100 ms for window/soft-dialog signals (both react faster than a full pane state push).
76
+
77
+
**Gotcha/Why**: `dialog close <settings>` requires the settings window to listen for the `mcp-settings-close` event and close itself (`apps/desktop/src/routes/settings/+page.svelte`). Without that listener the backend keeps polling for `WindowDisappeared("settings")` and times out at 1500 ms while the window stays put. Same shape applies if you add new window-based dialogs: the FE side has to opt in.
75
78
76
79
The 1500 ms budget is a backend-side latency budget, not a client-facing knob: MCP clients shouldn't have to tune ack timeouts. Bump it per-call via the `Duration` argument to `wait_for_ack` if a specific operation has a known higher latency floor; don't expose it as a tool parameter.
0 commit comments