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
SMB: auto-upgrade on dev profiles, plus MCP visibility and trigger
Three fixes that all touch the same flow: existing OS-mounted SMB shares can now reach the fast direct-smb2 path automatically (or via MCP for agents), and agents can see which volumes are on which path.
Auto-upgrade for dev profiles (#1): `upgrade_existing_smb_mounts` now takes an `AppHandle` and calls `crate::network::ensure_mdns_started` itself when it finds SMB mounts to upgrade. The `firstTriggerDone` gate is gone from this call site — the function is a no-op when there are no SMB mounts (no network activity, no macOS Local Network prompt), so the gate was protecting nothing useful. With mounts present and `network.directSmbConnection` on (default true), mDNS now starts at launch and the upgrade can resolve hostname-keyed Keychain creds the same way the manual "Connect directly" button does. Dev profiles with `firstTriggerDone == false` and an auto-reconnected SMB share previously stayed on the slow OS-mount path indefinitely; that's the bug.
MCP visibility (#3): `cmdr://state`'s volumes section now emits structured entries for SMB volumes with `name`, `id`, and `smbConnectionState` (`direct` | `os_mount` | `disconnected`). Non-SMB volumes stay as bare `- {name}` lines for compactness. Agents can now distinguish which SMB shares are on the fast path.
MCP trigger (#2): new `upgrade_smb_to_direct` tool, sibling of `connect_to_server` and `remove_manual_server` in the network category. Thin wrapper around the same upgrade flow the manual UI uses. Calls a newly-extracted `upgrade_to_smb_volume_inner` helper (the Tauri command's body minus the concrete-AppHandle mDNS kick) so the MCP executor — generic over `Runtime` — can reuse the logic. Tool description steers agents: if mDNS isn't running and hostname-keyed Keychain creds matter, take a network action first.
Refactor along the way: `enrich_smb_connection_state` was duplicated across `commands/volumes.rs` (for `list_volumes`) and `volume_broadcast.rs` (for `volumes-changed`) with a "must stay in sync" gotcha. With MCP becoming a third caller, the sync risk grew. Extracted to `volumes::enrich_smb_connection_state`; all three call sites now share it. CLAUDE.md gotcha → decision.
Tests / docs:
- MCP `test_all_tools_count` / `test_network_tools_count` bumped (29 → 30, 2 → 3).
- MCP `test_total_tool_count` bumped to 30.
- file_system/volume/CLAUDE.md startup-upgrade lifecycle entry updated to reflect the new mDNS-kick path and no-gate semantics.
- mcp/CLAUDE.md tool count, network category list, and `cmdr://state` volumes-shape description updated.
- volumes/CLAUDE.md "two-site sync" gotcha replaced with a single-source decision entry.
Verified: full `./scripts/check.sh` green (50 checks, 1983 unit + 32 integration + every linter), including the 189 MCP unit tests.
- File operations (6): `copy`, `move`, `delete`, `mkdir`, `mkfile`, `refresh`. `copy`/`move` accept optional `autoConfirm` (bool) and `onConflict` (`skip_all`|`overwrite_all`|`rename_all`). `delete` accepts optional `autoConfirm`. When `autoConfirm` is true, the dialog opens and immediately confirms.
@@ -31,12 +31,12 @@ Expose Cmdr functionality to AI agents via the Model Context Protocol (MCP). Age
31
31
- App (3): `switch_pane`, `swap_panes`, `quit`
32
32
- Search (2): `search` (structured file search across the drive index, optional `scope` for path/exclude filtering), `ai_search` (natural language search using configured LLM, optional `scope` merged with AI-inferred scope)
33
33
- Settings (1): `set_setting` (change a setting value via round-trip to frontend)
34
-
- Network (2): `connect_to_server` (add a manual SMB server by address, checks TCP reachability), `remove_manual_server` (remove a manually-added server by host ID)
34
+
- Network (3): `connect_to_server` (add a manual SMB server by address, checks TCP reachability), `remove_manual_server` (remove a manually-added server by host ID), `upgrade_smb_to_direct` (upgrade an OS-mounted SMB volume to a direct smb2 session for faster I/O; thin wrapper over the existing manual "Connect directly" Tauri command — tries Keychain creds, returns a typed result mirroring `UpgradeResult`)
35
35
- Async (1): `await` (poll PaneStateStore until a condition is met: `has_item`, `item_count_gte`, `path`, or `path_contains`. Supports `after_generation` to avoid matching stale state)
36
36
37
37
### Resources (`resources.rs`)
38
38
39
-
-`cmdr://state`: Complete app state in YAML (both panes, volumes, dialogs, active `listings` cache, `recentErrors`). Includes MTP volumes with `name` and `id`, and per-pane `volumeId`. The `listings` section reflects every entry in `LISTING_CACHE` (id, volumeId, path, entry count, ageMs); `recentErrors` is the last 20 directory-listing failures with `atUnixMs`, `listingId`, `volumeId`, `path`, `message` (see `listing_errors.rs` and the freshness contract below). Supports `?include=panes,volumes,dialogs,listings,recentErrors` projection (defaults to all) and `?compact=true` (drops the `files:` list inside each pane while keeping every summary field). Example: `cmdr://state?include=listings,recentErrors` is the minimal payload for "did the last listing succeed?".
39
+
-`cmdr://state`: Complete app state in YAML (both panes, volumes, dialogs, active `listings` cache, `recentErrors`). Includes MTP volumes with `name` and `id`, and per-pane `volumeId`. SMB volumes appear as structured entries with `name`, `id`, and `smbConnectionState` (`direct` | `os_mount` | `disconnected`) so agents can route the `upgrade_smb_to_direct` tool at the right volumes; non-SMB volumes stay as bare `- {name}` lines. The `listings` section reflects every entry in `LISTING_CACHE` (id, volumeId, path, entry count, ageMs); `recentErrors` is the last 20 directory-listing failures with `atUnixMs`, `listingId`, `volumeId`, `path`, `message` (see `listing_errors.rs` and the freshness contract below). Supports `?include=panes,volumes,dialogs,listings,recentErrors` projection (defaults to all) and `?compact=true` (drops the `files:` list inside each pane while keeping every summary field). Example: `cmdr://state?include=listings,recentErrors` is the minimal payload for "did the last listing succeed?".
40
40
-`cmdr://dialogs/available`: Static metadata about available dialogs
41
41
-`cmdr://indexing`: Drive indexing status in plain text (current phase, timeline history, DB stats). Calls `indexing::get_debug_status()` and formats as human-readable text.
42
42
-`cmdr://settings`: All settings with current values, defaults, types, and constraints. Fetched via round-trip to the frontend (`mcp-get-all-settings` event).
@@ -50,7 +50,7 @@ Directory module split by tool category. `mod.rs` contains the main `execute_too
50
50
-`nav.rs`: navigation commands (with and without params)
-`search.rs`: search index loading, search, ai_search
55
55
56
56
**Action-tool ack contract.** Every fire-and-forget action tool now waits for a backend ack signal before returning `OK`. Previously the tool returned `OK` the instant the event was dispatched; if the FE was stalled (modal blocking input, error pane up, race during startup), the action was silently dropped and MCP reported success anyway. The ack contract makes `OK` a meaningful promise: the FE has actually processed the dispatched action.
0 commit comments