Переглянути джерело

chore(codex): remove orphaned session-start-codex hook + refresh hook docs

hooks/session-start-codex has had no caller since "Remove Codex hooks"
(#1845) deleted hooks-codex.json and its manifest registration; the
Codex manifest now declares an empty hooks object so Codex registers no
session-start hook at all. The script is Codex-specific dead code —
nothing executes it on Codex or any other harness.

- Delete hooks/session-start-codex.
- tests/hooks/test-session-start.sh: drop the two Codex cases that are
  redundant with the generic session-start tests (nested-format and the
  legacy-warning omission are already covered by the Claude Code cases).
  Re-point the "wrapper dispatches" case to the live `session-start`
  script so run-hook.cmd dispatch coverage — used by Claude Code and
  Cursor in production — is preserved rather than lost.
- docs/porting-to-a-new-harness.md: Codex is no longer a Shape A
  (shell-hook) harness, so re-anchor that worked example to Cursor (a
  live shell-hook harness that demonstrates the same per-harness field,
  schema, and matcher variance) and mark Codex as native skill discovery
  with no session-start hook. Clears the references to the deleted
  hooks-codex.json.
- docs/windows/polyglot-hooks.md: the "check hooks-codex.json" pointer
  referenced a file deleted in #1845; re-point to hooks-cursor.json.

RELEASE-NOTES.md keeps its historical mention of hooks-codex.json (it
accurately records what that release did). The tests/codex-plugin-sync
fixtures build their own synthetic session-start-codex and test the sync
mechanism generically, so they are intentionally left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drew Ritter 2 місяців тому
батько
коміт
28b96af905

+ 24 - 23
docs/porting-to-a-new-harness.md

@@ -227,18 +227,20 @@ you may **not** do is bridge a gap by editing the user's global config.
 The harness has a hook system that runs a shell command at session start and
 reads JSON from its stdout. The configured command runs `run-hook.cmd`, a
 polyglot wrapper that just locates bash and dispatches the named script; the
-script (`hooks/session-start`, or a harness-specific variant like
-`hooks/session-start-codex`) is what reads `using-superpowers/SKILL.md` and
-prints a JSON object whose **field name and nesting differ per harness**.
+script (`hooks/session-start`, or a harness-specific variant) is what reads
+`using-superpowers/SKILL.md` and prints a JSON object whose **field name and
+nesting differ per harness**.
 
-- Reference: `hooks/session-start` (and `hooks/session-start-codex`),
-  `hooks/run-hook.cmd`, and the per-harness hook config `hooks/hooks.json`
-  (Claude Code), `hooks/hooks-codex.json` (Codex), `hooks/hooks-cursor.json`
+- Reference: `hooks/session-start`, `hooks/run-hook.cmd`, and the per-harness
+  hook config `hooks/hooks.json` (Claude Code) and `hooks/hooks-cursor.json`
   (Cursor).
-- Manifests: `.codex-plugin/plugin.json`, `.cursor-plugin/plugin.json` point the
-  harness at `./skills/` and the right `hooks-*.json`. (Claude Code's
-  `.claude-plugin/plugin.json` sets neither field — it auto-discovers `skills/`
-  and `hooks/hooks.json` by convention.)
+- Manifests: `.cursor-plugin/plugin.json` points the harness at `./skills/` and
+  the right `hooks-*.json`. (Claude Code's `.claude-plugin/plugin.json` sets
+  neither field — it auto-discovers `skills/` and `hooks/hooks.json` by
+  convention. Codex's `.codex-plugin/plugin.json` ships skills but declares an
+  empty `hooks` object: Codex auto-discovers `hooks/hooks.json` when the field
+  is absent, so the empty object suppresses that — Codex surfaces skills
+  natively and runs no session-start hook.)
 
 > **A hook *system* is not a session-start *event*.** A harness can have a
 > `hooks.json` mechanism — and even contain the literal string `SessionStart` in
@@ -287,7 +289,7 @@ part of the installed extension** — never substitute "edit the user's global
 
 | If the harness… | Use shape | Copy from |
 |---|---|---|
-| runs a shell command at session start and reads its stdout | A (shell-hook) | Codex (`hooks/session-start-codex` + `hooks/hooks-codex.json` + `.codex-plugin/`) |
+| runs a shell command at session start and reads its stdout | A (shell-hook) | Cursor (`hooks/session-start` + `hooks/hooks-cursor.json` + `.cursor-plugin/`) |
 | is a JS/TS plugin host with session/message lifecycle callbacks | B (in-process) | OpenCode (`.opencode/`) — or pi (`.pi/`) if it has no native skill tool |
 | ships an extension-declared context file it always loads | C (instructions-file) | Gemini (`gemini-extension.json` + `GEMINI.md` + `references/gemini-tools.md`) |
 | has a plugin install command and a manifest `contextFileName` (or equivalent) the installer keeps | C via the plugin installer | Antigravity (`.antigravity-plugin/` — `agy plugin install` ships a generated context file; verify the installer preserves it — Part 6) |
@@ -375,25 +377,24 @@ both double-injects). Find the
 exact field, nesting, and event-matcher values your harness expects. Then
 decide: add a fourth branch to `hooks/session-start`, or — if the harness needs
 a different bootstrap message or env contract — add a dedicated
