← Commit history

Hook: HOME-safe cron registration + loud missing-CLI (adom/hook#3), refresh the install-lock note (#2)

Colby Knox ·2e668ce66a ·2mo ago ·parent 990d8cc
2 files changed +39−6
check-updates.sh+17−4
@@ -43,7 +43,9 @@ now=$(date +%s 2>/dev/null || echo 0) # the last update succeeded or none has run. if [ -f "$STATUS" ]; then   st="$(cat "$STATUS" 2>/dev/null)"-  if [ "$st" != "running" ] && [ -n "$st" ] && [ "$st" != "0" ]; then+  # 'cli-missing' is reported by its own check below, with its own remedy, so it+  # is not re-reported here as a failed update.+  if [ "$st" != "running" ] && [ "$st" != "cli-missing" ] && [ -n "$st" ] && [ "$st" != "0" ]; then     reason="$(tail -n 3 "$LOG" 2>/dev/null | tr '\n' ' ' | cut -c1-300)"     echo "adom: the last background auto-update FAILED (exit $st) -- the fleet may be behind wiki.adom.inc. See why with 'adom-wiki pkg install adom/core'. Recent output: ${reason:-<none>}"     # Fall through and retry below; a transient failure self-heals, a real one@@ -59,7 +61,16 @@ if [ -z "${ADOM_HOOK_FORCE:-}" ] && [ "$last" -gt 0 ] && [ $(( now - last )) -lt fi touch "$STAMP" 2>/dev/null -command -v adom-wiki >/dev/null 2>&1 || exit 0+# The CLI is the whole update mechanism, so its absence means this container has+# STOPPED updating. Exiting 0 made that indistinguishable from "nothing to do"+# (adom/hook#3), the same silence this hook exists to break. Say it, and leave a+# status other surfaces can read, while staying non-fatal: a prompt hook must+# never block the user's session.+if ! command -v adom-wiki >/dev/null 2>&1; then+  echo "adom: auto-update is NOT running: the adom-wiki CLI is not on PATH (checked \$HOME/.local/bin and \$PATH). This container will drift behind wiki.adom.inc until the CLI is reinstalled."+  echo "cli-missing" > "$STATUS" 2>/dev/null+  exit 0+fi  # --- 3. Don't stack a second updater on top of one still running. ------------- # But treat a 'running' marker older than RUN_STALE_AFTER as crashed (container@@ -90,8 +101,10 @@ fi # `cp: cannot stat 'skills/.../SKILL.md'`. The flock below serializes the hook's # own updaters: the second to arrive skips instead of stacking. It is held for the # WHOLE background update (inside the subshell), not just the parent launch.-# (It does NOT cover a MANUAL `adom-wiki pkg install` racing the hook -- that needs-# a CLI-level install lock. See adom/hook #1 follow-up.)+# A MANUAL `adom-wiki pkg install` racing the hook is covered too, since+# adom-wiki-cli 1.0.39: every mutating pkg verb takes an exclusive lock on+# PREFIX/.install.lock and extracts atomically (stage into a sibling dir, then+# rename), so no caller can observe a half-written module dir. (adom/hook#2) echo running > "$STATUS" 2>/dev/null (   if command -v flock >/dev/null 2>&1; then
install.sh+22−2
@@ -95,10 +95,30 @@ wire "${HOME}/.codex/hooks.json" 0 CRON_LINE_INTERVAL="*/30 * * * * $HOOK_CMD >/dev/null 2>&1" CRON_LINE_REBOOT="@reboot $HOOK_CMD >/dev/null 2>&1" if command -v crontab >/dev/null 2>&1; then-  # Idempotent: strip any prior adom-core-update entries, then re-add both.-  if { crontab -l 2>/dev/null | grep -v "adom-core-update.sh" || true; \+  # Idempotent, and HOME-SAFE (adom/hook#3): crontab is a per-USER resource, not+  # per-HOME. Stripping every line matching "adom-core-update.sh" meant an+  # install run with a non-default HOME (an isolated test, a service account+  # sharing the user) deleted the REAL entries and repointed this user's cron at+  # the foreign HOME -- the container then stopped updating and said nothing,+  # which is the exact failure class this hook exists to prevent. Only ever+  # remove lines that invoke THIS hook path.+  cron_filter() {+    # Fixed-string match on the full hook path, so /home/a/... never matches+    # /home/b/..., and a regex metacharacter in HOME cannot widen the match.+    grep -vF "$HOOK" 2>/dev/null || true+  }+  if { crontab -l 2>/dev/null | cron_filter; \        echo "$CRON_LINE_INTERVAL"; echo "$CRON_LINE_REBOOT"; } | crontab - 2>/dev/null; then     echo "  registered cron for headless updates (*/30 + @reboot)"+    # Another HOME's hook in the same user crontab is legal but almost always a+    # mistake (a stray isolated-test install). Name it instead of leaving two+    # updaters racing invisibly.+    others="$(crontab -l 2>/dev/null | grep -F "adom-core-update.sh" | grep -vF "$HOOK" || true)"+    if [ -n "$others" ]; then+      echo "  note: this user's crontab also runs the hook from ANOTHER home:" >&2+      echo "$others" | sed 's/^/        /' >&2+      echo "        that is usually a leftover from an isolated-HOME install; remove it with 'crontab -e' if so." >&2+    fi     if ! pgrep -x crond >/dev/null 2>&1 && ! pgrep -x cron >/dev/null 2>&1; then       echo "  warning: crond is NOT running, so the schedule will not fire. Start cron in this image," >&2       echo "           or have the app call '$HOOK' on its own loop." >&2