Compare commits

..

5 Commits

Author SHA1 Message Date
Jesse Vincent
b18647194e Gemini CLI has been EOLed by Google as of 6/18/26 2026-06-24 11:19:20 -07:00
Jesse Vincent
e24f65cf01 Continued pruning of tokens we shouldn't need for modern agents 2026-06-24 11:15:14 -07:00
Jesse Vincent
f8997c7aa8 Rremove a ton of agentic boilerplate around per-harness tools 2026-06-24 11:06:52 -07:00
Jesse Vincent
b3b4535dcd Some manual tweaking of the bootstrap 2026-06-24 11:02:40 -07:00
Jesse Vincent
274cf1617b WIP snapshot: compress using-superpowers bootstrap (~1698 → ~993 tokens)
Condense the injected bootstrap without dropping behavior-shaping content:
replace the graphviz flowchart with prose (1% rule, plan-mode->brainstorm gate,
announce + checklist->todos), fold Instruction-Priority into User Instructions,
and drop the per-platform skill-loading section. Keep the full Red Flags
rationalization table (all 12), the platform tool-mapping pointer (now a
skill-relative path list), skill priority framed as a category (process before
implementation, not just the two named skills), and user-instruction precedence
plus the WHAT/HOW guard.

Snapshot on a local branch for review — NOT final, NOT for dev. Open items:
the dropped "Skill Types" (rigid/flexible) section, and evals for user
preferences overriding skills. Clean Docker evals show the more-aggressive
g-minimal preserves load-bearing triggering across opus/sonnet/haiku/codex/
gemini/kimi; this variant keeps more content.

Claude-Session: https://claude.ai/code/session_01Hz32pBE7kiqr78DY6PWmZN
2026-06-24 10:54:25 -07:00
14 changed files with 117 additions and 73 deletions

View File

@@ -9,7 +9,7 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
"version": "6.1.0", "version": "6.0.3",
"source": "./", "source": "./",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",

View File

@@ -1,7 +1,7 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
"version": "6.1.0", "version": "6.0.3",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",
"email": "jesse@fsck.com" "email": "jesse@fsck.com"

View File