-`hooks/session-start-<harness>` script, the way Codex did. If you add a branch
+`hooks/session-start-<harness>` script. If you add a branch
 and your harness *also* sets an env var an earlier branch keys on (some harnesses
 set `CLAUDE_PLUGIN_ROOT` too), order your branch before the one that would
 otherwise shadow it. Match the harness's
-own event-matcher strings (Claude Code uses `startup|clear|compact`, Codex
-`startup|resume|clear`, Cursor `sessionStart`); wrong matchers mean the hook
-silently never fires.
+own event-matcher strings (Claude Code uses `startup|clear|compact`, Cursor
+`sessionStart`); wrong matchers mean the hook silently never fires.
 
 The **hook-config schema itself varies per harness** — don't assume the
-Claude/Codex shape is universal. Compare `hooks/hooks.json`,
-`hooks/hooks-codex.json`, and `hooks/hooks-cursor.json`: Cursor's uses
+Claude Code shape is universal. Compare `hooks/hooks.json` and
+`hooks/hooks-cursor.json`: Cursor's uses
 `"version": 1`, a lowercase `sessionStart` key, a relative
-`./hooks/run-hook.cmd` command, and omits the `matcher`/`type`/`async` fields the
-others use. Match your `hooks-<harness>.json` to whichever existing file is
+`./hooks/run-hook.cmd` command, and omits the `matcher`/`type`/`async` fields
+Claude Code uses. Match your `hooks-<harness>.json` to whichever existing file is
 closest, not to a single canonical template.
 
 The hook **command string references a harness-provided plugin-root variable**,
 and its name differs per harness: `hooks.json` uses `${CLAUDE_PLUGIN_ROOT}`,
-`hooks-codex.json` uses `${PLUGIN_ROOT}`, Cursor uses a relative path. Use
+`hooks-cursor.json` uses a relative path. Use
 whatever your harness exports. (The `session-start` script re-derives the root
 itself via `dirname`, so the script body doesn't depend on this — but the
 command in the manifest does.)
