Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codex/plugins/ox/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ox",
"version": "0.0.22",
"version": "0.0.23",
"description": "Base plugin — commit command, code quality hooks, auto-format and check hooks for all projects",
"author": {
"name": "Oxidian"
Expand Down
4 changes: 2 additions & 2 deletions codex/plugins/ox/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"hooks": [
{
"type": "command",
"command": "sh -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; bootstrap_dir=\"${CODEX_PLUGINS_BOOTSTRAP_DIR:-.codex/cc-plugins}\"; case \"$bootstrap_dir\" in /*) bootstrap_root=\"$bootstrap_dir\" ;; *) bootstrap_root=\"$root/$bootstrap_dir\" ;; esac; bootstrap_runner=\"$bootstrap_root/codex/plugins/ox/scripts/run_if_changed.py\"; repo_runner=\"$root/codex/plugins/ox/scripts/run_if_changed.py\"; cache_runner=\"$HOME/.codex/plugins/cache/oxidian/ox/0.0.22/scripts/run_if_changed.py\"; if [ -f \"$bootstrap_runner\" ]; then runner=\"$bootstrap_runner\"; elif [ -f \"$repo_runner\" ]; then runner=\"$repo_runner\"; elif [ -f \"$cache_runner\" ]; then runner=\"$cache_runner\"; else echo \"ox hook runner not found; checked $bootstrap_runner, $repo_runner, and $cache_runner\" >&2; exit 2; fi; exec python3 \"$runner\" --runtime codex --action fast'",
"command": "sh -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; bootstrap_dir=\"${CODEX_PLUGINS_BOOTSTRAP_DIR:-.codex/cc-plugins}\"; case \"$bootstrap_dir\" in /*) bootstrap_root=\"$bootstrap_dir\" ;; *) bootstrap_root=\"$root/$bootstrap_dir\" ;; esac; bootstrap_runner=\"$bootstrap_root/codex/plugins/ox/scripts/run_if_changed.py\"; repo_runner=\"$root/codex/plugins/ox/scripts/run_if_changed.py\"; cache_runner=\"$HOME/.codex/plugins/cache/oxidian/ox/0.0.23/scripts/run_if_changed.py\"; if [ -f \"$bootstrap_runner\" ]; then runner=\"$bootstrap_runner\"; elif [ -f \"$repo_runner\" ]; then runner=\"$repo_runner\"; elif [ -f \"$cache_runner\" ]; then runner=\"$cache_runner\"; else echo \"ox hook runner not found; checked $bootstrap_runner, $repo_runner, and $cache_runner\" >&2; exit 2; fi; exec python3 \"$runner\" --runtime codex --action fast'",
"timeout": 30,
"statusMessage": "Running fast checks"
}
Expand All @@ -18,7 +18,7 @@
"hooks": [
{
"type": "command",
"command": "sh -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; bootstrap_dir=\"${CODEX_PLUGINS_BOOTSTRAP_DIR:-.codex/cc-plugins}\"; case \"$bootstrap_dir\" in /*) bootstrap_root=\"$bootstrap_dir\" ;; *) bootstrap_root=\"$root/$bootstrap_dir\" ;; esac; bootstrap_runner=\"$bootstrap_root/codex/plugins/ox/scripts/run_if_changed.py\"; repo_runner=\"$root/codex/plugins/ox/scripts/run_if_changed.py\"; cache_runner=\"$HOME/.codex/plugins/cache/oxidian/ox/0.0.22/scripts/run_if_changed.py\"; if [ -f \"$bootstrap_runner\" ]; then runner=\"$bootstrap_runner\"; elif [ -f \"$repo_runner\" ]; then runner=\"$repo_runner\"; elif [ -f \"$cache_runner\" ]; then runner=\"$cache_runner\"; else echo \"ox hook runner not found; checked $bootstrap_runner, $repo_runner, and $cache_runner\" >&2; exit 2; fi; exec python3 \"$runner\" --runtime codex --action slow'",
"command": "sh -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; bootstrap_dir=\"${CODEX_PLUGINS_BOOTSTRAP_DIR:-.codex/cc-plugins}\"; case \"$bootstrap_dir\" in /*) bootstrap_root=\"$bootstrap_dir\" ;; *) bootstrap_root=\"$root/$bootstrap_dir\" ;; esac; bootstrap_runner=\"$bootstrap_root/codex/plugins/ox/scripts/run_if_changed.py\"; repo_runner=\"$root/codex/plugins/ox/scripts/run_if_changed.py\"; cache_runner=\"$HOME/.codex/plugins/cache/oxidian/ox/0.0.23/scripts/run_if_changed.py\"; if [ -f \"$bootstrap_runner\" ]; then runner=\"$bootstrap_runner\"; elif [ -f \"$repo_runner\" ]; then runner=\"$repo_runner\"; elif [ -f \"$cache_runner\" ]; then runner=\"$cache_runner\"; else echo \"ox hook runner not found; checked $bootstrap_runner, $repo_runner, and $cache_runner\" >&2; exit 2; fi; exec python3 \"$runner\" --runtime codex --action slow'",
"timeout": 120,
"statusMessage": "Running final checks"
}
Expand Down
8 changes: 8 additions & 0 deletions codex/plugins/ox/scripts/run_if_changed.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,14 @@ def main() -> None:
_emit(args.runtime, "Plan mode active, skipping")
sys.exit(SUCCESS_CODE)

if (
args.runtime == RUNTIME_CODEX
and args.action == "slow"
and hook_input
and hook_input.get("stop_hook_active") is True
):
sys.exit(SUCCESS_CODE)

# Read config
config_file = os.path.join(project_dir, CONFIG_PATH)
if not os.path.exists(config_file):
Expand Down
2 changes: 1 addition & 1 deletion plugins/ox/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ox",
"description": "Base plugin — commit command, code quality hooks, auto-format and check hooks for all projects",
"version": "0.0.22",
"version": "0.0.23",
"author": {
"name": "Oxidian"
}
Expand Down
8 changes: 8 additions & 0 deletions plugins/ox/scripts/run_if_changed.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,14 @@ def main() -> None:
_emit(args.runtime, "Plan mode active, skipping")
sys.exit(SUCCESS_CODE)

if (
args.runtime == RUNTIME_CODEX
and args.action == "slow"
and hook_input
and hook_input.get("stop_hook_active") is True
):
sys.exit(SUCCESS_CODE)

# Read config
config_file = os.path.join(project_dir, CONFIG_PATH)
if not os.path.exists(config_file):
Expand Down
14 changes: 14 additions & 0 deletions tests/ox/test_run_if_changed.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ def test_success_has_no_output_and_derives_project_dir_from_cwd(self, tmp_path:
assert result.stdout == ""
assert result.stderr == ""

def test_reentrant_stop_skips_before_config_parsing(self, tmp_path: Path) -> None:
subprocess.run(["git", "init"], cwd=tmp_path, check=True, capture_output=True, text=True)
(tmp_path / ".claude").mkdir()
(tmp_path / ".claude" / "ox-hooks.json").write_text("{not json\n")
(tmp_path / "changed.txt").write_text("changed\n")
subdir = tmp_path / "subdir"
subdir.mkdir()

result = _run_codex_hook(subdir, "slow", extra_payload={"stop_hook_active": True})

assert result.returncode == 0
assert result.stdout == ""
assert result.stderr == ""

def test_failure_exits_two_with_feedback_on_stderr(self, tmp_path: Path) -> None:
check_script = tmp_path / "check.py"
check_script.write_text("import sys\nprint('bad check output')\nsys.exit(1)\n")
Expand Down
Loading