77# MOCK_CODEX_EXIT_CODE - exit code the mock returns (default: 0)
88# MOCK_CODEX_STDOUT - text the mock writes to stdout
99# MOCK_CODEX_STDERR - text the mock writes to stderr
10+ # MOCK_CODEX_HELP_OUTPUT - text the mock writes for `codex --help`
11+ # MOCK_CODEX_ARGS_FILE - optional file where non-help argv is captured
1012#
1113
1214set -euo pipefail
@@ -40,6 +42,23 @@ cat > "$MOCK_BIN_DIR/codex" << 'MOCK_EOF'
4042#!/usr/bin/env bash
4143# Mock codex binary for testing ask-codex.sh
4244# Controlled via environment variables.
45+ if printf '%s\n' "$@" | grep -qx -- '--help'; then
46+ if [[ "${1:-}" == "--disable" ]]; then
47+ feature="${2:-}"
48+ supported_features=" ${MOCK_CODEX_SUPPORTED_FEATURES:-hooks plugin_hooks codex_hooks} "
49+ if [[ "$supported_features" != *" $feature "* ]]; then
50+ echo "unknown feature: $feature" >&2
51+ exit 2
52+ fi
53+ fi
54+ if [[ -n "${MOCK_CODEX_HELP_OUTPUT:-}" ]]; then
55+ echo "$MOCK_CODEX_HELP_OUTPUT"
56+ fi
57+ exit 0
58+ fi
59+ if [[ -n "${MOCK_CODEX_ARGS_FILE:-}" ]]; then
60+ printf '%s\n' "$@" > "$MOCK_CODEX_ARGS_FILE"
61+ fi
4362if [[ -n "${MOCK_CODEX_STDERR:-}" ]]; then
4463 echo "$MOCK_CODEX_STDERR" >&2
4564fi
@@ -63,6 +82,9 @@ reset_mock() {
6382 export MOCK_CODEX_EXIT_CODE=" 0"
6483 export MOCK_CODEX_STDOUT=" "
6584 export MOCK_CODEX_STDERR=" "
85+ export MOCK_CODEX_HELP_OUTPUT=" "
86+ export MOCK_CODEX_ARGS_FILE=" "
87+ export MOCK_CODEX_SUPPORTED_FEATURES=" hooks plugin_hooks codex_hooks"
6688 rm -rf " $MOCK_PROJECT /.humanize/skill" 2> /dev/null || true
6789}
6890
@@ -86,6 +108,7 @@ run_ask_codex_capturing_dir() {
86108 cd " $MOCK_PROJECT "
87109 export CLAUDE_PROJECT_DIR=" $MOCK_PROJECT "
88110 export XDG_CACHE_HOME=" $RUN_XDG_CACHE_HOME "
111+ export XDG_CONFIG_HOME=" $TEST_DIR /no-user-config"
89112 PATH=" $MOCK_BIN_DIR :$PATH " bash " $ASK_CODEX_SCRIPT " " $@ " 2>&1 > /dev/null
90113 ) || RUN_EXIT_CODE=$?
91114 output_path=$( printf ' %s\n' " $run_stderr " | grep " ^ask-codex: response saved to " | sed ' s/^ask-codex: response saved to //' )
@@ -114,6 +137,7 @@ run_ask_codex() {
114137 cd " $MOCK_PROJECT "
115138 export CLAUDE_PROJECT_DIR=" $MOCK_PROJECT "
116139 export XDG_CACHE_HOME=" $TEST_DIR /cache"
140+ export XDG_CONFIG_HOME=" $TEST_DIR /no-user-config"
117141 PATH=" $MOCK_BIN_DIR :$PATH " bash " $ASK_CODEX_SCRIPT " " $@ "
118142 )
119143}
@@ -253,6 +277,54 @@ else
253277 fail " successful run exits 0" " exit 0" " exit=$EXIT_CODE "
254278fi
255279
280+ # Test: supported Codex --disable flag disables all known hook features
281+ reset_mock
282+ export MOCK_CODEX_STDOUT=" hook-disable-test"
283+ export MOCK_CODEX_HELP_OUTPUT=" --disable <feature> Disable a feature"
284+ export MOCK_CODEX_SUPPORTED_FEATURES=" hooks plugin_hooks codex_hooks"
285+ ASK_CODEX_ARGS_FILE=" $TEST_DIR /ask-codex-args.txt"
286+ export MOCK_CODEX_ARGS_FILE=" $ASK_CODEX_ARGS_FILE "
287+ EXIT_CODE=0
288+ run_ask_codex " hook disable test" > /dev/null 2>&1 || EXIT_CODE=$?
289+ CAPTURED_ARGS=" $( cat " $ASK_CODEX_ARGS_FILE " 2> /dev/null || true) "
290+ if [[ $EXIT_CODE -eq 0 ]] \
291+ && echo " $CAPTURED_ARGS " | grep -qx -- ' exec' \
292+ && echo " $CAPTURED_ARGS " | grep -qx -- ' --disable' \
293+ && echo " $CAPTURED_ARGS " | grep -qx -- ' hooks' \
294+ && echo " $CAPTURED_ARGS " | grep -qx -- ' plugin_hooks' \
295+ && echo " $CAPTURED_ARGS " | grep -qx -- ' codex_hooks' ; then
296+ pass " successful run disables all known hook features for nested codex exec"
297+ else
298+ fail " successful run disables all known hook features for nested codex exec" \
299+ " exec args include hooks, plugin_hooks, codex_hooks" \
300+ " exit=$EXIT_CODE , args=$CAPTURED_ARGS "
301+ fi
302+ reset_mock
303+
304+ # Test: older Codex builds only receive supported hook feature names
305+ reset_mock
306+ export MOCK_CODEX_STDOUT=" legacy-hook-disable-test"
307+ export MOCK_CODEX_HELP_OUTPUT=" --disable <feature> Disable a feature"
308+ export MOCK_CODEX_SUPPORTED_FEATURES=" codex_hooks"
309+ ASK_CODEX_ARGS_FILE=" $TEST_DIR /ask-codex-legacy-args.txt"
310+ export MOCK_CODEX_ARGS_FILE=" $ASK_CODEX_ARGS_FILE "
311+ EXIT_CODE=0
312+ run_ask_codex " legacy hook disable test" > /dev/null 2>&1 || EXIT_CODE=$?
313+ CAPTURED_ARGS=" $( cat " $ASK_CODEX_ARGS_FILE " 2> /dev/null || true) "
314+ if [[ $EXIT_CODE -eq 0 ]] \
315+ && echo " $CAPTURED_ARGS " | grep -qx -- ' exec' \
316+ && echo " $CAPTURED_ARGS " | grep -qx -- ' --disable' \
317+ && echo " $CAPTURED_ARGS " | grep -qx -- ' codex_hooks' \
318+ && ! echo " $CAPTURED_ARGS " | grep -qx -- ' hooks' \
319+ && ! echo " $CAPTURED_ARGS " | grep -qx -- ' plugin_hooks' ; then
320+ pass " successful run disables only supported hook features for older codex"
321+ else
322+ fail " successful run disables only supported hook features for older codex" \
323+ " exec args include only codex_hooks" \
324+ " exit=$EXIT_CODE , args=$CAPTURED_ARGS "
325+ fi
326+ reset_mock
327+
256328# ========================================
257329# Error Handling Tests
258330# ========================================
@@ -519,6 +591,7 @@ run_ask_codex_probe() {
519591 cd " $PROBE_PROJECT "
520592 export CLAUDE_PROJECT_DIR=" $PROBE_PROJECT "
521593 export XDG_CACHE_HOME=" $TEST_DIR /cache-probe"
594+ export XDG_CONFIG_HOME=" $TEST_DIR /no-user-config"
522595 PATH=" $PROBE_BIN_DIR :$PATH " bash " $ASK_CODEX_SCRIPT " " $@ "
523596 )
524597}
@@ -545,14 +618,17 @@ reset_mock
545618export MOCK_CODEX_STDOUT=" probe-test-supports"
546619run_ask_codex_probe " probe disable test" > /dev/null 2>&1 || true
547620
548- # Check that the cached probe result is "yes" in the skill dir
621+ # Check that the cached probe result lists the supported hook features.
549622PROBE_SKILL_DIR=$( find " $PROBE_PROJECT /.humanize/skill" -maxdepth 1 -mindepth 1 -type d 2> /dev/null | sort | tail -1)
550- if [[ -n " $PROBE_SKILL_DIR " ]] && [[ -f " $PROBE_SKILL_DIR /.codex-disable-hooks-supported" ]]; then
551- PROBE_RESULT=$( cat " $PROBE_SKILL_DIR /.codex-disable-hooks-supported" )
552- if [[ " $PROBE_RESULT " == " yes" ]]; then
553- pass " auto-probe: cached 'yes' when codex supports --disable"
623+ if [[ -n " $PROBE_SKILL_DIR " ]] && [[ -f " $PROBE_SKILL_DIR /.codex-disable-hooks-features" ]]; then
624+ PROBE_RESULT=$( cat " $PROBE_SKILL_DIR /.codex-disable-hooks-features" )
625+ if echo " $PROBE_RESULT " | grep -qx -- ' hooks' \
626+ && echo " $PROBE_RESULT " | grep -qx -- ' plugin_hooks' \
627+ && echo " $PROBE_RESULT " | grep -qx -- ' codex_hooks' ; then
628+ pass " auto-probe: cached supported hook features when codex supports --disable"
554629 else
555- fail " auto-probe: cached 'yes' when codex supports --disable" " yes" " $PROBE_RESULT "
630+ fail " auto-probe: cached supported hook features when codex supports --disable" \
631+ " hooks, plugin_hooks, codex_hooks" " $PROBE_RESULT "
556632 fi
557633else
558634 fail " auto-probe: probe cache file created" " cache file exists" " not found"
@@ -583,6 +659,7 @@ run_ask_codex_probe_no() {
583659 cd " $PROBE_PROJECT_NO "
584660 export CLAUDE_PROJECT_DIR=" $PROBE_PROJECT_NO "
585661 export XDG_CACHE_HOME=" $TEST_DIR /cache-probe-no"
662+ export XDG_CONFIG_HOME=" $TEST_DIR /no-user-config"
586663 PATH=" $PROBE_BIN_NO_DIR :$PATH " bash " $ASK_CODEX_SCRIPT " " $@ "
587664 )
588665}
@@ -592,23 +669,25 @@ export MOCK_CODEX_STDOUT="probe-test-no-support"
592669run_ask_codex_probe_no " probe no-support test" > /dev/null 2>&1 || true
593670
594671PROBE_NO_SKILL_DIR=$( find " $PROBE_PROJECT_NO /.humanize/skill" -maxdepth 1 -mindepth 1 -type d 2> /dev/null | sort | tail -1)
595- if [[ -n " $PROBE_NO_SKILL_DIR " ]] && [[ -f " $PROBE_NO_SKILL_DIR /.codex-disable-hooks-supported " ]]; then
596- PROBE_NO_RESULT=$( cat " $PROBE_NO_SKILL_DIR /.codex-disable-hooks-supported " )
597- if [[ " $PROBE_NO_RESULT " == " no " ]]; then
598- pass " auto-probe: cached 'no' when codex does not support --disable"
672+ if [[ -n " $PROBE_NO_SKILL_DIR " ]] && [[ -f " $PROBE_NO_SKILL_DIR /.codex-disable-hooks-features " ]]; then
673+ PROBE_NO_RESULT=$( cat " $PROBE_NO_SKILL_DIR /.codex-disable-hooks-features " )
674+ if [[ -z " $PROBE_NO_RESULT " ]]; then
675+ pass " auto-probe: cached empty feature list when codex does not support --disable"
599676 else
600- fail " auto-probe: cached 'no' when codex does not support --disable" " no" " $PROBE_NO_RESULT "
677+ fail " auto-probe: cached empty feature list when codex does not support --disable" \
678+ " (empty)" " $PROBE_NO_RESULT "
601679 fi
602680else
603681 fail " auto-probe: probe cache file created for no-support case" " cache file exists" " not found"
604682fi
605683
606684# Test C: ask-codex.sh script contains the probe implementation
607- if grep -q " CODEX_DISABLE_HOOKS_ARGS=(--disable hooks) " " $ASK_CODEX_SCRIPT " \
608- && grep -q " codex-disable-hooks-supported " " $ASK_CODEX_SCRIPT " ; then
685+ if grep -q " for feature_name in hooks plugin_hooks codex_hooks " " $ASK_CODEX_SCRIPT " \
686+ && grep -q " codex-disable-hooks-features " " $ASK_CODEX_SCRIPT " ; then
609687 pass " ask-codex.sh contains nested hook disable auto-probe implementation"
610688else
611- fail " ask-codex.sh contains nested hook disable auto-probe implementation" " hooks disable args + probe cache" " not found"
689+ fail " ask-codex.sh contains nested hook disable auto-probe implementation" \
690+ " feature loop + probe cache" " not found"
612691fi
613692
614693# ========================================
0 commit comments