Compare commits

..

7 Commits

Author SHA1 Message Date
Drew Ritter
935de5d5ec Simplify Codex hook entrypoint 2026-05-14 15:51:53 -07:00
Drew Ritter
f5c43d6055 test: add Codex native hook drill coverage 2026-05-13 18:21:55 -07:00
Drew Ritter
51514f86c8 feat: support Codex native plugin hooks 2026-05-13 18:21:07 -07:00
Drew Ritter
a57b6c5dc1 docs: plan Codex native hooks implementation 2026-05-13 18:19:42 -07:00
Drew Ritter
de320dce01 docs: record Codex hook contract spike 2026-05-13 18:19:42 -07:00
Drew Ritter
62b64d1674 docs: refine Codex hooks spec after review 2026-05-13 18:19:42 -07:00
Drew Ritter
09f3871be2 docs: specify Codex native hooks parity 2026-05-13 18:19:42 -07:00
8 changed files with 44 additions and 79 deletions

2
evals

Submodule evals updated: e2b37138c8...29957de826

View File

@@ -37,13 +37,13 @@ session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the
# See: https://github.com/obra/superpowers/issues/571
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
# Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
printf '{\n "additional_context": "%s"\n}\n' "$session_context" | cat
printf '{\n "additional_context": "%s"\n}\n' "$session_context"
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
# Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context" | cat
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
else
# Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
printf '{\n "additionalContext": "%s"\n}\n' "$session_context" | cat
printf '{\n "additionalContext": "%s"\n}\n' "$session_context"
fi
exit 0

View File

