#!/bin/bash
# System Monitor
# v1.4.0
# Oleg Koval
# oleg-koval
# Power-user macOS health dashboard for SwiftBar.
# https://github.com/oleg-koval/swiftbar-plugins
# bash
# 5s
# false
# true
# number(VAR_SM_LOAD_WARN=6): Load average warning threshold.
# number(VAR_SM_LOAD_CRIT=8): Load average critical threshold.
# number(VAR_SM_HIGH_CPU_THRESHOLD=90): CPU percent treated as runaway.
# number(VAR_SM_LOW_DISK_WARN_GB=20): Free disk GB warning threshold.
# boolean(VAR_SM_SHOW_DEVICES=false): Show display, USB, Bluetooth, and network sections.
# boolean(VAR_SM_SHOW_SYSTEM_ALERTS=true): Show update, iCloud, and Spotlight alerts.
# boolean(VAR_SM_CHECK_SOFTWARE_UPDATES=false): Run the slow software update check.
# boolean(VAR_SM_SHOW_DOCKER=true): Show Docker/OrbStack section when available.
# boolean(VAR_SM_SHOW_DOCKER_STATS=false): Show per-container CPU/memory stats.
# boolean(VAR_SM_SHOW_ENERGY=false): Show energy impact while on battery.
# boolean(VAR_SM_ANIMATE_TITLE=true): Animate the healthy menu bar indicator.
set -u
PLUGIN_VERSION="1.4.0"
AUTHOR_GITHUB="oleg-koval"
REPO_NAME="swiftbar-plugins"
REPO_DEFAULT_BRANCH="main"
REPO_PLUGIN_FILE="system-monitor.5s.sh"
REPO_URL="https://github.com/${AUTHOR_GITHUB}/${REPO_NAME}"
if [ -n "${SWIFTBAR_PLUGIN_PATH:-}" ]; then
PLUGIN_PATH="$SWIFTBAR_PLUGIN_PATH"
else
PLUGIN_DIR="$(cd "$(dirname "$0")" && pwd)"
PLUGIN_PATH="$PLUGIN_DIR/$(basename "$0")"
fi
DATA_DIR="${SWIFTBAR_PLUGIN_DATA_PATH:-$HOME/.config/swiftbar-system-monitor}"
CACHE_DIR="${SWIFTBAR_PLUGIN_CACHE_PATH:-$HOME/.cache/swiftbar-system-monitor}"
LOAD_WARN="6"
LOAD_CRIT="8"
HIGH_CPU_THRESHOLD="90"
LOW_DISK_WARN_GB="20"
SHOW_DEVICES="false"
SHOW_SYSTEM_ALERTS="true"
CHECK_SOFTWARE_UPDATES="false"
SHOW_DOCKER="true"
SHOW_DOCKER_STATS="false"
SHOW_ENERGY="false"
ANIMATE_TITLE="true"
SLOW_CACHE_TTL_SECONDS="300"
HARDWARE_CACHE_TTL_SECONDS="86400"
GITHUB_VERSION_CACHE_TTL_SECONDS="21600"
FLIGHT_RECORDER_WINDOW_SECONDS="900"
FLIGHT_RECORDER_MAX_ROWS="240"
UPDATE_STATUS_TTL_SECONDS="900"
PROCESS_SNAPSHOT=""
APPEARANCE_MODE=""
command_exists() {
command -v "$1" >/dev/null 2>&1
}
is_true() {
case "${1:-}" in
1|true|TRUE|yes|YES|on|ON) return 0 ;;
*) return 1 ;;
esac
}
is_number() {
case "$1" in
''|*[!0-9]*) return 1 ;;
*) return 0 ;;
esac
}
appearance_mode() {
if [ -z "$APPEARANCE_MODE" ]; then
if defaults read -g AppleInterfaceStyle >/dev/null 2>&1; then
APPEARANCE_MODE="Dark"
else
APPEARANCE_MODE="Light"
fi
fi
printf '%s' "$APPEARANCE_MODE"
}
secondary_color() {
if [ "$(appearance_mode)" = "Dark" ]; then
printf '#B0B8C1'
else
printf '#475467'
fi
}
critical_color() {
if [ "$(appearance_mode)" = "Dark" ]; then
printf '#FF8A80'
else
printf '#B42318'
fi
}
warning_color() {
if [ "$(appearance_mode)" = "Dark" ]; then
printf '#F5C451'
else
printf '#B54708'
fi
}
healthy_color() {
if [ "$(appearance_mode)" = "Dark" ]; then
printf '#4AD97A'
else
printf '#157F3B'
fi
}
set_config_value() {
local key="$1"
local value="$2"
case "$key" in
LOAD_WARN|SM_LOAD_WARN) LOAD_WARN="$value" ;;
LOAD_CRIT|SM_LOAD_CRIT) LOAD_CRIT="$value" ;;
HIGH_CPU_THRESHOLD|SM_HIGH_CPU_THRESHOLD) HIGH_CPU_THRESHOLD="$value" ;;
LOW_DISK_WARN_GB|SM_LOW_DISK_WARN_GB) LOW_DISK_WARN_GB="$value" ;;
SHOW_DEVICES|SM_SHOW_DEVICES) SHOW_DEVICES="$value" ;;
SHOW_SYSTEM_ALERTS|SM_SHOW_SYSTEM_ALERTS) SHOW_SYSTEM_ALERTS="$value" ;;
CHECK_SOFTWARE_UPDATES|SM_CHECK_SOFTWARE_UPDATES) CHECK_SOFTWARE_UPDATES="$value" ;;
SHOW_DOCKER|SM_SHOW_DOCKER) SHOW_DOCKER="$value" ;;
SHOW_DOCKER_STATS|SM_SHOW_DOCKER_STATS) SHOW_DOCKER_STATS="$value" ;;
SHOW_ENERGY|SM_SHOW_ENERGY) SHOW_ENERGY="$value" ;;
ANIMATE_TITLE|SM_ANIMATE_TITLE) ANIMATE_TITLE="$value" ;;
SLOW_CACHE_TTL_SECONDS|SM_SLOW_CACHE_TTL_SECONDS) SLOW_CACHE_TTL_SECONDS="$value" ;;
esac
}
load_config_file() {
local file="$1"
local line key value
[ -f "$file" ] || return 0
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
''|\#*) continue ;;
*=*)
key="${line%%=*}"
value="${line#*=}"
key="$(printf '%s' "$key" | tr -d '[:space:]')"
value="$(printf '%s' "$value" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^"//' -e 's/"$//')"
set_config_value "$key" "$value"
;;
esac
done <"$file"
}
apply_env_override() {
local env_name="$1"
local key="$2"
local value
eval "value=\${$env_name:-}"
[ -n "$value" ] && set_config_value "$key" "$value"
}
load_config() {
load_config_file "$HOME/.config/swiftbar-system-monitor/config"
load_config_file "$DATA_DIR/config"
apply_env_override "VAR_SM_LOAD_WARN" "LOAD_WARN"
apply_env_override "VAR_SM_LOAD_CRIT" "LOAD_CRIT"
apply_env_override "VAR_SM_HIGH_CPU_THRESHOLD" "HIGH_CPU_THRESHOLD"
apply_env_override "VAR_SM_LOW_DISK_WARN_GB" "LOW_DISK_WARN_GB"
apply_env_override "VAR_SM_SHOW_DEVICES" "SHOW_DEVICES"
apply_env_override "VAR_SM_SHOW_SYSTEM_ALERTS" "SHOW_SYSTEM_ALERTS"
apply_env_override "VAR_SM_CHECK_SOFTWARE_UPDATES" "CHECK_SOFTWARE_UPDATES"
apply_env_override "VAR_SM_SHOW_DOCKER" "SHOW_DOCKER"
apply_env_override "VAR_SM_SHOW_DOCKER_STATS" "SHOW_DOCKER_STATS"
apply_env_override "VAR_SM_SHOW_ENERGY" "SHOW_ENERGY"
apply_env_override "VAR_SM_ANIMATE_TITLE" "ANIMATE_TITLE"
apply_env_override "VAR_SM_SLOW_CACHE_TTL_SECONDS" "SLOW_CACHE_TTL_SECONDS"
is_number "$LOAD_WARN" || LOAD_WARN="6"
is_number "$LOAD_CRIT" || LOAD_CRIT="8"
is_number "$HIGH_CPU_THRESHOLD" || HIGH_CPU_THRESHOLD="90"
is_number "$LOW_DISK_WARN_GB" || LOW_DISK_WARN_GB="20"
is_number "$SLOW_CACHE_TTL_SECONDS" || SLOW_CACHE_TTL_SECONDS="300"
}
cache_is_fresh() {
local file="$1"
local ttl="$2"
local now modified age
[ -f "$file" ] || return 1
now="$(date +%s)"
modified="$(stat -f %m "$file" 2>/dev/null || echo 0)"
age=$((now - modified))
[ "$age" -lt "$ttl" ]
}
cached_command() {
local name="$1"
local ttl="$2"
shift 2
mkdir -p "$CACHE_DIR" 2>/dev/null || true
local cache_file="$CACHE_DIR/$name"
if cache_is_fresh "$cache_file" "$ttl"; then
cat "$cache_file"
return 0
fi
if "$@" >"$cache_file.tmp" 2>/dev/null; then
mv "$cache_file.tmp" "$cache_file"
cat "$cache_file"
else
rm -f "$cache_file.tmp"
[ -f "$cache_file" ] && cat "$cache_file"
fi
}
normalize_git_remote_url() {
local url="$1"
case "$url" in
git@github.com:*)
url="https://github.com/${url#git@github.com:}"
;;
ssh://git@github.com/*)
url="https://github.com/${url#ssh://git@github.com/}"
;;
esac
printf '%s' "${url%.git}"
}
official_checkout_dir() {
local checkout_dir origin_url normalized_origin
command_exists git || return 1
checkout_dir="$(git -C "$PLUGIN_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
[ -n "$checkout_dir" ] || return 1
origin_url="$(git -C "$checkout_dir" remote get-url origin 2>/dev/null || true)"
[ -n "$origin_url" ] || return 1
normalized_origin="$(normalize_git_remote_url "$origin_url")"
[ "$normalized_origin" = "$REPO_URL" ] || return 1
printf '%s' "$checkout_dir"
}
plugin_update_url() {
printf 'https://raw.githubusercontent.com/%s/%s/%s/%s' \
"$AUTHOR_GITHUB" \
"$REPO_NAME" \
"$REPO_DEFAULT_BRANCH" \
"$REPO_PLUGIN_FILE"
}
version_is_newer() {
local candidate="$1"
local current="$2"
awk -v candidate="$candidate" -v current="$current" '
BEGIN {
candidate_count = split(candidate, candidate_parts, ".")
current_count = split(current, current_parts, ".")
max_parts = candidate_count > current_count ? candidate_count : current_count
for (part_index = 1; part_index <= max_parts; part_index++) {
candidate_value = (part_index in candidate_parts && candidate_parts[part_index] ~ /^[0-9]+$/) ? candidate_parts[part_index] + 0 : 0
current_value = (part_index in current_parts && current_parts[part_index] ~ /^[0-9]+$/) ? current_parts[part_index] + 0 : 0
if (candidate_value > current_value) exit 0
if (candidate_value < current_value) exit 1
}
exit 1
}'
}
installed_plugin_version() {
sed -n 's/^PLUGIN_VERSION="\([^"]*\)"/\1/p' "$PLUGIN_PATH" | head -1
}
remote_plugin_version() {
local plugin_contents remote_version
command_exists curl || return 0
plugin_contents="$(cached_command github-plugin-version "$GITHUB_VERSION_CACHE_TTL_SECONDS" \
curl -fsSL --connect-timeout 2 --max-time 4 "$(plugin_update_url)")"
remote_version="$(printf '%s\n' "$plugin_contents" | sed -n 's/^PLUGIN_VERSION="\([^"]*\)"/\1/p' | head -1)"
[ -n "$remote_version" ] && printf '%s' "$remote_version"
}
validate_downloaded_plugin() {
local file="$1"
grep -q '^# System Monitor$' "$file" &&
grep -q '^PLUGIN_VERSION="' "$file"
}
download_plugin_update() {
local url="$1"
local target="$2"
curl -fsSL "$url" -o "$target"
}
print_update_status_line() {
local subtle remote_version
subtle="$(secondary_color)"
remote_version="$(remote_plugin_version)"
if [ -z "$remote_version" ]; then
echo "----GitHub: update check unavailable | color=$subtle"
elif version_is_newer "$remote_version" "$PLUGIN_VERSION"; then
echo "----GitHub: v${remote_version} available | color=$(healthy_color)"
elif version_is_newer "$PLUGIN_VERSION" "$remote_version"; then
echo "----GitHub: local version differs from main (v${remote_version}) | color=$(warning_color)"
else
echo "----GitHub: up to date (v${PLUGIN_VERSION}) | color=$subtle"
fi
}
plugin_update_status_file() {
printf '%s/plugin-update-status.tsv' "$DATA_DIR"
}
write_plugin_update_status() {
local state="$1"
local version="$2"
local message="$3"
mkdir -p "$DATA_DIR" 2>/dev/null || true
printf '%s\t%s\t%s\t%s\n' \
"$(sanitize_snapshot_field "$(flight_recorder_now)")" \
"$(sanitize_snapshot_field "$state")" \
"$(sanitize_snapshot_field "$version")" \
"$(sanitize_snapshot_field "$message")" >"$(plugin_update_status_file)"
}
refresh_plugin_menu() {
if command_exists open; then
open -g "swiftbar://refreshplugin?plugin=$(basename "$PLUGIN_PATH")" >/dev/null 2>&1 || true
fi
}
notify_update_result() {
local title="$1"
local message="$2"
if command_exists osascript; then
osascript -e "display notification \"${message//\"/\\\"}\" with title \"${title//\"/\\\"}\"" >/dev/null 2>&1 || true
fi
}
print_plugin_update_notice() {
local file now status_time status version message age label
file="$(plugin_update_status_file)"
[ -f "$file" ] || return 0
IFS=$'\t' read -r status_time status version message <"$file" || return 0
case "$status_time" in
''|*[!0-9]*) return 0 ;;
esac
now="$(flight_recorder_now)"
age=$((now - status_time))
[ "$age" -lt "$UPDATE_STATUS_TTL_SECONDS" ] || return 0
if [ "$age" -lt 60 ]; then
label="just now"
else
label="$((age / 60))m ago"
fi
case "$status" in
success)
echo "--Update: ${message} (${label}) | color=$(healthy_color)"
;;
pending)
echo "--Update: ${message} | color=$(warning_color)"
;;
*)
echo "--Update: ${message} (${label}) | color=$(critical_color)"
;;
esac
}
flight_recorder_file() {
printf '%s/flight-recorder.tsv' "$CACHE_DIR"
}
flight_recorder_now() {
if [ -n "${SM_TEST_NOW:-}" ]; then
printf '%s' "$SM_TEST_NOW"
else
date +%s
fi
}
sanitize_snapshot_field() {
local cleaned
cleaned="$(printf '%s' "${1:-unknown}" | tr '\t\r\n' ' ' | sed -e 's/[[:space:]][[:space:]]*/ /g' -e 's/^ //' -e 's/ $//')"
if [ -n "$cleaned" ]; then
printf '%s' "$cleaned"
else
printf 'unknown'
fi
}
load_average() {
uptime | awk -F'load averages?: ' '{print $2}' | awk '{print $1}' | tr ',' '.'
}
integer_part() {
printf '%s' "$1" | awk -F. '{print $1}'
}
memory_compressed_gb() {
local pages page_size
pages="$(vm_stat 2>/dev/null | awk '/occupied by compressor/ {gsub(/\./, "", $5); print $5}')"
page_size="$(pagesize 2>/dev/null || echo 16384)"
if is_number "$pages" && is_number "$page_size"; then
awk -v pages="$pages" -v page_size="$page_size" 'BEGIN { printf "%.1f", pages * page_size / 1073741824 }'
else
printf '?'
fi
}
disk_available_human() {
df -h / 2>/dev/null | awk 'NR==2 {print $4}' | sed -e 's/Gi$/ GB/' -e 's/Mi$/ MB/'
}
disk_available_gb() {
df -g / 2>/dev/null | awk 'NR==2 {print $4}'
}
process_awk_helpers() {
cat <<'AWK'
function join_fields(start_idx, end_idx, i, value) {
value = $(start_idx)
for (i = start_idx + 1; i <= end_idx; i++) {
value = value " " $i
}
return value
}
function app_name_from_cmd(cmd, cmd_path, parts, name) {
cmd_path = cmd
sub(/[[:space:]]+-.*/, "", cmd_path)
split(cmd_path, parts, "/")
name = parts[length(parts)]
if (length(name) > 40) name = substr(name, 1, 37) "..."
return name
}
function sanitize_cmd(cmd) {
gsub(/\t/, " ", cmd)
return cmd
}
AWK
}
top_process_summary() {
local sort_key="$1"
local metric_index="$2"
local awk_script summary
awk_script="$(process_awk_helpers)
{
metric = \$metric_index
cmd = join_fields(11, NF)
app_name = app_name_from_cmd(cmd)
printf \"%s|%.1f\", app_name, metric
exit
}"
summary="$(printf '%s\n' "$PROCESS_SNAPSHOT" |
tail -n +2 |
sort -nrk "$sort_key" |
awk -v metric_index="$metric_index" "$awk_script")"
if [ -n "$summary" ]; then
printf '%s' "$summary"
else
printf 'unknown|0.0'
fi
}
hardware_name() {
local model_name
model_name="$(cached_command hardware "$HARDWARE_CACHE_TTL_SECONDS" /usr/sbin/system_profiler SPHardwareDataType | awk -F': ' '/Model Name/ {print $2; exit}')"
if [ -n "$model_name" ]; then
printf '%s' "$model_name"
else
sysctl -n hw.model 2>/dev/null || printf 'Mac'
fi
}
macos_version() {
sw_vers -productVersion 2>/dev/null || printf 'unknown'
}
memory_pressure_percent() {
vm_stat 2>/dev/null | awk '
/Pages active/ {gsub(/\./, "", $3); active = $3}
/Pages wired down/ {gsub(/\./, "", $4); wired = $4}
/Pages occupied by compressor/ {gsub(/\./, "", $5); compressed = $5}
/Pages free/ {gsub(/\./, "", $3); free = $3}
/Pages inactive/ {gsub(/\./, "", $3); inactive = $3}
/Pages speculative/ {gsub(/\./, "", $3); speculative = $3}
END {
total = active + wired + compressed + free + inactive + speculative
if (total > 0) printf "%.0f", ((active + wired + compressed) / total) * 100
}'
}
human_rate() {
awk -v bytes="${1:-0}" 'BEGIN {
if (bytes >= 1048576) printf "%.1f MB/s", bytes / 1048576
else if (bytes >= 1024) printf "%.0f KB/s", bytes / 1024
else printf "%.0f B/s", bytes
}'
}
network_rates() {
local now totals in_bytes out_bytes cache_file prev_now prev_in prev_out elapsed in_rate out_rate
mkdir -p "$CACHE_DIR" 2>/dev/null || true
cache_file="$CACHE_DIR/network-counters"
now="$(date +%s)"
totals="$(netstat -ibn 2>/dev/null | awk '$1 !~ /^lo/ && $7 ~ /^[0-9]+$/ && $10 ~ /^[0-9]+$/ {inb += $7; outb += $10} END {printf "%s %s", inb + 0, outb + 0}')"
in_bytes="${totals%% *}"
out_bytes="${totals##* }"
if [ -f "$cache_file" ]; then
read -r prev_now prev_in prev_out <"$cache_file" || true
elapsed=$((now - ${prev_now:-0}))
if [ "$elapsed" -gt 0 ] && is_number "${prev_in:-}" && is_number "${prev_out:-}"; then
in_rate=$(((in_bytes - prev_in) / elapsed))
out_rate=$(((out_bytes - prev_out) / elapsed))
[ "$in_rate" -lt 0 ] && in_rate=0
[ "$out_rate" -lt 0 ] && out_rate=0
printf '%s down, %s up' "$(human_rate "$in_rate")" "$(human_rate "$out_rate")"
else
printf 'warming up'
fi
else
printf 'warming up'
fi
printf '%s %s %s\n' "$now" "$in_bytes" "$out_bytes" >"$cache_file"
}
wifi_profile_json() {
cached_command wifi-profile 120 /usr/sbin/system_profiler SPAirPortDataType -json
}
wifi_interface_device() {
networksetup -listallhardwareports 2>/dev/null |
awk '
/Hardware Port: Wi-Fi/ { found = 1; next }
found && /Device:/ { print $2; exit }
'
}
wifi_connected() {
local device profile status
device="$(wifi_interface_device)"
[ -n "$device" ] || return 1
profile="$(wifi_profile_json)"
[ -n "$profile" ] || return 1
status="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_status_information // empty' 2>/dev/null)"
[ "$status" = "spairport_status_connected" ]
}
wifi_ssid_label() {
local device profile ssid
device="$(wifi_interface_device)"
[ -n "$device" ] || return 1
profile="$(wifi_profile_json)"
[ -n "$profile" ] || return 1
ssid="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information._name // empty' 2>/dev/null)"
case "$ssid" in
''|''|''|'SSID Redacted') printf 'SSID hidden by macOS' ;;
*) printf '%s' "$ssid" ;;
esac
}
wifi_detail_value() {
local jq_filter="$1"
local fallback="${2:-}"
local device profile value
device="$(wifi_interface_device)"
[ -n "$device" ] || { printf '%s' "$fallback"; return 0; }
profile="$(wifi_profile_json)"
[ -n "$profile" ] || { printf '%s' "$fallback"; return 0; }
value="$(printf '%s' "$profile" | jq -r --arg dev "$device" "$jq_filter" 2>/dev/null)"
case "$value" in
''|'null') printf '%s' "$fallback" ;;
*) printf '%s' "$value" ;;
esac
}
wifi_security_label() {
case "$1" in
spairport_security_mode_none) printf 'Open' ;;
spairport_security_mode_wpa2_personal) printf 'WPA2 Personal' ;;
spairport_security_mode_wpa3_personal) printf 'WPA3 Personal' ;;
spairport_security_mode_wpa3_transition) printf 'WPA3 Transition' ;;
*) printf '%s' "$1" ;;
esac
}
wifi_network_type_label() {
case "$1" in
spairport_network_type_station) printf 'Infrastructure' ;;
spairport_network_type_ibss) printf 'Ad hoc' ;;
spairport_network_type_auto) printf 'Auto' ;;
*) printf '%s' "$1" ;;
esac
}
wifi_current_details() {
local ssid channel security signal rate phy_mode network_type router ip_addr device profile
device="$(wifi_interface_device)"
[ -n "$device" ] || return 1
profile="$(wifi_profile_json)"
[ -n "$profile" ] || return 1
ssid="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information._name // empty' 2>/dev/null)"
channel="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_network_channel // empty' 2>/dev/null)"
security="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_security_mode // empty' 2>/dev/null)"
signal="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_signal_noise // empty' 2>/dev/null)"
rate="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_network_rate // empty' 2>/dev/null)"
phy_mode="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_network_phymode // empty' 2>/dev/null)"
network_type="$(printf '%s' "$profile" | jq -r --arg dev "$device" '.SPAirPortDataType[0].spairport_airport_interfaces[]? | select(._name == $dev) | .spairport_current_network_information.spairport_network_type // empty' 2>/dev/null)"
ip_addr="$(ifconfig "$device" 2>/dev/null | awk '/inet / && $2 != "127.0.0.1" {print $2; exit}')"
router="$(ipconfig getsummary "$device" 2>/dev/null | awk -F' : ' '/Router/ {print $2; exit}')"
case "$ssid" in
''|''|''|'SSID Redacted') ssid="SSID hidden by macOS" ;;
esac
[ -n "$channel" ] || channel="Unknown channel"
[ -n "$signal" ] || signal="Signal unavailable"
[ -n "$rate" ] || rate="?"
[ -n "$phy_mode" ] || phy_mode="Unknown"
network_type="$(wifi_network_type_label "$network_type")"
[ -n "$network_type" ] || network_type="Unknown"
[ -n "$ip_addr" ] || ip_addr="Unknown"
[ -n "$router" ] || router="Unknown"
printf '%s|%s|%s|%s|%s|%s|%s|%s' \
"$ssid" \
"$channel" \
"$(wifi_security_label "$security")" \
"$signal" \
"$rate" \
"$phy_mode" \
"$network_type" \
"$ip_addr|$router"
}
vpn_services() {
scutil --nc list 2>/dev/null | perl -ne 'if (/\((Connected|Disconnected)\).*"([^"]+)".*\[VPN:([^\]]+)\]/) { print "$1|$2|$3\n" }'
}
vpn_summary() {
local status name connected configured line
connected=""
configured=""
while IFS='|' read -r status name _; do
[ -n "$name" ] || continue
configured="${configured}${configured:+, }$name"
if [ "$status" = "Connected" ]; then
connected="${connected}${connected:+, }$name"
fi
done < 1 && $3 > threshold { count++ } END { print count + 0 }'
}
valid_flight_history() {
local file="${1:-$(flight_recorder_file)}"
[ -f "$file" ] || return 0
awk -F '\t' 'NF >= 12 && $1 ~ /^[0-9]+$/ { print }' "$file"
}
prune_flight_history() {
local file now cutoff tmp
file="$(flight_recorder_file)"
[ -f "$file" ] || return 0
now="$(flight_recorder_now)"
cutoff=$((now - FLIGHT_RECORDER_WINDOW_SECONDS))
tmp="$file.tmp"
valid_flight_history "$file" |
awk -F '\t' -v cutoff="$cutoff" '$1 >= cutoff { print }' |
tail -n "$FLIGHT_RECORDER_MAX_ROWS" >"$tmp"
mv "$tmp" "$file"
}
record_flight_snapshot() {
local state="$1"
local issue="$2"
local load1="$3"
local high_cpu="$4"
local disk_gb="$5"
local batt_pct="$6"
local now mem_pressure top_cpu top_mem top_cpu_app top_cpu_pct top_mem_app top_mem_pct file
mkdir -p "$CACHE_DIR" 2>/dev/null || true
file="$(flight_recorder_file)"
now="$(flight_recorder_now)"
mem_pressure="$(memory_pressure_percent)"
top_cpu="$(top_process_summary "3" "3")"
top_mem="$(top_process_summary "4" "4")"
top_cpu_app="${top_cpu%%|*}"
top_cpu_pct="${top_cpu##*|}"
top_mem_app="${top_mem%%|*}"
top_mem_pct="${top_mem##*|}"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$(sanitize_snapshot_field "$now")" \
"$(sanitize_snapshot_field "$state")" \
"$(sanitize_snapshot_field "$issue")" \
"$(sanitize_snapshot_field "$load1")" \
"$(sanitize_snapshot_field "$high_cpu")" \
"$(sanitize_snapshot_field "$mem_pressure")" \
"$(sanitize_snapshot_field "$disk_gb")" \
"$(sanitize_snapshot_field "$batt_pct")" \
"$(sanitize_snapshot_field "$top_cpu_app")" \
"$(sanitize_snapshot_field "$top_cpu_pct")" \
"$(sanitize_snapshot_field "$top_mem_app")" \
"$(sanitize_snapshot_field "$top_mem_pct")" >>"$file"
prune_flight_history
}
flight_checkpoint_rows() {
local file="${1:-$(flight_recorder_file)}"
local now="${2:-$(flight_recorder_now)}"
[ -f "$file" ] || return 0
valid_flight_history "$file" | awk -F '\t' -v now="$now" '
function keep(target, label, age, diff) {
age = now - $1
if (age < target) return
diff = age - target
if (!(label in best_diff) || diff < best_diff[label]) {
best_diff[label] = diff
best[label] = $0
}
}
{
latest = $0
keep(60, "1m ago")
keep(300, "5m ago")
keep(900, "15m ago")
}
END {
if (latest != "") print "now\t" latest
if (best["1m ago"] != "" && best["1m ago"] != latest) print "1m ago\t" best["1m ago"]
if (best["5m ago"] != "" && best["5m ago"] != latest && best["5m ago"] != best["1m ago"]) print "5m ago\t" best["5m ago"]
if (best["15m ago"] != "" && best["15m ago"] != latest && best["15m ago"] != best["1m ago"] && best["15m ago"] != best["5m ago"]) print "15m ago\t" best["15m ago"]
}'
}
detect_incident_cause() {
local file="${1:-$(flight_recorder_file)}"
[ -f "$file" ] || { printf 'Learning recent activity. First cause after the next refresh.'; return 0; }
flight_checkpoint_rows "$file" | awk -F '\t' -v high_cpu="$HIGH_CPU_THRESHOLD" -v load_warn="$LOAD_WARN" -v low_disk_warn="$LOW_DISK_WARN_GB" '
function num(value) { return value ~ /^-?[0-9]+([.][0-9]+)?$/ }
function is_spotlight(app, app_lc) {
app_lc = tolower(app)
return app_lc ~ /(mds|mdworker|corespotlight|spotlight)/
}
function set_best(score, message) {
if (score > best_score) {
best_score = score
best_message = message
}
}
{
if ($1 == "now") {
last_ts = $2; last_state = $3; last_issue = $4; last_load = $5; last_mem = $7; last_disk = $8; last_cpu_app = $10; last_cpu_pct = $11
next
}
first_ts = $2; first_state = $3; first_issue = $4; first_load = $5; first_mem = $7; first_disk = $8; first_cpu_app = $10; first_cpu_pct = $11
}
END {
if (!last_ts || !first_ts) {
print "Learning recent activity. First cause after the next refresh."
exit
}
minutes = int((last_ts - first_ts) / 60)
if (minutes < 1) minutes = 1
cpu_delta = 0
mem_delta = 0
disk_drop = 0
load_delta = 0
if (num(first_cpu_pct) && num(last_cpu_pct)) cpu_delta = last_cpu_pct - first_cpu_pct
if (num(first_mem) && num(last_mem)) mem_delta = last_mem - first_mem
if (num(first_disk) && num(last_disk)) disk_drop = first_disk - last_disk
if (num(first_load) && num(last_load)) load_delta = last_load - first_load
if (is_spotlight(last_cpu_app) && num(last_cpu_pct) && (last_cpu_pct >= 40 || load_delta >= 2 || last_state != "healthy")) {
set_best(260 + last_cpu_pct, sprintf("Spotlight indexing is now driving load (%s %.1f%% CPU) in %dm", last_cpu_app, last_cpu_pct, minutes))
}
if (!is_spotlight(last_cpu_app) && num(last_cpu_pct) && (last_cpu_pct >= high_cpu || cpu_delta >= 40 || (last_state == "critical" && last_cpu_pct >= 60))) {
if (first_cpu_app == last_cpu_app && num(first_cpu_pct)) {
set_best(220 + cpu_delta, sprintf("%s jumped from %.1f%% to %.1f%% CPU in %dm", last_cpu_app, first_cpu_pct, last_cpu_pct, minutes))
} else {
set_best(200 + last_cpu_pct + cpu_delta, sprintf("%s is now top CPU at %.1f%% after %s in %dm", last_cpu_app, last_cpu_pct, first_cpu_app, minutes))
}
}
if (mem_delta >= 15 && num(last_mem) && last_mem >= 70) {
set_best(170 + mem_delta, sprintf("Memory pressure rose from %.0f%% to %.0f%% in %dm", first_mem, last_mem, minutes))
}
if (disk_drop >= 4 || (num(last_disk) && last_disk < low_disk_warn && disk_drop >= 2)) {
set_best(150 + disk_drop, sprintf("Disk free dropped by %.1fGB in %dm", disk_drop, minutes))
}
if (load_delta >= load_warn) {
set_best(120 + load_delta, sprintf("Load rose from %.1f to %.1f in %dm", first_load, last_load, minutes))
}
if (first_state == "healthy" && last_state != "healthy") {
set_best(80, sprintf("Health changed from healthy to %s: %s", last_state, last_issue))
}
if (best_message != "") printf "%s", best_message
else printf "No clear change in the last %dm. Watching for a stronger trend.", minutes
}'
}
battery_line() {
pmset -g batt 2>/dev/null | grep -E 'InternalBattery|Battery Power|AC Power' | tail -1
}
battery_percent() {
battery_line | grep -Eo '[0-9]+%' | head -1 | tr -d '%'
}
battery_state() {
battery_line | grep -Eo 'discharging|charging|charged' | head -1
}
battery_remaining() {
battery_line | grep -Eo '[0-9]+:[0-9]+ remaining' | head -1 | sed 's/ remaining//'
}
cpu_temperature() {
if command_exists osx-cpu-temp; then
osx-cpu-temp -c 2>/dev/null | grep -Eo '[0-9.]+' | head -1
fi
}
top_issue() {
local load_int="$1"
local high_cpu="$2"
local disk_gb="$3"
local battery_pct="$4"
local temp="$5"
local temp_int
temp_int="$(integer_part "$temp")"
if [ "$high_cpu" -gt 0 ]; then
printf 'Busy app using too much CPU'
elif [ "$load_int" -ge "$LOAD_CRIT" ]; then
printf 'System load is very high'
elif is_number "$disk_gb" && [ "$disk_gb" -lt "$LOW_DISK_WARN_GB" ]; then
printf 'Low disk space'
elif is_number "$battery_pct" && [ "$battery_pct" -lt 20 ]; then
printf 'Low battery'
elif is_number "$temp_int" && [ "$temp_int" -gt 85 ]; then
printf 'CPU temperature is high'
elif [ "$load_int" -ge "$LOAD_WARN" ]; then
printf 'System load is rising'
else
printf 'No urgent issue'
fi
}
health_state() {
local load_int="$1"
local high_cpu="$2"
local disk_gb="$3"
local battery_pct="$4"
local temp="$5"
local temp_int
temp_int="$(integer_part "$temp")"
if [ "$high_cpu" -gt 0 ] || [ "$load_int" -ge "$LOAD_CRIT" ]; then
printf 'critical'
elif is_number "$temp_int" && [ "$temp_int" -gt 85 ]; then
printf 'critical'
elif is_number "$disk_gb" && [ "$disk_gb" -lt "$LOW_DISK_WARN_GB" ]; then
printf 'warning'
elif is_number "$battery_pct" && [ "$battery_pct" -lt 20 ]; then
printf 'warning'
elif [ "$load_int" -ge "$LOAD_WARN" ]; then
printf 'warning'
else
printf 'healthy'
fi
}
state_icon() {
case "$1" in
critical) printf '🔥' ;;
warning) printf 'âš¡' ;;
*) printf '✅' ;;
esac
}
state_color() {
case "$1" in
critical) critical_color ;;
warning) warning_color ;;
*) healthy_color ;;
esac
}
menu_animation_frame() {
local frame_index
frame_index=$(( ($(flight_recorder_now) / 5) % 6 ))
case "$frame_index" in
0) printf '·' ;;
1) printf 'â—¦' ;;
2) printf 'â—‹' ;;
3) printf 'â—‰' ;;
4) printf 'â—‹' ;;
*) printf 'â—¦' ;;
esac
}
menu_title() {
local state="$1"
local load="$2"
local high_cpu="$3"
local icon
icon="$(state_icon "$state")"
if [ "$high_cpu" -gt 0 ]; then
printf '%s %s' "$icon" "$high_cpu"
elif [ "$state" = "healthy" ]; then
if is_true "$ANIMATE_TITLE"; then
menu_animation_frame
else
printf 'SM'
fi
else
printf '%s %.1f' "$icon" "$load"
fi
}
truncate_label() {
local value="$1"
local max="${2:-40}"
if [ "${#value}" -gt "$max" ]; then
printf '%s...' "${value:0:$((max - 3))}"
else
printf '%s' "$value"
fi
}
process_learning_note() {
local app_name="$1"
local cmd="$2"
local lower
lower="$(printf '%s %s' "$app_name" "$cmd" | tr '[:upper:]' '[:lower:]')"
case "$lower" in
*windowserver*)
printf 'macOS compositor; spikes with redraws, external displays, or screen sharing.'
;;
*kernel_task*)
printf 'Kernel thermal guard; high CPU can reflect heat throttling, not a user app.'
;;
*mds_stores*|*mdworker_shared*|*mdworker*|*" mds "*)
printf 'Spotlight indexing; spikes after installs, file moves, or attaching drives.'
;;
*backupd-helper*|*backupd*)
printf 'Time Machine backup helper; spikes during backups or local snapshots.'
;;
*"--type=gpu-process"*|*"gpu)"*|*"helper (gpu"*)
printf 'GPU helper; spikes from video decode, WebGL, or accelerated rendering.'
;;
*"--type=renderer"*|*"renderer)"*|*"webview helper"*|*"webview"*)
printf 'Renderer/web content process; spikes from heavy pages, calls, or extensions.'
;;
*microsoft*teams*)
printf 'Teams web layer; spikes during calls, screen sharing, or animated chats.'
;;
*cursor*helper*|*cursor*)
printf 'Cursor editor process; spikes from extensions, AI panes, or large workspaces.'
;;
*google*chrome*|*chromium*)
printf 'Browser process; spikes from active tabs, video, extensions, or site scripts.'
;;
top*)
printf 'Sampling command itself; can appear briefly because the plugin is collecting data.'
;;
*node*)
printf 'Node.js runtime; often a dev server, build tool, watcher, or CLI task.'
;;
*python*|*jupyter*)
printf 'Python runtime; often a script, notebook, data task, or background worker.'
;;
*coreaudiod*)
printf 'macOS audio daemon; spikes with calls, device changes, or routing glitches.'
;;
*cloudd*)
printf 'iCloud sync daemon; spikes when files or photos are syncing.'
;;
*softwareupdated*)
printf 'macOS update service; spikes while checking, downloading, or preparing updates.'
;;
*photoanalysisd*|*photolibraryd*)
printf 'Photos analysis/indexing; spikes during library scans or background ML work.'
;;
*docker*|*orbstack*)
printf 'Container runtime work; spikes from builds, pulls, or active containers.'
;;
*helper*)
printf 'Helper process for a parent app; usage usually follows that app''s active work.'
;;
*)
printf ''
;;
esac
}
print_process_learning_hint() {
local indent="$1"
local app_name="$2"
local cmd="$3"
local note
note="$(process_learning_note "$app_name" "$cmd")"
[ -n "$note" ] || return 0
printf '%s%s | font=Menlo size=10 color=gray\n' "$indent" "$(truncate_label "$note" 92)"
}
print_process_list() {
local title="$1"
local sort_key="$2"
local metric_label="$3"
local metric_index="$4"
local indent="${5:---}"
local awk_script rows user pid metric app_name cmd
echo "$title"
awk_script="$(process_awk_helpers)
{
user = \$1
pid = \$2
metric = \$metric_index
cmd = sanitize_cmd(join_fields(11, NF))
app_name = app_name_from_cmd(cmd)
printf \"%s\\t%s\\t%.1f\\t%s\\t%s\\n\", user, pid, metric, app_name, cmd
}"
rows="$(printf '%s\n' "$PROCESS_SNAPSHOT" |
tail -n +2 |
sort -nrk "$sort_key" |
head -6 |
awk -v metric_index="$metric_index" "$awk_script")"
[ -n "$rows" ] || return 0
while IFS=$'\t' read -r user pid metric app_name cmd; do
printf '%s%s (%s %.1f%%) | font=Menlo size=11\n' "$indent" "$app_name" "$metric_label" "$metric"
print_process_learning_hint "${indent}--" "$app_name" "$cmd"
printf '%s--Copy PID: %s | bash="%s" param1="copy-pid" param2="%s" terminal=false refresh=false\n' "$indent" "$pid" "$PLUGIN_PATH" "$pid"
if [ "$user" = "$USER" ]; then
printf '%s--Stop Process | bash="/bin/kill" param1="%s" terminal=false refresh=true color=red\n' "$indent" "$pid"
else
printf '%s--Protected system process | color=gray\n' "$indent"
fi
done <<< "$rows"
}
print_high_cpu_processes() {
local awk_script rows user pid cpu app_name cmd
echo "Busy Apps"
awk_script="$(process_awk_helpers)
NR > 1 && \$3 > threshold {
user = \$1
pid = \$2
cpu = \$3
cmd = sanitize_cmd(join_fields(11, NF))
app_name = app_name_from_cmd(cmd)
printf \"%s\\t%s\\t%.1f\\t%s\\t%s\\n\", user, pid, cpu, app_name, cmd
}"
rows="$(printf '%s\n' "$PROCESS_SNAPSHOT" |
awk -v threshold="$HIGH_CPU_THRESHOLD" "$awk_script")"
if [ -z "$rows" ]; then
echo "--No busy apps detected | color=green"
return 0
fi
while IFS=$'\t' read -r user pid cpu app_name cmd; do
printf -- '--%s (%.1f%%) | color=red font=Menlo size=11\n' "$app_name" "$cpu"
print_process_learning_hint "----" "$app_name" "$cmd"
printf -- '----PID: %s | font=Menlo size=10 color=gray\n' "$pid"
if [ "$user" = "$USER" ]; then
echo "----Process Actions"
printf -- '------Stop Process | bash="/bin/kill" param1="%s" terminal=false refresh=true color=red\n' "$pid"
echo "------Potentially Disruptive"
printf -- '--------Force Kill (Immediate) | bash="/bin/kill" param1="-9" param2="%s" terminal=true refresh=true color=red\n' "$pid"
else
echo "----Protected system process | color=gray"
printf -- '----Open Activity Monitor | bash="%s" param1="open-activity-monitor" terminal=false\n' "$PLUGIN_PATH"
fi
done <<< "$rows"
}
health_label() {
case "$1" in
critical) printf 'Critical' ;;
warning) printf 'Needs attention' ;;
*) printf 'Good' ;;
esac
}
print_mac_health_summary() {
local state="$1"
local issue="$2"
local color="$3"
local model_name os_version uptime_info subtle
model_name="$(hardware_name)"
os_version="$(macos_version)"
uptime_info="$(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')"
subtle="$(secondary_color)"
echo "Mac Health: $(health_label "$state") | color=$color"
echo "--${model_name} · macOS ${os_version} | color=$subtle"
echo "--Uptime: ${uptime_info} | color=$subtle"
echo "--Current issue: ${issue} | color=$color"
}
print_recommendation() {
local load_int="$1"
local high_cpu="$2"
local disk_gb="$3"
local battery_pct="$4"
local temp="$5"
local temp_int
temp_int="$(integer_part "$temp")"
echo "---"
echo "Today's Recommendation"
if [ "$high_cpu" -gt 0 ]; then
echo "--Stop one confirmed busy app below | color=red"
echo "----Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
elif [ "$load_int" -ge "$LOAD_CRIT" ]; then
echo "--Check CPU before killing anything | color=red"
echo "----Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
elif is_number "$disk_gb" && [ "$disk_gb" -lt "$LOW_DISK_WARN_GB" ]; then
echo "--Free disk space | color=orange"
echo "----Empty Trash | bash=\"$PLUGIN_PATH\" param1=\"empty-trash\" terminal=false refresh=true"
elif is_number "$battery_pct" && [ "$battery_pct" -lt 20 ]; then
echo "--Connect power soon | color=orange"
elif is_number "$temp_int" && [ "$temp_int" -gt 85 ]; then
echo "--Let the Mac cool down | color=red"
echo "----Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
elif [ "$load_int" -ge "$LOAD_WARN" ]; then
echo "--Watch the trend | color=orange"
echo "----Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
else
echo "--No urgent action | color=green"
fi
}
print_flight_checkpoints() {
local lines subtle checkpoint_count
subtle="$(secondary_color)"
lines="$(flight_checkpoint_rows)"
if [ -z "$lines" ]; then
echo "--Recent activity | color=$subtle"
echo "----Confidence improves over 15 minutes | color=$subtle"
return 0
fi
checkpoint_count="$(printf '%s\n' "$lines" | awk 'END { print NR + 0 }')"
echo "--Recent activity | color=$subtle"
printf '%s\n' "$lines" |
awk -F '\t' -v subtle="$subtle" '{
printf "----%s: %s, load %s, CPU %s %.1f%% | font=Menlo size=11 color=%s\n", $1, $3, $5, $10, $11, subtle
}'
if [ "$checkpoint_count" -lt 4 ]; then
echo "----Confidence improves over 15 minutes | color=$subtle"
fi
}
print_next_step() {
local load_int="$1"
local high_cpu="$2"
local disk_gb="$3"
local battery_pct="$4"
local temp="$5"
local temp_int
temp_int="$(integer_part "$temp")"
if [ "$high_cpu" -gt 0 ] || [ "$load_int" -ge "$LOAD_CRIT" ]; then
echo "--Next step: Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
elif is_number "$temp_int" && [ "$temp_int" -gt 85 ]; then
echo "--Next step: Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
elif is_number "$disk_gb" && [ "$disk_gb" -lt "$LOW_DISK_WARN_GB" ]; then
echo "--Next step: Review disk usage and free space | color=$(warning_color)"
elif is_number "$battery_pct" && [ "$battery_pct" -lt 20 ]; then
echo "--Next step: Connect power soon | color=$(warning_color)"
elif [ "$load_int" -ge "$LOAD_WARN" ]; then
echo "--Next step: Monitor CPU trend | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
else
echo "--Next step: No urgent action | color=$(healthy_color)"
fi
}
print_alert_rules() {
local subtle
subtle="$(secondary_color)"
echo "--How alerts work | color=$subtle"
echo "----Busy app: >=${HIGH_CPU_THRESHOLD}% CPU | color=$subtle"
echo "----Load: warning >=${LOAD_WARN}, critical >=${LOAD_CRIT} | color=$subtle"
echo "----Disk: warning <${LOW_DISK_WARN_GB}GB free | color=$subtle"
echo "----Battery: warning <20% | color=$subtle"
echo "----Temperature: critical >85°C | color=$subtle"
}
print_triage_summary() {
local state="$1"
local issue="$2"
local color="$3"
local load_int="$4"
local high_cpu="$5"
local disk_gb="$6"
local battery_pct="$7"
local temp="$8"
local cause
cause="$(detect_incident_cause)"
echo "---"
echo "Triage"
echo "--Status: $(health_label "$state") - ${issue} | color=$color"
echo "--Likely cause: ${cause}"
print_next_step "$load_int" "$high_cpu" "$disk_gb" "$battery_pct" "$temp"
echo "--Copy Incident Report | bash=\"$PLUGIN_PATH\" param1=\"diagnostic\" terminal=false refresh=false"
print_alert_rules
print_flight_checkpoints
}
print_flight_report() {
local now lines
now="$(flight_recorder_now)"
lines="$(valid_flight_history | tail -10)"
echo
echo "Flight Recorder:"
echo "Detected cause: $(detect_incident_cause)"
if [ -z "$lines" ]; then
echo "History: learning recent activity"
return 0
fi
echo "Recent snapshots:"
printf '%s\n' "$lines" |
awk -F '\t' -v now="$now" '{
age = now - $1
if (age < 60) label = "now"
else label = int(age / 60) "m ago"
printf " - %s | %s | load %s | mem %s%% | disk %sGB | CPU %s %.1f%%\n", label, $2, $4, $6, $7, $9, $10
}'
}
print_resource_overview() {
local load1="$1"
local high_cpu="$2"
local mem_gb="$3"
local disk_human="$4"
local disk_gb="$5"
local batt_pct="$6"
local temp="$7"
local mem_pressure batt_state batt_remaining net_rates disk_color batt_color temp_int wifi_details wifi_ssid wifi_channel wifi_security wifi_signal wifi_rate wifi_mode wifi_type wifi_ip wifi_router vpn_state subtle
mem_pressure="$(memory_pressure_percent)"
batt_state="$(battery_state)"
batt_remaining="$(battery_remaining)"
net_rates="$(network_rates)"
wifi_details="$(wifi_current_details 2>/dev/null || true)"
IFS='|' read -r wifi_ssid wifi_channel wifi_security wifi_signal wifi_rate wifi_mode wifi_type wifi_endpoint < 20) color = \"orange\"
else if (power_int > 5) color = \"yellow\"
else color = \"green\"
printf \"--%s (%.1f) | font=Menlo size=11 color=%s\\n\", app_name, power, color
printf \"----PID: %s | font=Menlo size=10 color=gray\\n\", pid
printf \"----Open Activity Monitor | bash=\\\"%s\\\" param1=\\\"open-activity-monitor\\\" terminal=false\\n\", plugin_path
}"
top -l 2 -o power -stats pid,command,power -n 6 2>/dev/null |
tail -6 |
awk -v plugin_path="$PLUGIN_PATH" "$awk_script"
fi
}
print_health_section() {
local temp temp_int batt_pct batt_state batt_remaining fan_speed uptime_info subtle
subtle="$(secondary_color)"
echo "Health"
temp="$(cpu_temperature)"
temp_int="$(integer_part "$temp")"
if is_number "$temp_int" && [ "$temp_int" -gt 0 ]; then
if [ "$temp_int" -gt 85 ]; then
echo "--CPU Temp: ${temp}°C | color=red"
elif [ "$temp_int" -gt 70 ]; then
echo "--CPU Temp: ${temp}°C | color=orange"
else
echo "--CPU Temp: ${temp}°C | color=green"
fi
else
echo "--CPU Temp: Not available | color=$subtle"
fi
batt_pct="$(battery_percent)"
batt_state="$(battery_state)"
batt_remaining="$(battery_remaining)"
if is_number "$batt_pct"; then
if [ "$batt_state" = "charging" ]; then
echo "--Battery: ${batt_pct}% (Charging)"
elif [ "$batt_state" = "charged" ]; then
echo "--Battery: ${batt_pct}% (Charged)"
elif [ -n "$batt_remaining" ]; then
echo "--Battery: ${batt_pct}% (${batt_remaining} left)"
elif [ "$batt_pct" -lt 20 ]; then
echo "--Battery: ${batt_pct}% | color=red"
elif [ "$batt_pct" -lt 50 ]; then
echo "--Battery: ${batt_pct}% | color=orange"
else
echo "--Battery: ${batt_pct}% | color=green"
fi
else
echo "--Battery: Desktop (No battery) | color=$subtle"
fi
if command_exists istats; then
fan_speed="$(istats fan speed 2>/dev/null | grep -Eo '[0-9]+ RPM' | head -1)"
[ -n "$fan_speed" ] && echo "--Fan: $fan_speed | color=$subtle"
fi
uptime_info="$(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')"
echo "--Uptime: $uptime_info | color=$subtle"
}
print_devices_section() {
local displays display_lines usb_devices bt_devices network_list device battery_pct battery_color ip_addr subtle
is_true "$SHOW_DEVICES" || return 0
subtle="$(secondary_color)"
echo "---"
echo "Devices"
echo "--Displays:"
displays="$(cached_command displays "$SLOW_CACHE_TTL_SECONDS" /usr/sbin/system_profiler SPDisplaysDataType)"
display_lines="$(printf '%s\n' "$displays" | awk '
/^[[:space:]]+[A-Za-z].*:$/ && !/Displays:|GPU|Chipset|Type:|Bus:|Cores:|Vendor:|Metal|Mirror:|Online:|Rotation:|Automatically|Connection Type:|UI Looks/ {
display_name = $0
gsub(/^[[:space:]]+/, "", display_name)
gsub(/:$/, "", display_name)
getline
if (/Resolution:/) {
resolution = $0
gsub(/^[[:space:]]+Resolution:[[:space:]]*/, "", resolution)
is_builtin = 0
while (getline > 0) {
if (/Connection Type: Internal/ || /Display Type:.*Built-in/) is_builtin = 1
if (/^[[:space:]]+[A-Za-z].*:$/ && !/Mirror:|Online:|Rotation:|Automatically|Connection Type:|UI Looks|Main Display/) break
}
type = is_builtin ? "Built-in" : "External"
printf "----%s (%s): %s | font=Menlo size=10\n", display_name, type, resolution
}
}')"
if [ -n "$display_lines" ]; then
printf '%s\n' "$display_lines"
else
echo "----No display details available | font=Menlo size=10 color=$subtle"
fi
echo "--USB Devices:"
usb_devices="$(cached_command usb "$SLOW_CACHE_TTL_SECONDS" /usr/sbin/system_profiler SPUSBDataType |
grep -v 'Apple\|Bluetooth\|Hub\|Host Controller' |
grep 'Product ID:' -B 1 |
grep -v 'Product ID\|--' |
sed 's/^[[:space:]]*//' |
head -5)"
if [ -n "$usb_devices" ]; then
printf '%s\n' "$usb_devices" | while IFS= read -r device; do
echo "----${device} | font=Menlo size=10"
done
else
echo "----None detected | font=Menlo size=10 color=$subtle"
fi
echo "--Bluetooth:"
bt_devices="$(cached_command bluetooth "$SLOW_CACHE_TTL_SECONDS" /usr/sbin/system_profiler SPBluetoothDataType |
awk '
/^[[:space:]]+Connected:[[:space:]]*$/ { in_connected = 1; next }
/^[[:space:]]+Not Connected:[[:space:]]*$/ { in_connected = 0; next }
in_connected && /^[[:space:]]+[A-Za-z0-9]/ && /:$/ {
gsub(/^[[:space:]]+/, "")
gsub(/:$/, "")
print
}' |
head -5)"
if [ -n "$bt_devices" ]; then
printf '%s\n' "$bt_devices" | while IFS= read -r device; do
battery_pct="$(ioreg -r -l 2>/dev/null | grep -A 20 "\"$device\"" | grep -Ei 'BatteryPercent|batterylevel' | head -1 | grep -Eo '[0-9]+' | head -1)"
if is_number "$battery_pct"; then
if [ "$battery_pct" -lt 20 ]; then
battery_color="red"
elif [ "$battery_pct" -lt 50 ]; then
battery_color="orange"
else
battery_color="green"
fi
echo "----${device} (Battery ${battery_pct}%) | font=Menlo size=10 color=$battery_color"
else
echo "----${device} | font=Menlo size=10"
fi
done
else
echo "----No devices connected | font=Menlo size=10 color=$subtle"
fi
echo "--Network:"
network_list="$(ifconfig -a 2>/dev/null | awk '/inet / && $2 != "127.0.0.1" {print $2}')"
if [ -n "$network_list" ]; then
printf '%s\n' "$network_list" | while IFS= read -r ip_addr; do
echo "----IP: ${ip_addr} | font=Menlo size=10"
done
else
echo "----No active connections | font=Menlo size=10 color=$subtle"
fi
}
print_system_alerts() {
local updates_available app_store_running icloud_drive mds_active
is_true "$SHOW_SYSTEM_ALERTS" || return 0
echo "---"
echo "Signals"
if is_true "$CHECK_SOFTWARE_UPDATES"; then
updates_available="$(cached_command softwareupdate 3600 /usr/sbin/softwareupdate -l | grep -c '^\*' || true)"
if [ "$updates_available" -gt 0 ]; then
echo "--System Updates: ${updates_available} available | color=orange"
echo "----Open Software Update | bash=\"/usr/bin/open\" param1=\"x-apple.systempreferences:com.apple.preferences.softwareupdate\" terminal=false"
else
echo "--System Updates: Up to date | color=green"
fi
else
:
fi
app_store_running="$(pgrep -fl 'Software Update' 2>/dev/null | wc -l | tr -d '[:space:]')"
[ "$app_store_running" -gt 0 ] && echo "--Background updates in progress | color=blue"
if pgrep -x bird >/dev/null 2>&1; then
icloud_drive="Active"
echo "--iCloud Drive: $icloud_drive | color=green"
else
icloud_drive="Inactive"
echo "--iCloud Drive: $icloud_drive | color=gray"
fi
mds_active="$(printf '%s\n' "$PROCESS_SNAPSHOT" | awk '$11 ~ /mds_stores/ && $3 > 10 { count++ } END { print count + 0 }')"
[ "$mds_active" -gt 0 ] && echo "--Spotlight: Indexing active | color=orange"
}
print_docker_section() {
local running_containers stopped_containers stats cpu mem display_name name
is_true "$SHOW_DOCKER" || return 0
pgrep -x OrbStack >/dev/null 2>&1 || return 0
echo "---"
echo "Containers (OrbStack)"
if ! command_exists docker || ! docker info >/dev/null 2>&1; then
echo "--Docker not available | color=gray"
return 0
fi
running_containers="$(docker ps --format '{{.Names}}' 2>/dev/null | wc -l | tr -d '[:space:]')"
if [ "$running_containers" -gt 0 ]; then
echo "--Running: ${running_containers} containers | color=green"
docker ps --format '{{.Names}}' 2>/dev/null | head -5 | while IFS= read -r name; do
display_name="$(truncate_label "$name" 25)"
echo "----${display_name} | font=Menlo size=10"
if is_true "$SHOW_DOCKER_STATS"; then
stats="$(docker stats "$name" --no-stream --format '{{.CPUPerc}} {{.MemUsage}}' 2>/dev/null || true)"
cpu="$(printf '%s' "$stats" | awk '{print $1}')"
mem="$(printf '%s' "$stats" | awk '{print $2}')"
[ -n "$cpu" ] && echo "------CPU: ${cpu}, Mem: ${mem} | font=Menlo size=9 color=gray"
fi
echo "------Stop | bash=\"$(command -v docker)\" param1=\"stop\" param2=\"$name\" terminal=false refresh=true"
echo "------Restart | bash=\"$(command -v docker)\" param1=\"restart\" param2=\"$name\" terminal=false refresh=true"
echo "------Logs | bash=\"$(command -v docker)\" param1=\"logs\" param2=\"$name\" param3=\"--tail\" param4=\"50\" terminal=true"
done
else
echo "--No containers running | color=gray"
fi
stopped_containers="$(docker ps -a --filter status=exited --format '{{.Names}}' 2>/dev/null | wc -l | tr -d '[:space:]')"
[ "$stopped_containers" -gt 0 ] && echo "--Stopped: ${stopped_containers} containers | color=gray"
echo "--Cleanup actions moved to Actions > Potentially Disruptive | color=gray"
}
print_safe_action_center() {
echo "---"
echo "About"
echo "--System Monitor v$PLUGIN_VERSION | color=gray"
print_plugin_update_notice
print_update_status_line
echo "----Update from GitHub | bash=\"$PLUGIN_PATH\" param1=\"update-from-github\" terminal=false refresh=false"
echo "--Repository: @$AUTHOR_GITHUB/swiftbar-plugins | href=\"$REPO_URL\""
echo "---"
echo "Actions"
echo "--Quick Actions"
echo "----Open Activity Monitor | bash=\"$PLUGIN_PATH\" param1=\"open-activity-monitor\" terminal=false"
echo "----Copy Diagnostic Report | bash=\"$PLUGIN_PATH\" param1=\"diagnostic\" terminal=false refresh=false"
echo "----Open Console (Logs) | bash=\"$PLUGIN_PATH\" param1=\"open-console\" terminal=false"
echo "----Open System Settings | bash=\"$PLUGIN_PATH\" param1=\"open-system-settings\" terminal=false"
echo "--Potentially Disruptive | color=orange"
echo "----Empty Trash (Permanent) | bash=\"$PLUGIN_PATH\" param1=\"empty-trash\" terminal=false refresh=true color=orange"
echo "----Clear Memory Cache (Requires sudo) | bash=\"$PLUGIN_PATH\" param1=\"purge-memory\" terminal=true refresh=true color=orange"
echo "----Restart Spotlight Index (Rebuilds search index) | bash=\"$PLUGIN_PATH\" param1=\"restart-spotlight\" terminal=true refresh=true color=orange"
if command_exists docker; then
echo "----Prune Docker System (Removes unused images and volumes) | bash=\"$(command -v docker)\" param1=\"system\" param2=\"prune\" param3=\"-af\" param4=\"--volumes\" terminal=true refresh=true color=red"
fi
echo "---"
echo "Refresh | refresh=true"
}
open_app() {
/usr/bin/open -a "$1" >/dev/null 2>&1
}
copy_pid() {
local pid="${1:-}"
case "$pid" in
''|*[!0-9]*)
printf 'Invalid PID: %s\n' "$pid" >&2
return 1
;;
esac
if ! command_exists pbcopy; then
printf 'pbcopy is required to copy the PID.\n' >&2
return 1
fi
printf '%s' "$pid" | pbcopy
if command_exists osascript; then
osascript -e "display notification \"PID ${pid} copied to clipboard\" with title \"System Monitor\"" >/dev/null 2>&1 || true
fi
}
empty_trash() {
/usr/bin/osascript -e 'tell application "Finder" to delete every item of trash' >/dev/null 2>&1
}
purge_memory() {
/usr/bin/sudo /usr/sbin/purge
}
restart_spotlight() {
/usr/bin/sudo /usr/bin/mdutil -E /
}
update_plugin_from_github() {
local checkout_dir tmp url new_version
if checkout_dir="$(official_checkout_dir)"; then
if ! git -C "$checkout_dir" pull --ff-only; then
write_plugin_update_status "failure" "" "Git update failed. Resolve local checkout state and try again."
printf 'Git update failed. Resolve local checkout state and try again.\n' >&2
return 1
fi
new_version="$(installed_plugin_version)"
write_plugin_update_status "success" "${new_version:-latest}" "Updated to v${new_version:-latest} from GitHub."
printf 'Updated System Monitor to %s from GitHub.\n' "${new_version:-latest}"
return 0
fi
if ! command_exists curl; then
write_plugin_update_status "failure" "" "curl is required to update this plugin from GitHub."
printf 'curl is required to update this plugin from GitHub.\n' >&2
return 1
fi
url="$(plugin_update_url)"
tmp="$(mktemp "${TMPDIR:-/tmp}/swiftbar-system-monitor-update.XXXXXX")" || return 1
if ! download_plugin_update "$url" "$tmp"; then
rm -f "$tmp"
write_plugin_update_status "failure" "" "Failed to download the latest plugin from GitHub."
printf 'Failed to download the latest plugin from GitHub.\n' >&2
return 1
fi
if ! validate_downloaded_plugin "$tmp"; then
rm -f "$tmp"
write_plugin_update_status "failure" "" "Downloaded file did not look like a valid System Monitor plugin."
printf 'Downloaded file did not look like a valid System Monitor plugin.\n' >&2
return 1
fi
if ! chmod +x "$tmp"; then
rm -f "$tmp"
write_plugin_update_status "failure" "" "Failed to mark the downloaded plugin as executable."
printf 'Failed to mark the downloaded plugin as executable.\n' >&2
return 1
fi
if ! mv "$tmp" "$PLUGIN_PATH"; then
rm -f "$tmp"
write_plugin_update_status "failure" "" "Failed to install the updated plugin."
printf 'Failed to install the updated plugin at %s.\n' "$PLUGIN_PATH" >&2
return 1
fi
new_version="$(installed_plugin_version)"
write_plugin_update_status "success" "${new_version:-latest}" "Updated to v${new_version:-latest} from GitHub."
printf 'Updated System Monitor to %s from GitHub.\n' "${new_version:-latest}"
}
perform_background_update_from_github() {
local output message
if output="$(update_plugin_from_github 2>&1)"; then
message="$(printf '%s' "$output" | tail -1)"
[ -n "$message" ] || message="Updated from GitHub."
notify_update_result "System Monitor Updated" "$message"
else
message="$(printf '%s' "$output" | tail -1)"
[ -n "$message" ] || message="Update failed."
notify_update_result "System Monitor Update Failed" "$message"
fi
refresh_plugin_menu
}
queue_background_update_from_github() {
write_plugin_update_status "pending" "$PLUGIN_VERSION" "Updating from GitHub in the background..."
refresh_plugin_menu
nohup "$PLUGIN_PATH" perform-update-from-github >/dev/null 2>&1 &
}
copy_diagnostic_report() {
local report
report="$(mktemp "${TMPDIR:-/tmp}/swiftbar-system-monitor.XXXXXX")"
{
echo "SwiftBar System Monitor Diagnostic"
echo "Version: $PLUGIN_VERSION"
echo "Author GitHub: @$AUTHOR_GITHUB"
echo "Repository: $REPO_URL"
echo "Generated: $(date)"
echo "Host: $(hostname)"
echo "macOS: $(sw_vers -productVersion 2>/dev/null || echo unknown)"
echo "Load: $(load_average)"
echo "Busy apps: $(high_cpu_count)"
echo "Memory compressed: $(memory_compressed_gb)GB"
echo "Disk available: $(disk_available_human)"
echo "Battery: $(battery_percent 2>/dev/null || echo desktop)% $(battery_state 2>/dev/null || true)"
print_flight_report
echo
echo "Top CPU:"
ps aux | sort -nrk 3 | head -6
echo
echo "Top Memory:"
ps aux | sort -nrk 4 | head -6
} >"$report"
if command_exists pbcopy; then
pbcopy <"$report"
fi
open -R "$report" >/dev/null 2>&1 || true
}
render_menu() {
local load1 load_int mem_gb disk_human disk_gb high_cpu batt_pct temp state issue color title_color
load1="$(load_average)"
PROCESS_SNAPSHOT="$(ps aux)"
load_int="$(integer_part "$load1")"
is_number "$load_int" || load_int="0"
mem_gb="$(memory_compressed_gb)"
disk_human="$(disk_available_human)"
disk_gb="$(disk_available_gb)"
high_cpu="$(high_cpu_count)"
batt_pct="$(battery_percent)"
temp="$(cpu_temperature)"
state="$(health_state "$load_int" "$high_cpu" "$disk_gb" "$batt_pct" "$temp")"
issue="$(top_issue "$load_int" "$high_cpu" "$disk_gb" "$batt_pct" "$temp")"
color="$(state_color "$state")"
title_color="$color"
if [ "$state" = "healthy" ] && [ "$high_cpu" -eq 0 ] && ! is_true "$ANIMATE_TITLE"; then
title_color="$(secondary_color)"
fi
record_flight_snapshot "$state" "$issue" "$load1" "$high_cpu" "$disk_gb" "$batt_pct"
echo "$(menu_title "$state" "$load1" "$high_cpu") | color=$title_color tooltip=\"$issue. Load: $load1. Busy apps: $high_cpu.\""
print_triage_summary "$state" "$issue" "$color" "$load_int" "$high_cpu" "$disk_gb" "$batt_pct" "$temp"
print_resource_overview "$load1" "$high_cpu" "$mem_gb" "$disk_human" "$disk_gb" "$batt_pct" "$temp"
print_high_cpu_processes
print_energy_impact
echo "---"
print_health_section
print_devices_section
print_system_alerts
print_docker_section
echo "---"
echo "Advanced"
print_process_list "--Top CPU" "3" "CPU" "3" "----"
print_process_list "--Top Memory" "4" "MEM" "4" "----"
print_safe_action_center
}
main() {
load_config
case "${1:-}" in
version|--version|-v)
echo "$PLUGIN_VERSION"
;;
diagnostic)
copy_diagnostic_report
;;
copy-pid)
copy_pid "${2:-}"
;;
open-activity-monitor)
open_app "Activity Monitor"
;;
open-console)
open_app "Console"
;;
open-system-settings)
open_app "System Settings"
;;
update-from-github)
queue_background_update_from_github
;;
perform-update-from-github)
perform_background_update_from_github
;;
empty-trash)
empty_trash
;;
purge-memory)
purge_memory
;;
restart-spotlight)
restart_spotlight
;;
*)
render_menu
;;
esac
}
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
main "$@"
fi