← back to AbramsEgo
build-loop: portable perl-alarm timeout fallback (macOS lacks timeout/gtimeout) + real PIPESTATUS rc
dd646ce2a97e10ce0f10eba80d1dd39c96917b9b · 2026-07-01 10:20:48 -0700 · Steve (AbramsEgo)
Files touched
A build-queue/STOPM scripts/build-loop.sh
Diff
commit dd646ce2a97e10ce0f10eba80d1dd39c96917b9b
Author: Steve (AbramsEgo) <steve@designerwallcoverings.com>
Date: Wed Jul 1 10:20:48 2026 -0700
build-loop: portable perl-alarm timeout fallback (macOS lacks timeout/gtimeout) + real PIPESTATUS rc
---
build-queue/STOP | 0
scripts/build-loop.sh | 13 +++++++++++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/build-queue/STOP b/build-queue/STOP
new file mode 100644
index 0000000..e69de29
diff --git a/scripts/build-loop.sh b/scripts/build-loop.sh
index 5f877f2..61c453e 100755
--- a/scripts/build-loop.sh
+++ b/scripts/build-loop.sh
@@ -22,6 +22,13 @@ MODEL="${ABRAMSEGO_MODEL:-claude-opus-4-8}"
MAX_TURNS="${MAX_TURNS:-40}"
PER_TASK_TIMEOUT="${PER_TASK_TIMEOUT:-900}" # 15 min hard budget per task
COOLDOWN="${COOLDOWN:-20}"
+
+# portable hard-timeout: GNU timeout / gtimeout / perl-alarm fallback (macOS has none of the first two)
+if command -v timeout >/dev/null 2>&1; then RUN(){ timeout "$PER_TASK_TIMEOUT" "$@"; }
+elif command -v gtimeout >/dev/null 2>&1; then RUN(){ gtimeout "$PER_TASK_TIMEOUT" "$@"; }
+else RUN(){ perl -e 'alarm shift @ARGV; exec @ARGV' "$PER_TASK_TIMEOUT" "$@"; }
+fi
+
mkdir -p "$Q"/{tasks,done,failed,logs}
LOG="$Q/loop.log"
ts(){ date '+%F %T'; }
@@ -46,10 +53,12 @@ echo "[$(ts)] START $name" | tee -a "$LOG"
PREFIX="You are the AbramsEgo autonomous builder working in $ROOT. Use /dtd to DECIDE any judgment call. Do only SAFE, REVERSIBLE work: edit code, add features/tests, commit with git (author steve@designerwallcoverings.com). The server ALREADY RUNS under pm2 as process 'abramsego' on port 9773 — to test changes run 'pm2 restart abramsego' then curl the running instance; NEVER start a second node on 9773. NEVER run a GATED action (deploy to Kamatera, DNS, domain registration, Stripe/pricing/publish, send-to-list, spend, remote push) — instead draft it to ~/.claude/yolo-queue/pending-approval/ with an officer APPROVE/REVISE/BLOCK block. Commit after each success. TASK FOLLOWS:\n\n"
LOGF="$Q/logs/${name%.md}.$(date +%s).log"
-if cat <(printf '%b' "$PREFIX") "$TASK" | timeout "$PER_TASK_TIMEOUT" "$CLAUDE_BIN" --print --permission-mode acceptEdits --max-turns "$MAX_TURNS" --model "$MODEL" >"$LOGF" 2>&1; then
+cat <(printf '%b' "$PREFIX") "$TASK" | RUN "$CLAUDE_BIN" --print --permission-mode acceptEdits --max-turns "$MAX_TURNS" --model "$MODEL" >"$LOGF" 2>&1
+rc=${PIPESTATUS[1]}
+if [ "$rc" -eq 0 ]; then
mv "$TASK" "$Q/done/$name"; echo "[$(ts)] DONE $name -> $LOGF" | tee -a "$LOG"
else
- mv "$TASK" "$Q/failed/$name"; echo "[$(ts)] FAIL $name (rc=$?) -> $LOGF" | tee -a "$LOG"
+ mv "$TASK" "$Q/failed/$name"; echo "[$(ts)] FAIL $name (rc=$rc) -> $LOGF" | tee -a "$LOG"
fi
sleep "$COOLDOWN"
← 194ddb9 build-loop: tell worker the server runs under pm2 (avoid por
·
back to AbramsEgo
·
harness: rate-limit-aware loop + StartInterval heartbeat + S 785c4e5 →