From cb932fe914e7dd96e750d5ad4a963d67ee23148c Mon Sep 17 00:00:00 2001 From: Paul Frederiksen Date: Tue, 7 Oct 2025 16:24:07 -0700 Subject: [PATCH 1/3] Fix btrestart command for macOS Monterey 12.2.1+ - Replace deprecated kextunload/kextload approach with launchctl - Kill audio and bluetooth processes before restarting services - Use launchctl to restart bluetooth and audio services - Add error handling with 2>/dev/null || true for robustness - Fixes issue where kext is 'in use or retained' on modern macOS Resolves #10934 --- plugins/macos/macos.plugin.zsh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/plugins/macos/macos.plugin.zsh b/plugins/macos/macos.plugin.zsh index 4d73d22c3..df2e0cde7 100644 --- a/plugins/macos/macos.plugin.zsh +++ b/plugins/macos/macos.plugin.zsh @@ -19,8 +19,17 @@ alias hidefiles="defaults write com.apple.finder AppleShowAllFiles -bool false & # Bluetooth restart function btrestart() { - sudo kextunload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport - sudo kextload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport + # Kill audio and bluetooth processes + pgrep audio | xargs sudo kill 2>/dev/null || true + pgrep bluetooth | xargs sudo kill 2>/dev/null || true + + # Restart bluetooth services using launchctl + sudo launchctl list | grep -i blue | awk '{ print $3 }' | xargs sudo launchctl stop 2>/dev/null || true + sudo launchctl list | grep -i blue | awk '{ print $3 }' | xargs sudo launchctl start 2>/dev/null || true + + # Restart audio services using launchctl + sudo launchctl list | grep -i audio | awk '{ print $3 }' | xargs sudo launchctl stop 2>/dev/null || true + sudo launchctl list | grep -i audio | awk '{ print $3 }' | xargs sudo launchctl start 2>/dev/null || true } function _omz_macos_get_frontmost_app() { From 23f825ff648b5b149c8c145829031cff2d59ca89 Mon Sep 17 00:00:00 2001 From: Paul Frederiksen Date: Tue, 7 Oct 2025 16:33:28 -0700 Subject: [PATCH 2/3] Simplify btrestart to use pkill bluetoothd approach - Replace complex launchctl approach with simple pkill bluetoothd - macOS automatically restarts bluetoothd when killed - Much more maintainable and future-proof - Reduces from 6 commands to 1 command - Less prone to OS changes and service discovery issues - Cleaner, more readable implementation Resolves #10934 --- plugins/macos/macos.plugin.zsh | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/plugins/macos/macos.plugin.zsh b/plugins/macos/macos.plugin.zsh index df2e0cde7..e0bfd045a 100644 --- a/plugins/macos/macos.plugin.zsh +++ b/plugins/macos/macos.plugin.zsh @@ -19,17 +19,9 @@ alias hidefiles="defaults write com.apple.finder AppleShowAllFiles -bool false & # Bluetooth restart function btrestart() { - # Kill audio and bluetooth processes - pgrep audio | xargs sudo kill 2>/dev/null || true - pgrep bluetooth | xargs sudo kill 2>/dev/null || true - - # Restart bluetooth services using launchctl - sudo launchctl list | grep -i blue | awk '{ print $3 }' | xargs sudo launchctl stop 2>/dev/null || true - sudo launchctl list | grep -i blue | awk '{ print $3 }' | xargs sudo launchctl start 2>/dev/null || true - - # Restart audio services using launchctl - sudo launchctl list | grep -i audio | awk '{ print $3 }' | xargs sudo launchctl stop 2>/dev/null || true - sudo launchctl list | grep -i audio | awk '{ print $3 }' | xargs sudo launchctl start 2>/dev/null || true + echo "Restarting Bluetooth daemon..." + sudo pkill bluetoothd + echo "Bluetooth daemon restarted." } function _omz_macos_get_frontmost_app() { From 897b56045d9ee784dda4ac1d10d84c3573353a0b Mon Sep 17 00:00:00 2001 From: Paul Frederiksen Date: Tue, 7 Oct 2025 16:45:32 -0700 Subject: [PATCH 3/3] Add validation to btrestart function - Track old PID before killing bluetoothd - Wait for process to actually stop (5s timeout) - Wait for process to restart (10s timeout) - Verify new PID is different from old PID - Provide clear success/failure feedback - Handle edge cases (no process, restart failure) - Return proper exit codes (0=success, 1=failure) - Maintain simplicity while adding robustness This ensures users know if the restart actually worked. --- plugins/macos/macos.plugin.zsh | 39 ++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/plugins/macos/macos.plugin.zsh b/plugins/macos/macos.plugin.zsh index e0bfd045a..362e4c280 100644 --- a/plugins/macos/macos.plugin.zsh +++ b/plugins/macos/macos.plugin.zsh @@ -20,8 +20,43 @@ alias hidefiles="defaults write com.apple.finder AppleShowAllFiles -bool false & # Bluetooth restart function btrestart() { echo "Restarting Bluetooth daemon..." - sudo pkill bluetoothd - echo "Bluetooth daemon restarted." + + # Get the current bluetoothd PID before killing + local old_pid=$(pgrep bluetoothd) + + if [ -n "$old_pid" ]; then + echo "Stopping bluetoothd (PID: $old_pid)..." + sudo pkill bluetoothd + + # Wait for the process to actually stop + local count=0 + while pgrep -f "bluetoothd" >/dev/null 2>&1 && [ $count -lt 10 ]; do + sleep 0.5 + count=$((count + 1)) + done + + # Wait for bluetoothd to restart + echo "Waiting for bluetoothd to restart..." + count=0 + while ! pgrep bluetoothd >/dev/null 2>&1 && [ $count -lt 20 ]; do + sleep 0.5 + count=$((count + 1)) + done + + # Check if it restarted successfully + local new_pid=$(pgrep bluetoothd) + if [ -n "$new_pid" ] && [ "$new_pid" != "$old_pid" ]; then + echo "✓ Bluetooth daemon restarted successfully (new PID: $new_pid)" + elif [ -n "$new_pid" ] && [ "$new_pid" = "$old_pid" ]; then + echo "⚠ Bluetooth daemon may not have restarted (same PID: $new_pid)" + else + echo "✗ Bluetooth daemon failed to restart" + return 1 + fi + else + echo "No bluetoothd process found to restart" + return 1 + fi } function _omz_macos_get_frontmost_app() {