@@ -784,7 +785,7 @@ Use this as the live index; when in doubt, read the files, not this table.
 | Harness | Entry point | Bootstrap mechanism | Tool mapping | Tests | Distribution |
 |---|---|---|---|---|---|
 | Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` | shell hook → `hooks/session-start` (`hookSpecificOutput.additionalContext`) | native `Skill` tool; `references/claude-code-tools.md` | `tests/hooks/` | marketplace |
-| Codex | `.codex-plugin/plugin.json` + `hooks/hooks-codex.json` | shell hook → `hooks/session-start-codex` | `references/codex-tools.md` | `tests/codex-plugin-sync/`, `tests/hooks/` | fork sync (`scripts/sync-to-codex-plugin.sh`) |
+| Codex | `.codex-plugin/plugin.json` (declares empty `hooks`) | native skill discovery (no session-start hook) | `references/codex-tools.md` | `tests/codex/`, `tests/codex-plugin-sync/` | fork sync (`scripts/sync-to-codex-plugin.sh`) |
 | Cursor | `.cursor-plugin/plugin.json` + `hooks/hooks-cursor.json` | shell hook → `hooks/session-start` (`additional_context`) | `references/claude-code-tools.md` | `tests/hooks/` | hand-authored |
 | Copilot CLI | (shares Claude Code hook path; `COPILOT_CLI` env) | shell hook → `hooks/session-start` (`additionalContext`) | `references/copilot-tools.md` | `tests/hooks/` | — |
 | Gemini CLI | `gemini-extension.json` + `GEMINI.md` | instructions file `@`-includes bootstrap + mapping | `references/gemini-tools.md` | — | `gemini extensions install` |
@@ -799,10 +800,10 @@ Use this as the live index; when in doubt, read the files, not this table.
 - **Wrong JSON field → silent failure or double injection.** Shape A only.
   Confirm the exact field/nesting; Claude Code reads two fields without dedup.
 - **Hook-config schema varies per harness.** Shape A. Cursor's `hooks-cursor.json`
-  looks nothing like the Claude/Codex one (`version`, lowercase `sessionStart`,
+  looks nothing like the Claude Code one (`version`, lowercase `sessionStart`,
   relative command, no `matcher`/`type`/`async`). Match the closest existing file.
 - **Plugin-root env var differs per harness.** Shape A. The hook command uses
-  `${CLAUDE_PLUGIN_ROOT}` (Claude), `${PLUGIN_ROOT}` (Codex), or a relative path
+  `${CLAUDE_PLUGIN_ROOT}` (Claude) or a relative path
   (Cursor). Use what your harness exports; the script re-derives the root itself.
 - **System-message injection.** Shape B injects a *user* message on purpose
   (#750, #894). Don't "fix" it to a system message.

+ 1 - 1
docs/windows/polyglot-hooks.md

@@ -140,7 +140,7 @@ Check that the script filename is **extensionless** in `hooks.json`. A command l
 
 ### Hook doesn't fire at all
 
-Verify the `matcher` in `hooks.json` matches the event type your harness emits. Claude Code uses `startup|clear|compact`; Codex uses `startup|resume|clear`. Check `hooks-codex.json` for the Codex variant.
+Verify the `matcher` in `hooks.json` matches the event type your harness emits. Claude Code uses `startup|clear|compact`; Cursor uses `sessionStart`. Check `hooks-cursor.json` for the Cursor variant.
 
 ## Related Issues
 

+ 0 - 26
hooks/session-start-codex

@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-# Codex SessionStart hook for superpowers plugin
-
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
-
-using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
-
-escape_for_json() {
-    local s="$1"
-    s="${s//\\/\\\\}"
-    s="${s//\"/\\\"}"
-    s="${s//$'\n'/\\n}"
-    s="${s//$'\r'/\\r}"
-    s="${s//$'\t'/\\t}"
-    printf '%s' "$s"
-}
-
-using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
-session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, follow the Codex skill-loading instructions in that skill:**\n\n${using_superpowers_escaped}\n</EXTREMELY_IMPORTANT>"
-
-printf '{\n  "hookSpecificOutput": {\n    "hookEventName": "SessionStart",\n    "additionalContext": "%s"\n  }\n}\n' "$session_context" | cat
-
-exit 0

+ 4 - 40
tests/hooks/test-session-start.sh

@@ -4,7 +4,6 @@ set -euo pipefail
 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
 REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
 HOOK_UNDER_TEST="$REPO_ROOT/hooks/session-start"
-CODEX_HOOK_UNDER_TEST="$REPO_ROOT/hooks/session-start-codex"
 WRAPPER_UNDER_TEST="$REPO_ROOT/hooks/run-hook.cmd"
 
 FAILURES=0
@@ -154,35 +153,15 @@ assert_command_output \
     CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
     bash "$HOOK_UNDER_TEST"
 
-codex_home="$(make_home codex-plugin-hooks)"
-codex_data="$TEST_ROOT/codex-plugin-hooks/data"
-mkdir -p "$codex_data"
+wrapper_home="$(make_home run-hook-wrapper)"
 assert_command_output \
-    "Codex plugin hooks use dedicated script and emit nested SessionStart additionalContext" \
+    "run-hook.cmd wrapper dispatches to the named session-start script" \
     "nested" \
     "" \
     "" \
-    "$codex_home" \
-    PLUGIN_DATA="$codex_data" \
-    CLAUDE_PLUGIN_DATA="$codex_data" \
-    PLUGIN_ROOT="$REPO_ROOT" \
+    "$wrapper_home" \
     CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
-    bash "$CODEX_HOOK_UNDER_TEST"
-
-codex_wrapper_home="$(make_home codex-wrapper)"
-codex_wrapper_data="$TEST_ROOT/codex-wrapper/data"
-mkdir -p "$codex_wrapper_data"
-assert_command_output \
-    "Codex wrapper path dispatches to dedicated script" \
-    "nested" \
-    "" \
-    "" \
-    "$codex_wrapper_home" \
-    PLUGIN_DATA="$codex_wrapper_data" \
-    CLAUDE_PLUGIN_DATA="$codex_wrapper_data" \
-    PLUGIN_ROOT="$REPO_ROOT" \
-    CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
-    bash "$WRAPPER_UNDER_TEST" session-start-codex
+    bash "$WRAPPER_UNDER_TEST" session-start
 
 cursor_home="$(make_home cursor)"
 assert_command_output \
@@ -217,21 +196,6 @@ assert_command_output \
     CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
     bash "$HOOK_UNDER_TEST"
 
-codex_legacy_home="$(make_home codex-legacy-warning-removed)"
-codex_legacy_data="$TEST_ROOT/codex-legacy-warning-removed/data"
-mkdir -p "$codex_legacy_home/.config/superpowers/skills" "$codex_legacy_data"
-assert_command_output \
-    "Codex SessionStart omits obsolete legacy custom-skill warning" \
-    "nested" \
-    "" \
-    "Superpowers now uses"$'\037'"~/.config/superpowers/skills"$'\037'"~/.claude/skills"$'\037'"legacy" \
-    "$codex_legacy_home" \
-    PLUGIN_DATA="$codex_legacy_data" \
-    CLAUDE_PLUGIN_DATA="$codex_legacy_data" \
-    PLUGIN_ROOT="$REPO_ROOT" \
-    CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
-    bash "$CODEX_HOOK_UNDER_TEST"
-
 if [[ "$FAILURES" -gt 0 ]]; then
     echo "STATUS: FAILED ($FAILURES failure(s))"
     exit 1