summaryrefslogtreecommitdiff
path: root/skills/pi-subagent/status.sh
diff options
context:
space:
mode:
Diffstat (limited to 'skills/pi-subagent/status.sh')
-rwxr-xr-xskills/pi-subagent/status.sh85
1 files changed, 85 insertions, 0 deletions
diff --git a/skills/pi-subagent/status.sh b/skills/pi-subagent/status.sh
new file mode 100755
index 0000000..15a75de
--- /dev/null
+++ b/skills/pi-subagent/status.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# Report on the subagents of one workdir: what is still running, and the
+# cost table of everything that finished, failed attempts included.
+#
+# status.sh <workdir> report once
+# status.sh --wait [secs] <workdir> report every <secs> (default 60) until
+# nothing is running, then the table
+#
+# Exit status: 0 when nothing is running, 3 while something still is.
+#
+# "Running" means <workdir>/out/<name>.running exists and its PID is alive. A
+# marker whose process is gone (run-agent.sh was killed) is reported as stale
+# and removed.
+
+set -u
+
+wait=""; interval=60
+if [[ "${1:-}" == "--wait" ]]
+then
+ wait=y; shift
+ if [[ "${1:-}" =~ ^[0-9]+$ ]]; then interval="$1"; shift; fi
+fi
+P="${1:?workdir}"
+out="$P/out"
+
+running() {
+ local marker pid alive=()
+ for marker in "$out"/*.running
+ do
+ [[ -e "$marker" ]] || continue
+ pid="$(cat "$marker" 2>/dev/null)"
+ if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null
+ then
+ alive+=("$(basename "$marker" .running)")
+ else
+ echo "stale: $(basename "$marker" .running) (process gone)" >&2
+ rm -f "$marker"
+ fi
+ done
+ echo "${alive[*]:-}"
+}
+
+free_gb() {
+ df -k "$P" | awk 'NR==2 {printf "%.1f", $4/1048576}'
+}
+
+if [[ -n "$wait" ]]
+then
+ while :
+ do
+ names="$(running)"
+ [[ -z "$names" ]] && break
+ echo "$(date +%H:%M:%S) running=$(wc -w <<< "$names" | tr -d ' ') freeGB=$(free_gb): $names"
+ sleep "$interval"
+ done
+fi
+
+names="$(running)"
+if [[ -n "$names" ]]
+then
+ echo "running: $names"
+fi
+
+shopt -s nullglob
+costs=("$out"/*.cost.json)
+if [[ ${#costs[@]} -gt 0 ]]
+then
+ {
+ echo -e "name\tprovider\tmodel\texit\tstop\tsecs\tturns\tin\tout\tanswer_bytes\tcost"
+ for f in "${costs[@]}"
+ do
+ n="$(basename "$f" .cost.json)"
+ bytes=0
+ [[ -e "$out/$n.md" ]] && bytes="$(wc -c < "$out/$n.md" | tr -d '[:space:]')"
+ jq -r --arg b "$bytes" '[.name,.provider,.model,(.exit|tostring),(.stopReason // "-"),(.seconds|tostring),
+ (.turns|tostring),(.input|tostring),(.output|tostring),$b,
+ (.cost*10000|round/10000|tostring)] | @tsv' "$f" 2>/dev/null \
+ || echo -e "$n\t?\t?\t?\t?\t?\t?\t?\t?\t$bytes\t(unreadable cost file)"
+ done | sort -t$'\t' -k11 -rn
+ } | column -t -s$'\t'
+ jq -s -r '"runs: \(length) failed: \(map(select(.exit != 0)) | length) total cost: $\(map(.cost) | add | .*10000 | round/10000)"' \
+ "${costs[@]}" 2>/dev/null
+fi
+
+[[ -z "$names" ]] || exit 3