← Commit history

Publish 1.1.8

Colby Knox ·a30188280a ·3mo ago ·parent 9c3948a
6 files changed +95−8
README.md+19−5
@@ -14,15 +14,29 @@ public registry instead, so it works for any user and any agent.  ## How it works -A `UserPromptSubmit` hook runs a throttled, bounded check (`adom-wiki outdated`,-~every 30 min). When an installed package is behind the registry, it applies the-update **in the background** and drops a one-line note into the model's context. It-never blocks your prompt.+A throttled, bounded check (`adom-wiki outdated`, ~every 30 min). When an installed+package is behind the registry, it applies the update **in the background** and+drops a one-line note into the model's context. It never blocks your prompt.++Two triggers are wired, sharing one throttle stamp (so a double fire is a no-op):++| Trigger | Where it matters |+| --- | --- |+| `UserPromptSubmit` (Claude Code / Codex) | interactive containers -- updates as you type |+| cron (`*/30` + `@reboot`) | **headless** lite/service containers -- no prompts, so this is the only trigger they get, and it's where prod releases run |++If the image has no `crontab` (or `crond` isn't running), install says so; have the+app call `~/.adom/hooks/adom-core-update.sh` on its own interval instead (throttled++ idempotent, safe to call often).++Under cron, stdout goes to mail or `/dev/null`, so the durable record is+`~/.adom/last-update.status` (`running`, or the last exit code) and+`~/.adom/last-update.log`.  | Layer | Updates | Cadence | | --- | --- | --- | | `adom-wiki` CLI | its own binary | ~2 h, on use |-| `adom/hook` (this) | installed apps + skills | ~30 min, on prompt |+| `adom/hook` (this) | installed apps + skills | ~30 min, on prompt **or** cron |  ## Install 
SKILL.md+27
@@ -20,6 +20,33 @@ This is the registry-native replacement for the old `git fetch` hook: same "stay current automatically" behavior, but sourced from the public registry so it works for any user and any agent, with no private-GitHub dependency. +## Two triggers (interactive + headless)++Installing wires BOTH, and they share one throttle stamp, so a double fire is a+no-op:++- **`UserPromptSubmit`** (Claude Code / Codex) -- fast: an interactive container+  updates the moment you type.+- **cron** (`*/30` + `@reboot`) -- the headless trigger. A lite/service container+  has no prompts, so without this it never updates and packages rot until someone+  SSHes in -- which is exactly where prod releases run. Cron is registered+  unconditionally (not only when Claude is absent), so an interactive box that sits+  idle for a day still gets a backstop.++If the image has no `crontab`, or `crond` is not running, install says so. In that+case have the app call `~/.adom/hooks/adom-core-update.sh` on its own interval --+it is throttled and idempotent, so calling it often is safe.++**Reading the result on a headless box:** stdout is meaningless under cron (it+becomes mail or `/dev/null`). The durable record is:++- `~/.adom/last-update.status` -- `running`, or the last exit code (`0` = fine).+- `~/.adom/last-update.log` -- the last update's output.++A failed update is also reported to the next interactive prompt, and the CLI+version each container reports to the registry answers "is the fleet current?"+fleet-wide (`GET /api/admin/clients?name=adom-wiki-cli`) without SSHing anywhere.+ ## Two layers of auto-update  - **CLI layer** -- `adom-wiki` self-updates its own binary on use (throttled ~2h).
install.sh+35
@@ -76,6 +76,41 @@ PY wire "${HOME}/.claude/settings.json" 1 wire "${HOME}/.codex/hooks.json" 0 +# ---------------------------------------------------------------------------+# Headless trigger (adom/hook #1). UserPromptSubmit only fires inside Claude Code+# / Codex, so a lite/service container -- arguably where currency matters MOST,+# since that is where prod releases run -- has no trigger at all and rots until+# someone SSHes in.+#+# Register cron ALWAYS, not only when Claude is absent. The script's throttle+# stamp (ADOM_HOOK_INTERVAL, default 30m) makes a second trigger a no-op, so this+# is strictly additive: an interactive box keeps the fast prompt trigger AND gains+# a backstop for when it sits idle for a day. Auto-detecting "no Claude here"+# would leave that idle gap open and adds a branch that can guess wrong.+#+# Note stdout is meaningless under cron (it becomes mail or /dev/null) -- the+# observable surface for a headless box is the status/log file the script writes+# (~/.adom/last-update.status, ~/.adom/last-update.log), plus the CLI version it+# reports to the registry on each update.+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; \+       echo "$CRON_LINE_INTERVAL"; echo "$CRON_LINE_REBOOT"; } | crontab - 2>/dev/null; then+    echo "  registered cron for headless updates (*/30 + @reboot)"+    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+    fi+  else+    echo "  warning: could not write the crontab; this container will only update on a Claude/Codex prompt." >&2+  fi+else+  echo "  note: no crontab in this image, so there is no headless trigger. Either install cron, or have the"+  echo "        app call '$HOOK' on its own interval (it is throttled + idempotent, safe to call often)."+fi+ # Retire a gallia statusline if one is wired (gallia is gone; revert to default). # Targeted: only removed when the statusline command points at gallia. python3 - "${HOME}/.claude/settings.json" <<'PY'
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "hook",-  "version": "1.1.7",+  "version": "1.1.8",   "type": "app",   "org": "adom",   "bundled": true,
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "hook",-  "version": "1.1.7",+  "version": "1.1.8",   "type": "app",   "org": "adom",   "bundled": true,
uninstall.sh+12−1
@@ -32,6 +32,17 @@ PY  unwire "${HOME}/.claude/settings.json" unwire "${HOME}/.codex/hooks.json"++# Drop the headless cron trigger too, or uninstall would leave entries pointing at+# a script it just deleted (cron would then log a failure every 30 minutes).+if command -v crontab >/dev/null 2>&1; then+  if crontab -l 2>/dev/null | grep -q "adom-core-update.sh"; then+    { crontab -l 2>/dev/null | grep -v "adom-core-update.sh" || true; } | crontab - 2>/dev/null \+      && echo "  removed the adom-core-update cron entries"+  fi+fi+ rm -f "$HOOK" rm -rf "${HOME}/.claude/skills/adom-hook"-echo "Removed adom-hook (unwired from Claude + Codex)"+rm -f "${HOME}/.adom/last-update.status" "${HOME}/.adom/last-update.log" "${HOME}/.adom/last-core-check"+echo "Removed adom-hook (unwired from Claude + Codex, cron entries dropped)"