@@ -21,6 +21,6 @@ escape_for_json() {
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
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
exit 0

View File

@@ -14,26 +14,22 @@ Subagent (general-purpose):
## What Was Implemented
[DESCRIPTION]
{DESCRIPTION}
## Requirements / Plan
[PLAN_OR_REQUIREMENTS]
{PLAN_OR_REQUIREMENTS}
## Git Range to Review
**Base:** [BASE_SHA]
**Head:** [HEAD_SHA]
**Base:** {BASE_SHA}
**Head:** {HEAD_SHA}
```bash
git diff --stat [BASE_SHA]..[HEAD_SHA]
git diff [BASE_SHA]..[HEAD_SHA]
git diff --stat {BASE_SHA}..{HEAD_SHA}
git diff {BASE_SHA}..{HEAD_SHA}
```
## Read-Only Review
Your review is read-only on this checkout. Do not mutate the working tree, the index, HEAD, or branch state in any way. Use tools like `git show`, `git diff`, and `git log` to inspect history. If you need a working copy of a different revision, check it out into a separate temporary directory (e.g. `git worktree add /tmp/review-[SHA] [SHA]`) — never move HEAD on this checkout.
## What to Check
**Plan alignment:**
@@ -126,10 +122,10 @@ Subagent (general-purpose):
```
**Placeholders:**
- `[DESCRIPTION]` — brief summary of what was built
- `[PLAN_OR_REQUIREMENTS]` — what it should do (plan file path, task text, or requirements)
- `[BASE_SHA]` — starting commit
- `[HEAD_SHA]` — ending commit
- `{DESCRIPTION}` — brief summary of what was built
- `{PLAN_OR_REQUIREMENTS}` — what it should do (plan file path, task text, or requirements)
- `{BASE_SHA}` — starting commit
- `{HEAD_SHA}` — ending commit
**Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment

View File

@@ -18,22 +18,6 @@ Subagent (general-purpose):
[From implementer's report]
## Git Range to Review
**Base:** [BASE_SHA — commit before this task]
**Head:** [HEAD_SHA — current commit]
```bash
git diff --stat [BASE_SHA]..[HEAD_SHA]
git diff [BASE_SHA]..[HEAD_SHA]
```
Only read files in this diff. Do not crawl the broader codebase.
## Read-Only Review
Your review is read-only on this checkout. Do not mutate the working tree, the index, HEAD, or branch state in any way. Use tools like `git show`, `git diff`, and `git log` to inspect history. If you need a working copy of a different revision, check it out into a separate temporary directory (e.g. `git worktree add /tmp/review-[SHA] [SHA]`) — never move HEAD on this checkout.
## CRITICAL: Do Not Trust the Report
The implementer finished suspiciously quickly. Their report may be incomplete,

View File

@@ -237,7 +237,7 @@ If you catch yourself thinking:
- "Is that not happening?" - You assumed without verifying
- "Will it show us...?" - You should have added evidence gathering
- "Stop guessing" - You're proposing fixes without understanding
- "Ultra-think this" - Question fundamentals, not just symptoms
- "Ultrathink this" - Question fundamentals, not just symptoms
- "We're stuck?" (frustrated) - Your approach isn't working
**When you see these:** STOP. Return to Phase 1.

View File

@@ -102,15 +102,15 @@ These thoughts mean STOP—you're rationalizing:
When multiple skills could apply, use this order:
1. **Process skills first** (brainstorming, systematic-debugging) - these determine HOW to approach the task
1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
"Let's build X" → brainstorming first, then implementation skills.
"Fix this bug" → systematic-debugging first, then domain-specific skills.
"Fix this bug" → debugging first, then domain-specific skills.
## Skill Types
**Rigid** (TDD, systematic-debugging): Follow exactly. Don't adapt away discipline.
**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.
**Flexible** (patterns): Adapt principles to context.

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
# Windows lifecycle tests for the brainstorm server.
#
# Verifies brainstorm server lifecycle behavior, including:
# - Windows/MSYS2 foreground mode and empty OWNER_PID handling
# - Server survival past the 60-second lifecycle check window
# - Dead-at-startup OWNER_PID validation (logged, monitoring disabled)
# - Clean stop-server.sh shutdown
# Verifies that the brainstorm server survives the 60-second lifecycle
# check on Windows, where OWNER_PID monitoring is disabled because the
# MSYS2 PID namespace is invisible to Node.js.
#
# Requirements:
# - Node.js in PATH
@@ -22,7 +20,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="${SUPERPOWERS_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
START_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/start-server.sh"
STOP_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/stop-server.sh"
SERVER_SCRIPT="$REPO_ROOT/skills/brainstorming/scripts/server.cjs"
SERVER_JS="$REPO_ROOT/skills/brainstorming/scripts/server.js"
TEST_DIR="${TMPDIR:-/tmp}/brainstorm-win-test-$$"
@@ -66,7 +64,7 @@ skip() {
wait_for_server_info() {
local dir="$1"
for _ in $(seq 1 50); do
if [[ -f "$dir/state/server-info" ]]; then
if [[ -f "$dir/.server-info" ]]; then
return 0
fi
sleep 0.1
@@ -75,9 +73,9 @@ wait_for_server_info() {
}
get_port_from_info() {
# Read the port from state/server-info. Use grep/sed instead of Node.js
# Read the port from .server-info. Use grep/sed instead of Node.js
# to avoid MSYS2-to-Windows path translation issues.
grep -o '"port":[0-9]*' "$1/state/server-info" | head -1 | sed 's/"port"://'
grep -o '"port":[0-9]*' "$1/.server-info" | head -1 | sed 's/"port"://'
}
http_check() {
@@ -216,11 +214,11 @@ BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/survival/.server.log" 2>&1 &
node "$SERVER_JS" > "$TEST_DIR/survival/.server.log" 2>&1 &
SERVER_PID=$!
if ! wait_for_server_info "$TEST_DIR/survival"; then
fail "Server starts successfully" "Server did not write state/server-info within 5 seconds"
fail "Server starts successfully" "Server did not write .server-info within 5 seconds"
kill "$SERVER_PID" 2>/dev/null || true
SERVER_PID=""
else
@@ -256,15 +254,10 @@ else
SERVER_PID=""
fi
# ========== Test 5: Dead-at-startup OWNER_PID is logged but does not kill the server ==========
#
# The server validates BRAINSTORM_OWNER_PID at startup. If it's already dead,
# the PID resolution was wrong (common on WSL, Tailscale SSH, cross-user
# scenarios). The server logs 'owner-pid-invalid', disables owner monitoring,
# and continues running. The idle timeout becomes the only shutdown trigger.
# ========== Test 5: Bad OWNER_PID causes shutdown (control) ==========
echo ""
echo "--- Dead-at-startup OWNER_PID: server survives, logs owner-pid-invalid ---"
echo "--- Control: Bad OWNER_PID causes shutdown ---"
mkdir -p "$TEST_DIR/control"
@@ -279,41 +272,33 @@ BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="$BAD_PID" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/control/.server.log" 2>&1 &
node "$SERVER_JS" > "$TEST_DIR/control/.server.log" 2>&1 &
CONTROL_PID=$!
if ! wait_for_server_info "$TEST_DIR/control"; then
fail "Control server starts" "Server did not write state/server-info within 5 seconds"
fail "Control server starts" "Server did not write .server-info within 5 seconds"
kill "$CONTROL_PID" 2>/dev/null || true
CONTROL_PID=""
else
pass "Control server starts with dead-at-startup OWNER_PID=$BAD_PID"
pass "Control server starts with bad OWNER_PID=$BAD_PID"
echo " Waiting ~75s to verify server survives past lifecycle check..."
echo " Waiting ~75s for lifecycle check to kill server..."
sleep 75
if kill -0 "$CONTROL_PID" 2>/dev/null; then
pass "Server survives with dead-at-startup OWNER_PID (owner monitoring disabled)"
fail "Control server self-terminates with bad OWNER_PID" \
"Server is still alive (expected it to die)"
kill "$CONTROL_PID" 2>/dev/null || true
else
fail "Server survives with dead-at-startup OWNER_PID" \
"Server died unexpectedly. Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
fi
if grep -q "owner-pid-invalid" "$TEST_DIR/control/.server.log" 2>/dev/null; then
pass "Server logs 'owner-pid-invalid' for dead-at-startup PID"
else
fail "Server logs 'owner-pid-invalid' for dead-at-startup PID" \
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
pass "Control server self-terminates with bad OWNER_PID"
fi
if grep -q "owner process exited" "$TEST_DIR/control/.server.log" 2>/dev/null; then
fail "No spurious 'owner process exited' log" \
"Found 'owner process exited' but owner monitoring should be disabled"
pass "Control server logs 'owner process exited'"
else
pass "No spurious 'owner process exited' log"
fail "Control server logs 'owner process exited'" \
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
fi
kill "$CONTROL_PID" 2>/dev/null || true
fi
wait "$CONTROL_PID" 2>/dev/null || true
@@ -324,16 +309,16 @@ CONTROL_PID=""
echo ""
echo "--- Clean Shutdown ---"
mkdir -p "$TEST_DIR/stop-test/state"
mkdir -p "$TEST_DIR/stop-test"
BRAINSTORM_DIR="$TEST_DIR/stop-test" \
BRAINSTORM_HOST="127.0.0.1" \
BRAINSTORM_URL_HOST="localhost" \
BRAINSTORM_OWNER_PID="" \
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
node "$SERVER_SCRIPT" > "$TEST_DIR/stop-test/.server.log" 2>&1 &
node "$SERVER_JS" > "$TEST_DIR/stop-test/.server.log" 2>&1 &
STOP_TEST_PID=$!
echo "$STOP_TEST_PID" > "$TEST_DIR/stop-test/state/server.pid"
echo "$STOP_TEST_PID" > "$TEST_DIR/stop-test/.server.pid"
if ! wait_for_server_info "$TEST_DIR/stop-test"; then
fail "Stop-test server starts" "Server did not start"