feat(doctor): --online, for the release a host has never fetched
Everything doctor checks compares copies already on the machine, deliberately — it runs in a SessionStart hook where latency shows, and its header promises no network I/O. That leaves exactly one case invisible, and #30 walked straight into it: a host whose checkout, marketplace clone and installed plugin all agree reads as clean while all three sit a release behind origin. `--online` closes it with one `git ls-remote`, opt-in, for a scheduled per-host job rather than the session hook. Comparison is by order, not equality, so a host ahead of the newest tag — normal between a release commit and its tag — stays quiet. An unreachable remote is a WARN naming itself, not a staleness FAIL. "I could not check" and "you are behind" are different answers, and collapsing them would make a network blip look like a stale library. The remote URL is never printed: a remote rewritten by url.insteadOf expands into a live token, which is a documented way this fleet has leaked one before. Five fixture cases through a $DOCTOR_LATEST_TAG_CMD seam, including one that asserts the DEFAULT run performs no lookup at all — the promise in the header is now a test, not a comment. Verified live on koala: $ bin/doctor --online FAIL behind: this host has 0.12.1; origin has released 0.13.4 $ bin/doctor skills doctor: clean — 41 skills Closes #38 Bump-Type: minor
This commit is contained in:
+41
-2
@@ -10,6 +10,7 @@
|
||||
# doctor human report, non-zero exit on drift
|
||||
# doctor --quiet print only when something is wrong (SessionStart hook)
|
||||
# doctor --json machine-readable findings
|
||||
# doctor --online ALSO ask origin for the latest tag (one network call)
|
||||
#
|
||||
# POSIX sh on purpose: it runs on macOS and Linux, before any toolchain is
|
||||
# guaranteed present, and inside a session-start hook where latency shows.
|
||||
@@ -21,10 +22,12 @@ set -u
|
||||
|
||||
QUIET=0
|
||||
JSON=0
|
||||
ONLINE=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--quiet) QUIET=1 ;;
|
||||
--json) JSON=1 ;;
|
||||
--quiet) QUIET=1 ;;
|
||||
--json) JSON=1 ;;
|
||||
--online) ONLINE=1 ;;
|
||||
-h|--help)
|
||||
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0 ;;
|
||||
@@ -288,6 +291,42 @@ if [ -n "$installed_v" ] && [ -n "$available_v" ] && [ "$installed_v" != "$avail
|
||||
add FAIL plugin-version "Claude Code has skills@mathias $installed_v installed but $available_v is available on this host — /plugin update skills@mathias (a host stale enough to matter is running the old doctor, so the first detection may need this run by hand)"
|
||||
fi
|
||||
|
||||
# --- optional: the release this host has never fetched ----------------------
|
||||
# Every check above compares copies already present, so a host whose checkout,
|
||||
# marketplace clone and installed plugin all agree reads as clean while sitting
|
||||
# a release behind origin (#38). Closing that needs a network call, which the
|
||||
# default run must not make — hence opt-in, for a scheduled per-host job rather
|
||||
# than the SessionStart hook.
|
||||
#
|
||||
# $DOCTOR_LATEST_TAG_CMD is the test seam; it prints the newest remote tag.
|
||||
if [ "$ONLINE" -eq 1 ]; then
|
||||
if [ -n "${DOCTOR_LATEST_TAG_CMD:-}" ]; then
|
||||
remote_tag=$(eval "$DOCTOR_LATEST_TAG_CMD" 2>/dev/null | tail -1 | tr -d '[:space:]')
|
||||
else
|
||||
# The URL is never printed: a remote rewritten by url.insteadOf can expand
|
||||
# into a live token.
|
||||
origin=$(git -C "$CHECKOUT" config --get remote.origin.url 2>/dev/null || true)
|
||||
if [ -n "$origin" ]; then
|
||||
remote_tag=$(git ls-remote --tags --refs "$origin" 2>/dev/null \
|
||||
| sed 's#.*refs/tags/##' | sort -t. -k1,1n -k2,2n -k3,3n | tail -1 | tr -d '[:space:]')
|
||||
else
|
||||
remote_tag=''
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$remote_tag" ]; then
|
||||
# Not drift. A host that cannot reach origin has an unanswered question,
|
||||
# not a stale library, and saying otherwise would make the two look alike.
|
||||
add WARN offline "could not reach origin for the latest tag — this run proves nothing about staleness"
|
||||
else
|
||||
remote_v=${remote_tag#v}
|
||||
if [ -n "$available_v" ] && [ "$remote_v" != "$available_v" ] \
|
||||
&& [ "$(newer_version "$available_v" "$remote_v")" = "$remote_v" ]; then
|
||||
add FAIL behind "this host has $available_v; origin has released $remote_v — run 'task update' and '/plugin update skills@mathias'"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- output -----------------------------------------------------------------
|
||||
if [ "$JSON" -eq 1 ]; then
|
||||
printf '{"checkout":"%s","expected":%s,"plugin":{"installed":"%s","available":"%s"},"findings":[%s]}\n' \
|
||||
|
||||
Reference in New Issue
Block a user