+
+ macOS Diagnostics
+
+
+ {/* System Info */}
+ {systemInfo && (
+
+
System
+
+
macOS {systemInfo.os_version}
+
Arch {systemInfo.arch}
+
Model {systemInfo.model || "N/A"}
+
WiFi {systemInfo.wifi_interface || "N/A"} ({systemInfo.wifi_power ? "On" : "Off"})
+ {systemInfo.serial_drivers.length > 0 && (
+
+ Serial Drivers{" "}
+
+ {systemInfo.serial_drivers.join(", ")}
+
+
+ )}
+
+
+ )}
+
+ {/* Permissions */}
+ {permissions && (
+
+
Permissions
+
+ {[
+ { label: "Network", ok: permissions.network_access },
+ { label: "USB Serial", ok: permissions.usb_access },
+ { label: "WiFi Scan", ok: permissions.wifi_scan },
+ { label: "Location", ok: permissions.location_services },
+ ].map((p) => (
+
+ {p.ok ? "\u2713" : "\u2717"} {p.label}
+
+ ))}
+
+
+ )}
+
+ {/* Current WiFi */}
+ {wifiInfo && (
+
+
Current WiFi Connection
+
+
SSID {wifiInfo.ssid || "N/A"}
+
Channel {wifiInfo.channel || "N/A"}
+
RSSI {wifiInfo.rssi || "N/A"} dBm
+
BSSID {wifiInfo.bssid || "N/A"}
+
Noise {wifiInfo.noise || "N/A"} dBm
+
Tx Rate {wifiInfo.tx_rate || "N/A"} Mbps
+
Security {wifiInfo.security || "N/A"}
+
PHY {wifiInfo.phy_mode || "N/A"}
+
+
+ )}
+
+ {/* WiFi Scan */}
+
+
+
WiFi Site Survey
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {scanResults.length > 0 && (
+
+
+
+ {["SSID", "BSSID", "Ch", "RSSI", "Security"].map((h) => (
+ | {h} |
+ ))}
+
+
+
+ {scanResults.map((r, i) => (
+
+ | {r.ssid || "(hidden)"} |
+ {r.bssid} |
+ {r.channel} |
+ {r.rssi} dBm |
+ {r.security} |
+
+ ))}
+
+
+ )}
+
+ {scanResults.length === 0 && !scanning && (
+
+ Click "Scan Networks" to discover nearby WiFi access points. Useful for positioning ESP32 nodes.
+
+ )}
+
+
+ );
+};
diff --git a/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/types.ts b/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/types.ts
index d9b2e2937..6340443d7 100644
--- a/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/types.ts
+++ b/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/types.ts
@@ -229,3 +229,42 @@ export interface AppSettings {
discover_interval_ms: number;
theme: "dark" | "light";
}
+
+// ---------------------------------------------------------------------------
+// macOS Diagnostics (only available on macOS)
+// ---------------------------------------------------------------------------
+
+export interface MacWifiInfo {
+ ssid: string | null;
+ bssid: string | null;
+ channel: number | null;
+ rssi: number | null;
+ noise: number | null;
+ tx_rate: number | null;
+ security: string | null;
+ phy_mode: string | null;
+}
+
+export interface MacWifiScanResult {
+ ssid: string;
+ bssid: string;
+ rssi: number;
+ channel: number;
+ security: string;
+}
+
+export interface MacSystemInfo {
+ os_version: string;
+ arch: string;
+ model: string | null;
+ wifi_interface: string | null;
+ wifi_power: boolean;
+ serial_drivers: string[];
+}
+
+export interface MacPermissions {
+ network_access: boolean;
+ usb_access: boolean;
+ wifi_scan: boolean;
+ location_services: boolean;
+}
diff --git a/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/version.ts b/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/version.ts
index c09cc912a..3b4a12241 100644
--- a/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/version.ts
+++ b/rust-port/wifi-densepose-rs/crates/wifi-densepose-desktop/ui/src/version.ts
@@ -1,2 +1,2 @@
// Application version - single source of truth
-export const APP_VERSION = "0.4.4";
+export const APP_VERSION = "0.4.5";
diff --git a/scripts/install-macos.sh b/scripts/install-macos.sh
new file mode 100755
index 000000000..b89db4f55
--- /dev/null
+++ b/scripts/install-macos.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+# RuView Desktop macOS installer
+# Usage: curl -fsSL https://raw.githubusercontent.com/ruvnet/RuView/main/scripts/install-macos.sh | bash
+
+set -euo pipefail
+
+VERSION="${RUVIEW_VERSION:-0.4.5}"
+REPO="ruvnet/RuView"
+
+# Detect architecture
+ARCH=$(uname -m)
+case "$ARCH" in
+ arm64|aarch64) ARCH_LABEL="arm64" ;;
+ x86_64) ARCH_LABEL="x64" ;;
+ *) echo "Unsupported architecture: $ARCH"; exit 1 ;;
+esac
+
+DMG_NAME="RuView-Desktop-${VERSION}-macos-${ARCH_LABEL}.dmg"
+ZIP_NAME="RuView-Desktop-${VERSION}-macos-${ARCH_LABEL}.zip"
+DOWNLOAD_URL="https://github.com/${REPO}/releases/download/desktop-v${VERSION}"
+
+echo "RuView Desktop Installer"
+echo "========================"
+echo "Version: ${VERSION}"
+echo "Arch: ${ARCH_LABEL}"
+echo ""
+
+# Try DMG first, fall back to ZIP
+TMPDIR=$(mktemp -d)
+trap "rm -rf $TMPDIR" EXIT
+
+echo "Downloading..."
+if curl -fsSL -o "${TMPDIR}/${DMG_NAME}" "${DOWNLOAD_URL}/${DMG_NAME}" 2>/dev/null; then
+ echo "Installing from DMG..."
+ MOUNT_POINT=$(hdiutil attach "${TMPDIR}/${DMG_NAME}" -nobrowse -noautoopen | tail -1 | awk '{print $NF}')
+
+ # Remove old version
+ if [ -d "/Applications/RuView Desktop.app" ]; then
+ echo "Removing previous installation..."
+ rm -rf "/Applications/RuView Desktop.app"
+ fi
+
+ cp -r "${MOUNT_POINT}/RuView Desktop.app" /Applications/
+ hdiutil detach "$MOUNT_POINT" -quiet
+
+elif curl -fsSL -o "${TMPDIR}/${ZIP_NAME}" "${DOWNLOAD_URL}/${ZIP_NAME}" 2>/dev/null; then
+ echo "Installing from ZIP..."
+ cd "$TMPDIR"
+ unzip -q "$ZIP_NAME"
+
+ if [ -d "/Applications/RuView Desktop.app" ]; then
+ echo "Removing previous installation..."
+ rm -rf "/Applications/RuView Desktop.app"
+ fi
+
+ cp -r "RuView Desktop.app" /Applications/
+
+else
+ echo "Failed to download RuView Desktop v${VERSION}"
+ echo "Check https://github.com/${REPO}/releases for available versions"
+ exit 1
+fi
+
+# Clear Gatekeeper quarantine attribute
+xattr -cr "/Applications/RuView Desktop.app" 2>/dev/null || true
+
+echo ""
+echo "RuView Desktop v${VERSION} installed to /Applications"
+echo ""
+echo "To launch: open '/Applications/RuView Desktop.app'"
+echo ""
+echo "ESP32 serial drivers:"
+echo " CP210x: https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers"
+echo " CH340: https://github.com/WCHSoftGroup/ch34xser_macos"
+echo " FTDI: https://ftdichip.com/drivers/vcp-drivers/"