mirror of https://github.com/garrytan/gstack.git
fix(codex): add shell-watchdog fallback to timeout wrapper
When neither gtimeout (Homebrew coreutils) nor timeout is on PATH, _gstack_codex_timeout_wrapper ran codex completely unwrapped, so every /codex and /autoplan invocation had silent zero hang protection on a bare macOS install. setup's coreutils auto-install covers most machines but not ones where setup never ran or brew install failed. The wrapper now falls back to a pure-shell watchdog: background the command, poll every 5s, TERM at the deadline, KILL 10s later, and report exit 124 like GNU timeout so the skills' existing hang handling (_CODEX_EXIT = 124 checks, including the PIPESTATUS callers) fires unchanged. Bash "Terminated" job notices are silenced inside a stderr-swapped brace group while fd 3 carries the command's real stderr through, so call-site 2>"$TMPERR" captures keep working and no notice junk leaks into skill output. Both jobs are reaped inside the group so nothing outlives the call holding the caller's pipes open. gtimeout/timeout preference is unchanged; the watchdog only engages when both are absent. test/codex-hardening.test.ts passes 29/29. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a3259400a3
commit
974fbf2e15
|
|
@ -5,7 +5,7 @@
|
|||
# Functions (all prefixed with _gstack_codex_ for namespace hygiene):
|
||||
# _gstack_codex_auth_probe — multi-signal auth check (env + file)
|
||||
# _gstack_codex_version_check — warn on known-bad Codex CLI versions
|
||||
# _gstack_codex_timeout_wrapper — gtimeout -> timeout -> unwrapped fallback
|
||||
# _gstack_codex_timeout_wrapper — gtimeout -> timeout -> shell-watchdog fallback
|
||||
# _gstack_codex_log_event — telemetry emission to ~/.gstack/analytics/
|
||||
#
|
||||
# Hygiene rules (enforced by test/codex-hardening.test.ts):
|
||||
|
|
@ -53,17 +53,50 @@ _gstack_codex_version_check() {
|
|||
|
||||
_gstack_codex_timeout_wrapper() {
|
||||
# Resolve wrapper binary: prefer gtimeout (Homebrew coreutils on macOS),
|
||||
# fall back to timeout (Linux), else run unwrapped. Arguments: $1 is the
|
||||
# duration in seconds; rest is the command to run.
|
||||
# fall back to timeout (Linux), else a pure-shell watchdog so hang
|
||||
# protection still works on machines with neither (e.g. bare macOS).
|
||||
# Arguments: $1 is the duration in seconds; rest is the command to run.
|
||||
local _duration="$1"
|
||||
shift
|
||||
local _to
|
||||
_to=$(command -v gtimeout 2>/dev/null || command -v timeout 2>/dev/null || echo "")
|
||||
if [ -n "$_to" ]; then
|
||||
"$_to" "$_duration" "$@"
|
||||
else
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
# Shell watchdog: background the command, poll every 5s, TERM at the
|
||||
# deadline (KILL 10s later if TERM is ignored), and report exit 124 like
|
||||
# GNU timeout so callers' hang handling still fires. The brace group
|
||||
# routes the shell's own stderr to /dev/null so bash's "Terminated" job
|
||||
# notices never leak into skill output, while fd 3 carries the real
|
||||
# stderr through to the command (call-site 2> captures keep working).
|
||||
# Both jobs are reaped inside the silenced group so no notice surfaces
|
||||
# later and nothing outlives the call holding the caller's pipes open.
|
||||
local _cmd_pid _watchdog_pid
|
||||
local _rc=0
|
||||
{
|
||||
"$@" 2>&3 3>&- &
|
||||
_cmd_pid=$!
|
||||
(
|
||||
_waited=0
|
||||
while [ "$_waited" -lt "$_duration" ]; do
|
||||
sleep 5
|
||||
kill -0 "$_cmd_pid" 2>/dev/null || exit 0
|
||||
_waited=$((_waited + 5))
|
||||
done
|
||||
kill -TERM "$_cmd_pid" 2>/dev/null
|
||||
sleep 10
|
||||
kill -KILL "$_cmd_pid" 2>/dev/null
|
||||
) >/dev/null 2>&1 3>&- &
|
||||
_watchdog_pid=$!
|
||||
wait "$_cmd_pid" || _rc=$?
|
||||
kill "$_watchdog_pid" 2>/dev/null
|
||||
wait "$_watchdog_pid" 2>/dev/null || :
|
||||
} 3>&2 2>/dev/null
|
||||
if [ "$_rc" -eq 143 ] || [ "$_rc" -eq 137 ]; then
|
||||
_rc=124
|
||||
fi
|
||||
return "$_rc"
|
||||
}
|
||||
|
||||
# --- Telemetry event --------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in New Issue