#!/usr/bin/env bash
# Continuously deprioritize dev-build/test processes so interactive work
# (claude agents, terminals, desktop, calls) always wins CPU + IO.
# renice/ionice ONLY — never kills, never moves cgroups → cannot OOM or break a build.
# Selector = build/test toolchain; hard-excludes interactive, dev-servers, language servers.
set -uo pipefail

# Confine: build/test SUBCOMMANDS + toolchain leaves (NOT dev/preview/serve — those are live servers).
ALLOW='node_modules/\.bin/|(astro|vite|next|nuxt)[^ ]* (build|check)|vitest|jest|playwright|esbuild|rollup|webpack|rspack|parcel|turbo|drizzle-kit|tsc\b|workerd|wrangler|write-build-info|chromium|headless_shell|(pnpm|npm|yarn)[^ ]* (run )?(build|test|typecheck|lint|gate|vitest|check)'
# Never touch: interactive, desktop, VMs, language servers, live dev/preview servers.
DENY='claude|cursor-agent|ccr|harnessd|dead-advisor|agent.?guard|discord|firefox|chrome|cinnamon|gnome-shell|gnome-terminal|Xorg|Xwayland|pipewire|wireplumber|qemu|virt-manager|/lib/systemd|systemd --user|dbus|tsserver|typingsInstaller|(astro|vite|next|nuxt|serve)[^ ]* (dev|preview|serve|start)'

# Builtin matching: a forked `grep` per process would cost ~2 forks x ~900 procs
# every 20s, which is itself a heavier load than the sweep removes.
shopt -s nocasematch

n=0
while read -r pid rest; do
  [ -z "$pid" ] && continue
  [[ $rest =~ $DENY ]] && continue
  [[ $rest =~ $ALLOW ]] || continue
  [ "$(ps -o ni= -p "$pid" 2>/dev/null | tr -d ' ')" = "19" ] && continue
  renice +19 -p "$pid" >/dev/null 2>&1 && ionice -c3 -p "$pid" 2>/dev/null && n=$((n+1))
done < <(ps -eo pid,args --no-headers)

[ "$n" -gt 0 ] && printf '%s deprioritized %d build proc(s)\n' "$(date -Is)" "$n" >> "$HOME/.claude/run/build-nice-sweep.log"
exit 0
