mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 08:23:59 +01:00
bin/gstack-doctor prints one row per check without starting a skill: install root (the registry rows behind ./setup --status), state root, Bun against the floor, hook parse check, Codex mode and self-locate via gstack-codex-probe subcommands, the cached model probe with its age (--live runs the paid probe-model), artifacts-sync health from the status file with the status code clamped, the browse bundle, Claude Code version, the largest session journal and the last five schema-1 guard reason codes. Rows are ok, warn, not configured or fail; only fail exits non-zero; fix lines name helpers by absolute install-root path. ./setup --status gains a read-only Codex row (bin/gstack-codex-status.sh, shared with the doctor) and ends with the doctor's absolute path. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
75 lines
3.3 KiB
Bash
75 lines
3.3 KiB
Bash
# shellcheck shell=bash
|
|
# gstack-codex-status.sh — free, read-only Codex facts shared by
|
|
# `./setup --status` and bin/gstack-doctor. Sourced, never executed. Bash 3.2
|
|
# builtins plus head/tr/date; it never runs a model, never writes, and never
|
|
# needs bun, so `./setup --status` stays "no bun, no build, no writes".
|
|
#
|
|
# The model-probe cache is <state root>/.codex-model-probe, written only by
|
|
# bin/gstack-codex-probe: first line "STATUS EPOCH SIGNATURE". Only the status
|
|
# word and the epoch are read here; the signature check (and so whether the
|
|
# entry would still be reused) stays the probe's own logic.
|
|
|
|
# gstack_codex_cache_read STATE_ROOT — sets _gcx_probe to MODEL_OK,
|
|
# MODEL_UNUSABLE, MODEL_QUOTA_EXHAUSTED, unrecognized, or "" (never probed),
|
|
# and _gcx_age to the entry's age in seconds ("" when the epoch is unusable).
|
|
gstack_codex_cache_read() {
|
|
_gcx_probe="" _gcx_age=""
|
|
_gcx_line=""
|
|
[ -f "$1/.codex-model-probe" ] && _gcx_line=$(head -1 "$1/.codex-model-probe" 2>/dev/null)
|
|
[ -n "$_gcx_line" ] || return 0
|
|
_gcx_status="${_gcx_line%% *}"
|
|
_gcx_ts="${_gcx_line#* }"; _gcx_ts="${_gcx_ts%% *}"
|
|
case "$_gcx_status" in
|
|
MODEL_OK|MODEL_UNUSABLE|MODEL_QUOTA_EXHAUSTED) _gcx_probe="$_gcx_status" ;;
|
|
*) _gcx_probe=unrecognized ;;
|
|
esac
|
|
case "$_gcx_ts" in ''|*[!0-9]*) return 0 ;; esac
|
|
_gcx_now=$(date +%s 2>/dev/null)
|
|
case "$_gcx_now" in ''|*[!0-9]*) return 0 ;; esac
|
|
[ "$_gcx_ts" -le "$_gcx_now" ] && _gcx_age=$((_gcx_now - _gcx_ts))
|
|
return 0
|
|
}
|
|
|
|
# gstack_codex_age_text SECONDS — "40s ago", "12m ago", "3h ago", "2d ago";
|
|
# "age unknown" when SECONDS is empty.
|
|
gstack_codex_age_text() {
|
|
case "$1" in
|
|
''|*[!0-9]*) printf 'age unknown' ;;
|
|
*) if [ "$1" -lt 60 ]; then printf '%ss ago' "$1"
|
|
elif [ "$1" -lt 3600 ]; then printf '%sm ago' "$(($1 / 60))"
|
|
elif [ "$1" -lt 172800 ]; then printf '%sh ago' "$(($1 / 3600))"
|
|
else printf '%sd ago' "$(($1 / 86400))"; fi ;;
|
|
esac
|
|
}
|
|
|
|
# gstack_codex_version — sets _gcx_version to the first line of
|
|
# `codex --version`, clamped to a version-like charset and 60 characters;
|
|
# "" when codex is absent or prints nothing. Returns codex's exit code.
|
|
gstack_codex_version() {
|
|
_gcx_version=""
|
|
command -v codex >/dev/null 2>&1 || return 127
|
|
_gcx_vout=$(codex --version </dev/null 2>/dev/null)
|
|
_gcx_vrc=$?
|
|
_gcx_version=$(printf '%s\n' "$_gcx_vout" | head -1 | tr -cd 'A-Za-z0-9 ._+()-' | cut -c1-60)
|
|
return "$_gcx_vrc"
|
|
}
|
|
|
|
# gstack_codex_status_line GSTACK_ROOT STATE_ROOT — the `./setup --status`
|
|
# Codex row: install and version, the codex_reviews setting, and the cached
|
|
# model probe with its age. No paid call.
|
|
gstack_codex_status_line() {
|
|
_gcx_reviews=$("$1/bin/gstack-config" get codex_reviews 2>/dev/null || echo enabled)
|
|
case "$_gcx_reviews" in enabled|disabled) ;; *) _gcx_reviews=unknown ;; esac
|
|
if ! command -v codex >/dev/null 2>&1; then
|
|
printf 'Codex: not installed (codex_reviews=%s; outside reviews in /review, /ship, /autoplan and /codex need it)\n' "$_gcx_reviews"
|
|
return 0
|
|
fi
|
|
gstack_codex_version
|
|
gstack_codex_cache_read "$2"
|
|
case "$_gcx_probe" in
|
|
'') _gcx_probe_text="not probed" ;;
|
|
*) _gcx_probe_text="$_gcx_probe $(gstack_codex_age_text "$_gcx_age")" ;;
|
|
esac
|
|
printf 'Codex: installed (%s); codex_reviews=%s; model probe: %s\n' "${_gcx_version:-version unknown}" "$_gcx_reviews" "$_gcx_probe_text"
|
|
}
|