Просмотр исходного кода

feat(mac-ops): Add bluetooth-audit + font-audit

bluetooth-audit.sh   Paired devices + connection state, bluetoothd health,
                     recent connect/disconnect events, BT error log, wake-
                     for-bluetooth settings. Diagnostic for AirPods drops,
                     Magic Mouse stutter, BT-driven 3am wakes.

font-audit.sh        Font directory inventory (system + user + Adobe),
                     fontd CPU + memory + recent errors, duplicate filename
                     detection. Font conflicts are a common silent cause of
                     Office and Adobe crashes.

Now: 22 scripts, 10 reference docs, 6,355 lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0xDarkMatter 2 недель назад
Родитель
Сommit
ba848f2833

+ 1 - 1
.claude-plugin/plugin.json

@@ -1,6 +1,6 @@
 {
   "name": "claude-mods",
-  "version": "2.7.4",
+  "version": "2.7.5",
   "description": "Custom commands, skills, and agents for Claude Code - session continuity, 23 expert agents, 78 skills, 2 commands, 6 rules, 4 hooks, 13 output styles, modern CLI tools",
   "author": "0xDarkMatter",
   "repository": "https://github.com/0xDarkMatter/claude-mods",

Разница между файлами не показана из-за своего большого размера
+ 3 - 0
README.md


+ 132 - 0
skills/mac-ops/scripts/bluetooth-audit.sh

@@ -0,0 +1,132 @@
+#!/usr/bin/env bash
+# mac-ops :: bluetooth-audit.sh
+# Bluetooth state: paired devices, currently connected, recent connection
+# issues, the Bluetooth daemon state.
+#
+# Common Bluetooth pains on Mac: keyboard/mouse disconnects, AirPods audio
+# quality drops, Magic Mouse cursor stutter, HomePod handoff failures. The
+# log usually has the smoking gun.
+
+set -u
+
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        --help|-h)
+            cat <<EOF
+Usage: $0 [options]
+
+  --json, --redact, --quiet, --verbose
+
+Reports:
+  1. Bluetooth power state + daemon health (bluetoothd)
+  2. Paired devices + connection state
+  3. Recent connection/disconnection events (24h)
+  4. Recent Bluetooth errors / faults
+  5. Wake-on-Bluetooth setting
+
+Common fixes:
+  - sudo pkill bluetoothd               # daemon restart
+  - sudo defaults delete ~/Library/Preferences/com.apple.Bluetooth.plist  # reset (drastic)
+  - Remove + re-pair the misbehaving device
+EOF
+            exit 0 ;;
+        *) shift ;;
+    esac
+done
+
+source "$(dirname "$0")/_lib/common.sh"
+parse_common_flags "$@"
+maybe_filter_self "$@"
+
+# ----------------------------------------------------------------------------
+section "1. BLUETOOTH POWER + DAEMON"
+# ----------------------------------------------------------------------------
+# Use system_profiler — slow but reliable
+bt_summary=$(system_profiler SPBluetoothDataType 2>/dev/null)
+state=$(echo "$bt_summary" | awk -F': *' '/State:/{print $2; exit}')
+addr=$(echo "$bt_summary" | awk -F': *' '/Address:/{print $2; exit}')
+
+case "$state" in
+    *On*) log_pass "Bluetooth state" "On" ;;
+    *Off*) log_info "Bluetooth state" "Off" ;;
+    *) log_info "Bluetooth state" "${state:-unknown}" ;;
+esac
+[[ -n "$addr" ]] && note "  Adapter address: $addr"
+
+# bluetoothd process
+if pgrep -x bluetoothd >/dev/null; then
+    pid=$(pgrep -x bluetoothd | head -1)
+    cpu=$(ps -p "$pid" -o pcpu= 2>/dev/null | tr -d ' ')
+    log_pass "bluetoothd" "PID $pid (CPU ${cpu:-0}%)"
+else
+    log_fail "bluetoothd" "not running"
+fi
+
+# ----------------------------------------------------------------------------
+section "2. PAIRED DEVICES"
+# ----------------------------------------------------------------------------
+# Extract device blocks from system_profiler output
+note "  Paired devices (name | connected | type):"
+echo "$bt_summary" | awk '
+    /Address:/ && /[0-9A-F][0-9A-F]-/{
+        # We are inside the device list (not the adapter section)
+        device_name=prev_line
+    }
+    /Connected:/ && device_name {
+        connected=$0; sub(/^[[:space:]]+Connected:[[:space:]]+/, "", connected)
+    }
+    /Minor Type:|Major Type:/ && device_name {
+        type=$0; sub(/^[[:space:]]+[^:]+:[[:space:]]+/, "", type)
+    }
+    /^$/ && device_name && connected {
+        printf "    %-35s %-10s %s\n", device_name, connected, (type ? type : "?")
+        device_name=""; connected=""; type=""
+    }
+    {prev_line=$0}
+' | head -20
+
+# ----------------------------------------------------------------------------
+section "3. RECENT CONNECTION EVENTS (24h)"
+# ----------------------------------------------------------------------------
+conn_events=$(log show --last 24h --style compact \
+    --predicate '(subsystem == "com.apple.bluetooth" OR process == "bluetoothd") AND (eventMessage CONTAINS[c] "connect" OR eventMessage CONTAINS[c] "disconnect")' \
+    2>/dev/null | grep -iE "(connect|disconnect)" | tail -15)
+
+if [[ -n "$conn_events" ]]; then
+    n=$(echo "$conn_events" | wc -l | tr -d ' \n')
+    log_info "Bluetooth connect/disconnect events (24h)" "$n"
+    note "  Recent (last 10):"
+    echo "$conn_events" | tail -10 | sed 's/^/    /'
+fi
+
+# ----------------------------------------------------------------------------
+section "4. RECENT BLUETOOTH ERRORS"
+# ----------------------------------------------------------------------------
+bt_errors=$(log show --last 24h --style compact \
+    --predicate '(subsystem == "com.apple.bluetooth" OR process == "bluetoothd") AND (messageType == "Error" OR messageType == "Fault")' \
+    2>/dev/null | head -10)
+
+if [[ -n "$bt_errors" ]]; then
+    n=$(echo "$bt_errors" | wc -l | tr -d ' \n')
+    log_warn "Bluetooth error/fault events (24h)" "$n"
+    echo "$bt_errors" | head -5 | sed 's/^/    /'
+else
+    log_pass "Bluetooth error/fault events (24h)" "0"
+fi
+
+# ----------------------------------------------------------------------------
+section "5. WAKE FOR BLUETOOTH"
+# ----------------------------------------------------------------------------
+# "Wake for Bluetooth devices" — often the culprit for 3am wakes
+wake_setting=$(pmset -g | awk '/ttyskeepawake/{print $2; exit}')
+note "  pmset settings (lookout for wake-for-bluetooth):"
+pmset -g 2>/dev/null | grep -iE "bluetooth|womp|hidwake" | sed 's/^/    /'
+
+# ----------------------------------------------------------------------------
+section "6. BLUETOOTH PROCESS NAMES TO KNOW"
+# ----------------------------------------------------------------------------
+note "  Active BT-related processes:"
+ps -Ao pid,comm 2>/dev/null | grep -iE "bluetoothd|BTSupport|BTLE|AirPort|AirDrop" | head -10 | sed 's/^/    /'
+
+# ----------------------------------------------------------------------------
+emit_summary