@@ -1,6 +1,6 @@
{ {
"name": "superpowers", "name": "superpowers",
"version": "6.1.0", "version": "6.0.3",
"description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.", "description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",
@@ -21,7 +21,7 @@
"workflow" "workflow"
], ],
"skills": "./skills/", "skills": "./skills/",
"hooks": {}, "hooks": "./hooks/hooks-codex.json",
"interface": { "interface": {
"displayName": "Superpowers", "displayName": "Superpowers",
"shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents", "shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",

View File

@@ -2,7 +2,7 @@
"name": "superpowers", "name": "superpowers",
"displayName": "Superpowers", "displayName": "Superpowers",
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
"version": "6.1.0", "version": "6.0.3",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",
"email": "jesse@fsck.com" "email": "jesse@fsck.com"

View File

@@ -1,6 +1,6 @@
{ {
"name": "superpowers", "name": "superpowers",
"version": "6.1.0", "version": "6.0.3",
"description": "An agentic skills framework and software development methodology.", "description": "An agentic skills framework and software development methodology.",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",

View File

@@ -1,23 +1,5 @@
# Superpowers Release Notes # Superpowers Release Notes
## v6.1.0 (2026-06-30)
### Lower Per-Session Token Cost
The `using-superpowers` bootstrap is injected into every session, so its size is paid for constantly. This release trims it and the per-harness references it points to, without dropping behavior-shaping content.
- **Compressed the `using-superpowers` bootstrap.** Replaced the graphviz skill-flow diagram with the prose it encoded, folded the standalone Instruction-Priority section into User Instructions, dropped the per-platform "How to Access Skills" walkthrough, and trimmed the Platform Adaptation pointer to the harnesses that still ship a reference file. The full Red Flags rationalization table and the user-instruction precedence rules are unchanged.
- **Pruned the per-harness tool-mapping references.** The verbose action-to-tool tables restated guidance modern agents already follow. Each reference file is trimmed to the harness-specific notes that still carry weight — subagent dispatch, task tracking, instructions-file paths — and `claude-code-tools.md` and `copilot-tools.md`, which had nothing harness-specific left, are deleted.
### Codex
- **Codex can install from the marketplace.** Codex marketplace sources expect a `.agents/plugins/marketplace.json` at the marketplace root; the repo only shipped the Claude marketplace file, so Codex could name the marketplace but found no installable plugin entries. A repo-local Codex marketplace manifest now points at the same repository root, so the plugin is installable from Codex.
- **Codex no longer ships a SessionStart hook.** Codex reliably triggers skills on its own, and the bootstrap hook made the UX worse rather than better. The Codex hook config (`hooks-codex.json`) and its manifest registration are removed.
### Harness Support
- **Gemini CLI support removed.** Google EOLed the Gemini CLI on 2026-06-18; the extension can no longer be installed or updated. Gemini is gone from the install docs, the subagent-capable platform lists, and the eval-harness description, and its tool-mapping reference is deleted.
## v6.0.3 (2026-06-18) ## v6.0.3 (2026-06-18)
### Subagent-Driven Development ### Subagent-Driven Development

View File

@@ -90,7 +90,7 @@ every session, with no per-session opt-in by your human partner.** This is the
one non-negotiable capability. It can take any form: one non-negotiable capability. It can take any form:
- a **hook/event system** that runs a shell command at session start and reads - a **hook/event system** that runs a shell command at session start and reads
its stdout (Claude Code, Cursor, Copilot CLI), or its stdout (Claude Code, Codex, Cursor, Copilot CLI), or
- an **in-process plugin/extension** with a session-start or message lifecycle - an **in-process plugin/extension** with a session-start or message lifecycle
callback that can mutate the message array (OpenCode, pi), or callback that can mutate the message array (OpenCode, pi), or
- an **instructions-file** convention where the harness loads a context file that - an **instructions-file** convention where the harness loads a context file that
@@ -227,20 +227,18 @@ 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 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 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 polyglot wrapper that just locates bash and dispatches the named script; the
script (`hooks/session-start`, or a harness-specific variant) is what reads script (`hooks/session-start`, or a harness-specific variant like
`using-superpowers/SKILL.md` and prints a JSON object whose **field name and `hooks/session-start-codex`) is what reads `using-superpowers/SKILL.md` and
nesting differ per harness**. prints a JSON object whose **field name and nesting differ per harness**.
- Reference: `hooks/session-start`, `hooks/run-hook.cmd`, and the per-harness - Reference: `hooks/session-start` (and `hooks/session-start-codex`),
hook config `hooks/hooks.json` (Claude Code) and `hooks/hooks-cursor.json` `hooks/run-hook.cmd`, and the per-harness hook config `hooks/hooks.json`
(Claude Code), `hooks/hooks-codex.json` (Codex), `hooks/hooks-cursor.json`
(Cursor). (Cursor).
- Manifests: `.cursor-plugin/plugin.json` is the Shape A manifest example that - Manifests: `.codex-plugin/plugin.json`, `.cursor-plugin/plugin.json` point the
points the harness at `./skills/` and the right `hooks-*.json`. Claude Code's harness at `./skills/` and the right `hooks-*.json`. (Claude Code's
`.claude-plugin/plugin.json` sets neither field — it auto-discovers `skills/` `.claude-plugin/plugin.json` sets neither field — it auto-discovers `skills/`
and `hooks/hooks.json` by convention. Do **not** copy Codex's and `hooks/hooks.json` by convention.)
`.codex-plugin/plugin.json` for Shape A: it declares an empty `hooks` object
specifically to suppress Codex's `hooks/hooks.json` auto-discovery, because
Codex surfaces skills natively and runs no session-start hook.
> **A hook *system* is not a session-start *event*.** A harness can have a > **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 > `hooks.json` mechanism — and even contain the literal string `SessionStart` in
@@ -289,7 +287,7 @@ part of the installed extension** — never substitute "edit the user's global
| If the harness… | Use shape | Copy from | | If the harness… | Use shape | Copy from |
|---|---|---| |---|---|---|
| runs a shell command at session start and reads its stdout | A (shell-hook) | Cursor (`hooks/session-start` + `hooks/hooks-cursor.json` + `.cursor-plugin/`) | | 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/`) |
| 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 | | 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`) | | 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) | | 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) |
@@ -311,7 +309,7 @@ patterns below are summaries; the code is the spec.
Create whatever the harness uses to recognize the plugin. Match the existing Create whatever the harness uses to recognize the plugin. Match the existing
ones in spirit: ones in spirit:
- **Shape A:** a `*-plugin/plugin.json` (see `.cursor-plugin/plugin.json`) with - **Shape A:** a `*-plugin/plugin.json` (see `.codex-plugin/plugin.json`) with
`name`, `version`, `description`, author/license/keywords, `"skills": `name`, `version`, `description`, author/license/keywords, `"skills":
"./skills/"`, and `"hooks": "./hooks/hooks-<harness>.json"`. Plus the "./skills/"`, and `"hooks": "./hooks/hooks-<harness>.json"`. Plus the
`hooks-<harness>.json` itself, registering a session-start hook whose command `hooks-<harness>.json` itself, registering a session-start hook whose command
@@ -377,24 +375,25 @@ both double-injects). Find the
exact field, nesting, and event-matcher values your harness expects. Then 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 decide: add a fourth branch to `hooks/session-start`, or — if the harness needs
a different bootstrap message or env contract — add a dedicated a different bootstrap message or env contract — add a dedicated
`hooks/session-start-<harness>` script. If you add a branch `hooks/session-start-<harness>` script, the way Codex did. If you add a branch
and your harness *also* sets an env var an earlier branch keys on (some harnesses 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 set `CLAUDE_PLUGIN_ROOT` too), order your branch before the one that would
otherwise shadow it. Match the harness's otherwise shadow it. Match the harness's
own event-matcher strings (Claude Code uses `startup|clear|compact`, Cursor own event-matcher strings (Claude Code uses `startup|clear|compact`, Codex
`sessionStart`); wrong matchers mean the hook silently never fires. `startup|resume|clear`, Cursor `sessionStart`); wrong matchers mean the hook
silently never fires.
The **hook-config schema itself varies per harness** — don't assume the The **hook-config schema itself varies per harness** — don't assume the
Claude Code shape is universal. Compare `hooks/hooks.json` and Claude/Codex shape is universal. Compare `hooks/hooks.json`,
`hooks/hooks-cursor.json`: Cursor's uses `hooks/hooks-codex.json`, and `hooks/hooks-cursor.json`: Cursor's uses
`"version": 1`, a lowercase `sessionStart` key, a relative `"version": 1`, a lowercase `sessionStart` key, a relative
`./hooks/run-hook.cmd` command, and omits the `matcher`/`type`/`async` fields `./hooks/run-hook.cmd` command, and omits the `matcher`/`type`/`async` fields the
Claude Code uses. Match your `hooks-<harness>.json` to whichever existing file is others use. Match your `hooks-<harness>.json` to whichever existing file is
closest, not to a single canonical template. closest, not to a single canonical template.
The hook **command string references a harness-provided plugin-root variable**, The hook **command string references a harness-provided plugin-root variable**,
and its name differs per harness: `hooks.json` uses `${CLAUDE_PLUGIN_ROOT}`, and its name differs per harness: `hooks.json` uses `${CLAUDE_PLUGIN_ROOT}`,
`hooks-cursor.json` uses a relative path. Use `hooks-codex.json` uses `${PLUGIN_ROOT}`, Cursor uses a relative path. Use
whatever your harness exports. (The `session-start` script re-derives the root 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 itself via `dirname`, so the script body doesn't depend on this — but the
command in the manifest does.) command in the manifest does.)
@@ -785,7 +784,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 | | 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 | | 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` (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`) | | 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`) |
| 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 | | 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/` | — | | 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` | | Gemini CLI | `gemini-extension.json` + `GEMINI.md` | instructions file `@`-includes bootstrap + mapping | `references/gemini-tools.md` | — | `gemini extensions install` |
@@ -800,10 +799,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. - **Wrong JSON field → silent failure or double injection.** Shape A only.
Confirm the exact field/nesting; Claude Code reads two fields without dedup. 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` - **Hook-config schema varies per harness.** Shape A. Cursor's `hooks-cursor.json`
looks nothing like the Claude Code one (`version`, lowercase `sessionStart`, looks nothing like the Claude/Codex one (`version`, lowercase `sessionStart`,
relative command, no `matcher`/`type`/`async`). Match the closest existing file. relative command, no `matcher`/`type`/`async`). Match the closest existing file.
- **Plugin-root env var differs per harness.** Shape A. The hook command uses - **Plugin-root env var differs per harness.** Shape A. The hook command uses
`${CLAUDE_PLUGIN_ROOT}` (Claude) or a relative path `${CLAUDE_PLUGIN_ROOT}` (Claude), `${PLUGIN_ROOT}` (Codex), or a relative path
(Cursor). Use what your harness exports; the script re-derives the root itself. (Cursor). Use what your harness exports; the script re-derives the root itself.
- **System-message injection.** Shape B injects a *user* message on purpose - **System-message injection.** Shape B injects a *user* message on purpose
(#750, #894). Don't "fix" it to a system message. (#750, #894). Don't "fix" it to a system message.

View File

@@ -140,7 +140,7 @@ Check that the script filename is **extensionless** in `hooks.json`. A command l
### Hook doesn't fire at all ### 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`; Cursor uses `sessionStart`. Check `hooks-cursor.json` for the Cursor variant. 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.
## Related Issues ## Related Issues

View File

@@ -1,6 +1,6 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
"version": "6.1.0", "version": "6.0.3",
"contextFileName": "GEMINI.md" "contextFileName": "GEMINI.md"
} }

