Releases: Fasen24-AI/autofuse
Releases · Fasen24-AI/autofuse
v4.1
Added
- MCP tool behavior annotations — all 34 tools now carry
readOnlyHint/destructiveHint/idempotentHintannotations per the MCP spec, so clients can auto-approve the 18 read-only tools and reserve confirmation prompts for destructive ones. Known engine error codes return ahint:line pointing the agent at the next step (e.g.host_key_mismatch→ runlearn_host_key). - Agent-friendly CLI commands (
cli/autofuse, v4.1) —connect <ws>pings the workstation, sends Wake-on-LAN if it's off, then mounts all of its disks;json [status|health|list|disks <ws>]emits machine-readable JSON with stable shapes ([{workstation, disk, status, mount_point}],[{name, lan_ip, vpn_ip, disks[], mac}],[{letter, label, remote_path}]);raw <cmd> [...]gives direct access to everymount.shengine subcommand, including ones without a friendly wrapper. - Architecture conventions in
CONTRIBUTING.md— engine-as-source-of-truth, exit-code-as-signal, stable output strings, energy discipline. - Real app screenshots in the README (menu bar, Add Computer, Preferences) and per-client MCP configuration snippets (Cursor/Windsurf/Cline, Codex CLI, Gemini CLI, skill-based agents).
- MCP Server (
mcp-server/) — Model Context Protocol server for Claude Desktop, Claude Code, and other MCP clients. Now exposes 34 tools (6 intent-level composites likequick_connect/fix_it/locate+ granular mount/unmount/wake/scan/probe/health/panic recovery + unrestrictedrun_local_shell/run_remote_shellescape hatches). Installable with./install.sh. Zero shell injection risk viaexecFilearray args. Tool descriptions follow a consistent verb+when+returns+errors template so LLM callers select the right tool accurately. - Sparkle auto-update (optional, conditional) — when
brew install sparkleis present, AutoFuse bundles Sparkle.framework and adds a "Check for Updates…" menu item. All Sparkle code guarded by#if __has_include(<Sparkle/Sparkle.h>)so it compiles cleanly with or without Sparkle. Seedocs/SPARKLE-SETUP.mdandappcast.xml. - SMB protocol support —
discover.sh scan-networkandprobe-hostnow also check port 445; protocol auto-suggested in workstation config (protocol: "smb"+smb_share: "C$"). Complements SSHFS for Windows file shares. - Multi-endpoint machine identity (SSH host key) — three new commands:
learn-host-key <ws>captures the remote SHA256 fingerprint,verify-host-key <ws>checks it against every endpoint, andpick-endpoint <ws>prints the best reachable endpoint (host-key-verified when a fingerprint is stored). Config schema adds optionaladditional_ips[]andhost_key_sha256fields; mDNS<name>.localis automatically tried as a final fallback. Lets AutoFuse reconnect to the same machine across different networks (Studio WiFi, home WiFi, VPN, Tailscale) even when IPs change. When a fingerprint is stored,_do_mountnow uses it transparently to pick a verified endpoint and refuses to mount if no endpoint's current key matches — protects against silent connections to a rotated or impostor host. First successful mount of a new workstation auto-captures the fingerprint (TOFU), so users get multi-endpoint identity + rotation protection without running any extra command. The Add/Edit Workstation dialog now exposes a multi-line "Additional IPs" field (Tailscale, mDNS, extra routes) and a read-only "Host Key" display with a "Re-learn" button for post-reinstall recovery — no more config.json hand-editing. - Smart endpoint memory —
_pick_endpointnow caches the last-working endpoint per workstation at~/.config/autofuse/.endpoint-cache/<ws>(TTL 1 hour). On repeated mounts from the same network, the cached endpoint is tried first, skipping up to 4 × 2s_reachableprobes plus ssh-keyscan overhead on wrong endpoints. Falls back to full iteration on cache miss / staleness / unreachable-cached / key-mismatch. New CLI:endpoint-cache-show [ws]andendpoint-cache-clear [ws]. - Endpoint-switch notifications — when
_pick_endpointfalls through to a different endpoint than the one cached (e.g. LAN → Tailscale because you left the office), it drops an event file at~/.config/autofuse/.events/switch-<ts>that the menu-bar app consumes and posts a nativeUNUserNotification: "ml-workstation reconnected — Switched to 192.168.1.100 via en0 (was 172.16.0.100)". The new-endpoint interface is resolved via/sbin/routeso the user immediately sees the network-context change, not just a bare IP. Drain runs on a background queue with 2s route-lookup timeout — no UI stalls during network flaps. - Auto-exclude from Spotlight / Time Machine — every successful mount now calls
mdutil -i off+tmutil addexclusionon the mount point. Idempotent and silent; wired into all four mount success paths (LAN / VPN / WoL-LAN / WoL-VPN). Resolves two prior UX pitfalls that were documented as manual fixes. panic-unmount-allandpanic-checkcommands in mount.sh for aggressive stale-mount recovery on network loss- Network loss detection in main.m: pings workstations on network change; if none reachable, triggers panic-unmount to prevent Finder/app hangs
- Faster stale detection:
_alive()uses 2s hard timeout (was 3s) - GitHub publication assets:
.gitignore,CONTRIBUTING.md,SECURITY.md,.github/workflows/(CI + release), issue templates
Fixed
health-jsoncommand now emits valid JSON array even when no mounts active- Primary disk flag now preserved correctly when editing a workstation via the dialog
probe-hostdisk output: size (e.g.(421.8/464.8)) now appended to label, not corrupted intoremote_path- User config (
~/.config/autofuse/config.json) now takes priority over bundle config — fixes lost workstations after app updates - MCP server parsers rewritten (14 tools) to use pipe-delimited format matching mount.sh output instead of JSON.parse
_ssh_okand_ensure_key_unlockedtimeouts (alarm 8 + ConnectTimeout=5) were too tight for ~1s RTT links (Tailscale overseas, WifiMan distant sites, satellite). Raised toalarm 25 + ConnectTimeout=15— covers ~4-8 RTT of SSH handshake at 1s/RTT while still failing fast (25s) on truly dead hosts.ssh_options.connect_timeoutconfig key was silently ignored by the sshfs launcher. Now applied as-o ConnectTimeout={value, default 30}so users on high-latency VPNs can tune the initial mount window without patching code.build.sh: Info.plist is now generated BEFORE the MCP bundle step, andnpm installfor the MCP server has a 60s hard timeout viaperl alarm. Previously a stalled npm (slow Wi-Fi) could abort the script before reaching Info.plist creation, leaving the bundle without a CFBundleIdentifier — the app would then fail to launch with "UNUserNotificationCenter could not determine bundleIdentifier".discover.sh probe-hostnow early-exits witherror:probe_failed:host_unreachablewhen both port 22 and port 445 are closed, cutting unreachable-host probe time from 14s (2× SSH ConnectTimeout=5s + 2× fallback) to ~4s (2× nc timeout 2s).discover.sh scan-networknow filters multicast (224.0.0.0/4), broadcast (255.255.255.255), and their MAC equivalents (ff:ff:ff:ff:ff:ff,01:00:5e:*) from ARP cache results — previously produced rows like224.0.0.251|mdns.mcast.net|1:0:5e:0:0:fbthat confused LLM callers.discover.sh detect-vpnnow detects Unifi WifiMan SD-WAN by process match (pgrep -if wifiman) — the bundled WireGuard is not visible to thewgCLI, so utun interfaces were previously labeled genericvpninstead ofwifiman.status-allcommand parallelized via process substitution (< <(_json_raw list_workstations)) instead of a pipe — pipes run thewhileloop in a subshell that loses track of backgrounded forks, breakingwaitsemantics.
Changed
- License changed from MIT to PolyForm Shield 1.0.0 to allow commercial use while preventing competing forks
- README badges updated to reflect new license
- Menu bar opens immediately from cached state, with async refresh in background — previously blocked 2-6s on slow networks during
status-all. - Status log is state-transition-only (per-disk cache at
~/.config/autofuse/.status-cache/<ws>__<letter>) — eliminates polling flood inautofuse.log. - Idle-energy discipline: mount state is polled natively via
getmntinfo()(no per-poll subprocesses), poll/heal timers stretch on an adaptive cadence when nothing is changing, and the engine defaults SSH keepalive toServerAliveInterval=30.
Security
- Untrusted input (remote-host output, user config values) never reaches an interpreter as source — values are passed via
argv(python3 -c '…' "$value"), not string-interpolated into code. - Stale-mount recovery kills sshfs by verified per-PID match against the exact mount point, instead of a broad
pkill -f "sshfs.*<pattern>"that could hit unrelated processes. - All
NSWindowinstances usereleasedWhenClosed = NO, fixing a use-after-free when dialogs are reopened.