Files
claudetools/.claude/skills/unifi-wifi/scripts/sites.sh
Howard Enos e1031ae91a unifi-wifi: skill health pass — fix optimize-radios stray REPL echo + ASCII-clean all output
Full verification of the skill against Cascades (live):
- All 19 scripts syntax-clean.
- Controller-side read-only validated live: sites, audit-site, switch-audit, live-stats, model-rank,
  optimize-radios, monitor-run, gw-audit. Dry-run apply paths validated: apply-radio, apply-wlan,
  client-control, device-control. AP-side mechanism validated: SSH auth + /proc/ui_neighbor read on a
  sample AP; full neighbor-collect (74-AP SNR sweep) -> channel-plan end-to-end produced a 1/6/11 plan.

Fixes:
- optimize-radios.sh: the `for(k in prof)` loop's numeric completion value was REPL-echoed by the legacy
  mongo shell (stray "94.56..." line in output). Terminated the loop body with `void 0` to suppress it.
- ASCII-clean printed output (CLAUDE.md no-non-ASCII): replaced em-dashes / Unicode arrows / § that
  reached stdout and rendered as `?`/mojibake on the Windows console, across optimize-radios,
  neighbor-collect, survey-collect, dfs-check, audit-site, sites, monitor-run, apply-radio, apply-wlan,
  pfsense-backend. (Comment-only non-ASCII left as-is; never printed.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:08:35 -07:00

53 lines
3.3 KiB
Bash

#!/usr/bin/env bash
# sites.sh — fleet overview of every UniFi site on the UOS controller + per-site skill readiness.
# The entry point for "what clients can I run this on". Controller-side scripts (audit-site,
# live-stats, model-rank, optimize-radios, apply-radio) work on ANY site with ZERO per-client setup
# (they use the shared controller creds). The AP-side collectors (neighbor-collect, survey-collect,
# dfs-check, watch-ap) additionally need that client's AP device-auth cred vaulted + L3 reach (VPN).
#
# Usage: bash .claude/skills/unifi-wifi/scripts/sites.sh [--ap-cred-glob 'clients/*/unifi-ap-ssh']
set -uo pipefail
REPO="$(git rev-parse --show-toplevel 2>/dev/null || echo .)"
UOS="$REPO/.claude/scripts/uos-mongo.sh"
VROOT="${VAULT_ROOT:-$(jq -r '.vault_path // empty' "$REPO/.claude/identity.json" 2>/dev/null)}"
[ -n "$VROOT" ] || VROOT="$REPO/../vault"
echo "[INFO] UniFi sites on the UOS controller (controller-side scripts work on ALL of these now):"
cat <<'JS' | bash "$UOS" 2>&1 | grep -viE 'WARNING|post-quantum|store now|upgraded|openssh'
var sites={};
db.site.find({},{name:1,desc:1}).forEach(function(s){ sites[s._id.str]={name:(s.desc||s.name),short:s.name,ap:0,sw:0,gw:0}; });
db.device.find({},{site_id:1,type:1}).forEach(function(d){ var s=sites[d.site_id]; if(!s)return;
if(d.type=='uap')s.ap++; else if(d.type=='usw')s.sw++; else if(d.type=='ugw'||d.type=='uxg'||d.type=='udm')s.gw++; });
function pad(v,n){var s=String(v);while(s.length<n)s=' '+s;return s;} // old mongo JS has no padStart
var rows=Object.keys(sites).map(function(id){var s=sites[id];return [id,s];}).sort(function(a,b){return b[1].ap-a[1].ap;});
print("");
print("site_id APs SW GW name");
print("------------------------- --- -- -- ----");
rows.forEach(function(r){ var s=r[1];
print(r[0]+" "+pad(s.ap,3)+" "+pad(s.sw,2)+" "+pad(s.gw,2)+" "+s.name);
});
print("\n# "+rows.length+" sites. Run any controller-side script with the site name/desc or id, e.g.:");
print("# bash .claude/skills/unifi-wifi/scripts/audit-site.sh <name|id>");
JS
# AP-side readiness: which clients have an AP device-auth cred vaulted (clients/<x>/unifi-ap-ssh)
echo ""
echo "[INFO] AP-side collectors (neighbor/survey/dfs/watch-ap) need a per-client AP device-auth cred."
echo " Vaulted AP creds found (clients/*/unifi-ap-ssh):"
if [ -d "$VROOT" ]; then
found=$(find "$VROOT/clients" -name 'unifi-ap-ssh.sops.yaml' 2>/dev/null | sed -E 's#.*/clients/([^/]+)/.*# [ready] clients/\1/unifi-ap-ssh#' | sort)
[ -n "$found" ] && echo "$found" || echo " (none yet - only the controller-side scripts will work until you vault one)"
else
echo " (vault not found at $VROOT - set VAULT_ROOT)"
fi
cat <<'EOF'
To enable AP-side collectors for a new client:
1) get that site's Device Authentication user/pass (UniFi OS -> Settings -> System ->
Device Authentication, per site) + L3 reach to its AP mgmt VLAN (site VPN/route).
2) bash .claude/skills/vault/scripts/vault-helper.sh new clients/<slug>/unifi-ap-ssh \
--kind generic --name '<Client> UniFi AP device-auth SSH' --tag unifi \
--set username=<u> --set password=<pw>
3) pass it as the script's vault-path arg, e.g.:
bash .../neighbor-collect.sh <site> clients/<slug>/unifi-ap-ssh
EOF