Przeglądaj źródła

fix(codex): suppress SessionStart hook auto-discovery with empty hooks object

Codex auto-discovers a plugin's hooks/hooks.json whenever the Codex
manifest has no `hooks` field: load_plugin_hooks falls back to a
hardcoded DEFAULT_HOOKS_CONFIG_FILE = "hooks/hooks.json" and registers
it. hooks/hooks.json is the Claude Code SessionStart hook, it is tracked
in this repo, and the Codex marketplace installs the whole repo root
(source url "./"), so the fallback re-registered the SessionStart hook
and its install-time trust prompt on Codex.

Removing the Codex hook file and the manifest `hooks` pointer (commit
"Remove Codex hooks") did not disable the hook on Codex — it removed the
explicit declaration that was overriding the fallback, so the fallback
took over and found the Claude hooks/hooks.json.

Declare an empty inline hooks object ({}) in .codex-plugin/plugin.json.
It parses as an empty inline hook set and stops Codex reaching the
auto-discovery fallback. An absent field, an empty array ([]), and an
empty inline list all collapse back to the fallback, so the value must
be exactly {}.

Update the test to assert the manifest declares hooks: {} (and that
hooks/hooks.json exists, which is what makes the declaration necessary),
replacing the prior assertion that the field was absent — which passed
while the hook was still being auto-discovered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drew Ritter 2 miesięcy temu
rodzic
commit
b15ef6ebbe

+ 1 - 0
.codex-plugin/plugin.json

@@ -21,6 +21,7 @@
     "workflow"
   ],
   "skills": "./skills/",
+  "hooks": {},
   "interface": {
     "displayName": "Superpowers",
     "shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",

+ 17 - 2
tests/codex/test-marketplace-manifest.sh

@@ -51,10 +51,25 @@ if not plugin_manifest.exists():
 
 manifest = json.loads(plugin_manifest.read_text(encoding="utf-8"))
 assert_equal(manifest.get("name"), plugin.get("name"), "plugin manifest name")
+
+# Codex auto-discovers a plugin's hooks/hooks.json whenever the Codex manifest
+# has no `hooks` field: load_plugin_hooks falls back to a hardcoded
+# DEFAULT_HOOKS_CONFIG_FILE = "hooks/hooks.json" and registers it. That file is
+# the Claude Code SessionStart hook, it is tracked in this repo, and this
+# marketplace installs the whole repo root (source url "./"), so on Codex the
+# fallback re-registers the SessionStart hook and its install-time trust prompt.
+# Declaring an empty inline hooks object ({}) parses as an empty inline hook set
+# and suppresses the auto-discovery. An absent field, an empty array ([]), and
+# an empty inline list all collapse back to the fallback, so the value must be
+# exactly an empty object.
+hooks_config = repo_root / "hooks" / "hooks.json"
+if not hooks_config.exists():
+    raise AssertionError("hooks/hooks.json must exist (Claude Code SessionStart hook)")
+
 assert_equal(
     manifest.get("hooks"),
-    None,
-    "Codex manifest ships no hooks",
+    {},
+    "Codex manifest must declare empty hooks {} to suppress hooks/hooks.json auto-discovery",
 )
 
 print("Codex marketplace manifest looks good")