16
hooks/hooks-codex.json Normal file
View File

@@ -0,0 +1,16 @@
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|clear|compact",
"hooks": [
{
"type": "command",
"command": "\"${PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start-codex",
"async": false
}
]
}
]
}
}

26
hooks/session-start-codex Executable file
View File

@@ -0,0 +1,26 @@
#!/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

View File

@@ -1,6 +1,6 @@
{ {
"name": "superpowers", "name": "superpowers",
"version": "6.1.0", "version": "6.0.3",
"description": "Superpowers skills and runtime bootstrap for coding agents", "description": "Superpowers skills and runtime bootstrap for coding agents",
"type": "module", "type": "module",
"main": ".opencode/plugins/superpowers.js", "main": ".opencode/plugins/superpowers.js",

View File

@@ -51,25 +51,10 @@ if not plugin_manifest.exists():
manifest = json.loads(plugin_manifest.read_text(encoding="utf-8")) manifest = json.loads(plugin_manifest.read_text(encoding="utf-8"))
assert_equal(manifest.get("name"), plugin.get("name"), "plugin manifest name") 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( assert_equal(
manifest.get("hooks"), manifest.get("hooks"),
{}, "./hooks/hooks-codex.json",
"Codex manifest must declare empty hooks {} to suppress hooks/hooks.json auto-discovery", "Codex hooks manifest",
) )
print("Codex marketplace manifest looks good") print("Codex marketplace manifest looks good")

View File

@@ -4,6 +4,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
HOOK_UNDER_TEST="$REPO_ROOT/hooks/session-start" 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" WRAPPER_UNDER_TEST="$REPO_ROOT/hooks/run-hook.cmd"
FAILURES=0 FAILURES=0
@@ -153,15 +154,35 @@ assert_command_output \
CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \ CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
bash "$HOOK_UNDER_TEST" bash "$HOOK_UNDER_TEST"
wrapper_home="$(make_home run-hook-wrapper)" codex_home="$(make_home codex-plugin-hooks)"
codex_data="$TEST_ROOT/codex-plugin-hooks/data"
mkdir -p "$codex_data"
assert_command_output \ assert_command_output \
"run-hook.cmd wrapper dispatches to the named session-start script" \ "Codex plugin hooks use dedicated script and emit nested SessionStart additionalContext" \
"nested" \ "nested" \
"" \ "" \
"" \ "" \
"$wrapper_home" \ "$codex_home" \
PLUGIN_DATA="$codex_data" \
CLAUDE_PLUGIN_DATA="$codex_data" \
PLUGIN_ROOT="$REPO_ROOT" \
CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \ CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
bash "$WRAPPER_UNDER_TEST" session-start 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
cursor_home="$(make_home cursor)" cursor_home="$(make_home cursor)"
assert_command_output \ assert_command_output \
@@ -196,6 +217,21 @@ assert_command_output \
CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \ CLAUDE_PLUGIN_ROOT="$REPO_ROOT" \
bash "$HOOK_UNDER_TEST" 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 if [[ "$FAILURES" -gt 0 ]]; then
echo "STATUS: FAILED ($FAILURES failure(s))" echo "STATUS: FAILED ($FAILURES failure(s))"
exit 1 exit 1