+ 128 - 0
skills/mac-ops/scripts/font-audit.sh

@@ -0,0 +1,128 @@
+#!/usr/bin/env bash
+# mac-ops :: font-audit.sh
+# Font inventory + duplicate detection. Font conflicts cause real problems —
+# Office crashes, Adobe app crashes, font rendering glitches, login slowness
+# (Font Book validates ALL fonts at login if registry is corrupt).
+
+set -u
+
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        --help|-h)
+            cat <<EOF
+Usage: $0 [options]
+
+  --json, --redact, --quiet, --verbose
+
+Reports:
+  1. Font directories + counts (system, user, library, fontd cache)
+  2. fontd process state + recent errors
+  3. Duplicate fonts (same family in multiple locations)
+  4. Disabled fonts in Font Book
+  5. Suspicious / corrupt font files
+
+Common fixes:
+  - Open Font Book → File → Validate fonts → resolve duplicates
+  - sudo atsutil databases -remove        # clear font cache, reboot
+  - sudo atsutil server -shutdown         # restart font server
+EOF
+            exit 0 ;;
+        *) shift ;;
+    esac
+done
+
+source "$(dirname "$0")/_lib/common.sh"
+parse_common_flags "$@"
+maybe_filter_self "$@"
+
+# ----------------------------------------------------------------------------
+section "1. FONT DIRECTORIES"
+# ----------------------------------------------------------------------------
+declare -a font_dirs=(
+    "/System/Library/Fonts"
+    "/Library/Fonts"
+    "$HOME/Library/Fonts"
+)
+
+for d in "${font_dirs[@]}"; do
+    if [[ -d "$d" ]]; then
+        count=$(find "$d" -maxdepth 2 -type f \( -name "*.ttf" -o -name "*.otf" -o -name "*.ttc" -o -name "*.dfont" \) 2>/dev/null | wc -l | tr -d ' \n')
+        size=$(du -sh "$d" 2>/dev/null | awk '{print $1}')
+        log_info "$d" "$count fonts, $size"
+    fi
+done
+
+# Adobe / third-party font cache directories
+adobe_fonts=$(find /Users -maxdepth 5 -path "*/Library/Application Support/Adobe/CoreSync/plugins/livetype/r" -type d 2>/dev/null | head -3)
+if [[ -n "$adobe_fonts" ]]; then
+    while IFS= read -r d; do
+        count=$(find "$d" -maxdepth 2 -type f \( -name "*.ttf" -o -name "*.otf" \) 2>/dev/null | wc -l | tr -d ' \n')
+        note "    $d ($count Adobe Fonts)"
+    done <<< "$adobe_fonts"
+fi
+
+# ----------------------------------------------------------------------------
+section "2. fontd PROCESS"
+# ----------------------------------------------------------------------------
+if pgrep -x fontd >/dev/null; then
+    pid=$(pgrep -x fontd | head -1)
+    cpu=$(ps -p "$pid" -o pcpu= 2>/dev/null | tr -d ' ')
+    rss=$(ps -p "$pid" -o rss= 2>/dev/null | tr -d ' ')
+    log_pass "fontd running" "PID $pid (CPU ${cpu:-0}%, RSS ${rss:-?} KB)"
+else
+    log_info "fontd" "not running (Font Book may not be open)"
+fi
+
+# Recent fontd errors
+font_errors=$(log show --last 24h --style compact \
+    --predicate '(process == "fontd" OR process == "FontRegistry" OR eventMessage CONTAINS "font") AND (messageType == "Error" OR messageType == "Fault")' \
+    2>/dev/null | grep -iE "font" | tail -5)
+if [[ -n "$font_errors" ]]; then
+    n=$(echo "$font_errors" | wc -l | tr -d ' \n')
+    log_warn "Font errors in log (24h)" "$n"
+    echo "$font_errors" | head -3 | sed 's/^/    /'
+fi
+
+# ----------------------------------------------------------------------------
+section "3. DUPLICATE FONTS"
+# ----------------------------------------------------------------------------
+# Find filename collisions across all font dirs
+all_fonts=$(for d in "${font_dirs[@]}"; do
+    [[ -d "$d" ]] && find "$d" -maxdepth 2 -type f \( -name "*.ttf" -o -name "*.otf" -o -name "*.ttc" \) 2>/dev/null
+done)
+
+dupes=$(echo "$all_fonts" | awk -F/ '{print $NF}' | sort | uniq -d)
+if [[ -n "$dupes" ]]; then
+    n=$(echo "$dupes" | wc -l | tr -d ' \n')
+    log_warn "Duplicate font filenames" "$n"
+    note "  Duplicates (filename, then locations):"
+    echo "$dupes" | head -10 | while read -r f; do
+        printf "    %s\n" "$f"
+        echo "$all_fonts" | grep "/$f\$" | sed 's/^/      /'
+    done
+else
+    log_pass "Duplicate font filenames" "0"
+fi
+
+# ----------------------------------------------------------------------------
+section "4. FONT BOOK DISABLED FONTS"
+# ----------------------------------------------------------------------------
+# Font Book stores disabled-state in a plist (path varies by macOS version)
+disabled_plist=$(find "$HOME/Library/FontCollections" -maxdepth 2 -name "*.collection" 2>/dev/null | head -3)
+if [[ -n "$disabled_plist" ]]; then
+    note "  Font collections found:"
+    echo "$disabled_plist" | sed 's/^/    /'
+fi
+
+# ----------------------------------------------------------------------------
+section "5. CACHE / VALIDATION"
+# ----------------------------------------------------------------------------
+note "  Font cache reset (drastic) requires sudo:"
+note "    sudo atsutil databases -remove   # clears all font caches"
+note "    sudo atsutil server -shutdown    # restarts font server"
+note ""
+note "  To open Font Book and validate:"
+note "    open -a 'Font Book'              # then File → Validate Fonts"
+
+# ----------------------------------------------------------------------------
+emit_summary

+ 1 - 1
skills/mac-ops/tests/run.sh

@@ -175,7 +175,7 @@ expected_scripts=(
     tcc-audit.sh wake-reasons.sh spotlight-status.sh storage-pressure.sh
     kext-audit.sh firewall-audit.sh network-locations.sh
     sysdiagnose-helper.sh brew-health.sh update-state.sh media-libraries.sh
-    keychain-audit.sh
+    keychain-audit.sh bluetooth-audit.sh font-audit.sh
 )
 for s in "${expected_scripts[@]}"; do
     assert "script exists: $s" test -f "$root/scripts/$s"