mirror of
https://github.com/obra/superpowers.git
synced 2026-04-21 00:49:06 +08:00
Compare commits
45 Commits
opencode-c
...
drew/pri-8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20fabcd1d7 | ||
|
|
f146752b8d | ||
|
|
2cbbd8ce88 | ||
|
|
97677b2b24 | ||
|
|
46078a1a90 | ||
|
|
4351ee23dc | ||
|
|
c319e2be6d | ||
|
|
9c63edc732 | ||
|
|
a26ab96bad | ||
|
|
747355018b | ||
|
|
c141508f36 | ||
|
|
7820adcde7 | ||
|
|
250dea46fd | ||
|
|
477c55386a | ||
|
|
cb4745eeb5 | ||
|
|
872ec69f4c | ||
|
|
e0fcfaf838 | ||
|
|
5bf3f77483 | ||
|
|
8a0a5ca6a3 | ||
|
|
2d46da1b37 | ||
|
|
0002948041 | ||
|
|
3128a2c3cd | ||
|
|
f34ee479b7 | ||
|
|
1128a721ca | ||
|
|
d1b5f578b0 | ||
|
|
61a64d7098 | ||
|
|
825a142aa3 | ||
|
|
bd537d817d | ||
|
|
24be2e8b7c | ||
|
|
a479e10050 | ||
|
|
a4c48714bc | ||
|
|
2c6a8a352d | ||
|
|
2b25774f31 | ||
|
|
f4b54a1717 | ||
|
|
911fa1d6c5 | ||
|
|
4e7c0842f8 | ||
|
|
689f27c968 | ||
|
|
537ec640fd | ||
|
|
c5e9538311 | ||
|
|
fd318b1b79 | ||
|
|
ea472dedf0 | ||
|
|
addfe8511a | ||
|
|
c6a2b1b576 | ||
|
|
6d21e9cc07 | ||
|
|
687a66183d |
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.5",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.5",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"skills": "./skills/",
|
||||
"agents": "./agents/",
|
||||
"commands": "./commands/",
|
||||
"hooks": "./hooks/hooks.json"
|
||||
"hooks": "./hooks/hooks-cursor.json"
|
||||
}
|
||||
|
||||
@@ -3,107 +3,71 @@
|
||||
## Prerequisites
|
||||
|
||||
- [OpenCode.ai](https://opencode.ai) installed
|
||||
- Git installed
|
||||
|
||||
## Installation Steps
|
||||
## Installation
|
||||
|
||||
### 1. Clone Superpowers
|
||||
Add superpowers to the `plugin` array in your `opencode.json` (global or project-level):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the Plugin
|
||||
Restart OpenCode. That's it — the plugin auto-installs and registers all skills.
|
||||
|
||||
Create a symlink so OpenCode discovers the plugin:
|
||||
Verify by asking: "Tell me about your superpowers"
|
||||
|
||||
## Migrating from the old symlink-based install
|
||||
|
||||
If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/plugins
|
||||
# Remove old symlinks
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
```
|
||||
|
||||
### 3. Symlink Skills
|
||||
|
||||
Create a symlink so OpenCode's native skill tool discovers superpowers skills:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
|
||||
# Optionally remove the cloned repo
|
||||
rm -rf ~/.config/opencode/superpowers
|
||||
|
||||
# Remove skills.paths from opencode.json if you added one for superpowers
|
||||
```
|
||||
|
||||
### 4. Restart OpenCode
|
||||
|
||||
Restart OpenCode. The plugin will automatically inject superpowers context.
|
||||
|
||||
Verify by asking: "do you have superpowers?"
|
||||
Then follow the installation steps above.
|
||||
|
||||
## Usage
|
||||
|
||||
### Finding Skills
|
||||
|
||||
Use OpenCode's native `skill` tool to list available skills:
|
||||
Use OpenCode's native `skill` tool:
|
||||
|
||||
```
|
||||
use skill tool to list skills
|
||||
```
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
Use OpenCode's native `skill` tool to load a specific skill:
|
||||
|
||||
```
|
||||
use skill tool to load superpowers/brainstorming
|
||||
```
|
||||
|
||||
### Personal Skills
|
||||
|
||||
Create your own skills in `~/.config/opencode/skills/`:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills/my-skill
|
||||
```
|
||||
|
||||
Create `~/.config/opencode/skills/my-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
### Project Skills
|
||||
|
||||
Create project-specific skills in `.opencode/skills/` within your project.
|
||||
|
||||
**Skill Priority:** Project skills > Personal skills > Superpowers skills
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode/superpowers
|
||||
git pull
|
||||
Superpowers updates automatically when you restart OpenCode.
|
||||
|
||||
To pin a specific version:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git#v5.0.3"]
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin symlink: `ls -l ~/.config/opencode/plugins/superpowers.js`
|
||||
2. Check source exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
3. Check OpenCode logs for errors
|
||||
1. Check logs: `opencode run --print-logs "hello" 2>&1 | grep -i superpowers`
|
||||
2. Verify the plugin line in your `opencode.json`
|
||||
3. Make sure you're running a recent version of OpenCode
|
||||
|
||||
### Skills not found
|
||||
|
||||
1. Check skills symlink: `ls -l ~/.config/opencode/skills/superpowers`
|
||||
2. Verify it points to: `~/.config/opencode/superpowers/skills`
|
||||
3. Use `skill` tool to list what's discovered
|
||||
1. Use `skill` tool to list what's discovered
|
||||
2. Check that the plugin is loading (see above)
|
||||
|
||||
### Tool mapping
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Superpowers plugin for OpenCode.ai
|
||||
*
|
||||
* Injects superpowers bootstrap context via system prompt transform.
|
||||
* Skills are discovered via OpenCode's native skill tool from symlinked directory.
|
||||
* Auto-registers skills directory via config hook (no symlinks needed).
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
@@ -84,6 +84,18 @@ ${toolMapping}
|
||||
};
|
||||
|
||||
return {
|
||||
// Inject skills path into live config so OpenCode discovers superpowers skills
|
||||
// without requiring manual symlinks or config file edits.
|
||||
// This works because Config.get() returns a cached singleton — modifications
|
||||
// here are visible when skills are lazily discovered later.
|
||||
config: async (config) => {
|
||||
config.skills = config.skills || {};
|
||||
config.skills.paths = config.skills.paths || [];
|
||||
if (!config.skills.paths.includes(superpowersSkillsDir)) {
|
||||
config.skills.paths.push(superpowersSkillsDir);
|
||||
}
|
||||
},
|
||||
|
||||
// Use system prompt transform to inject bootstrap (fixes #226 agent reset bug)
|
||||
'experimental.chat.system.transform': async (_input, output) => {
|
||||
const bootstrap = getBootstrapContent();
|
||||
|
||||
13
CHANGELOG.md
Normal file
13
CHANGELOG.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## [5.0.5] - 2026-03-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Brainstorm server ESM fix**: Renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. ([PR #784](https://github.com/obra/superpowers/pull/784) by @sarbojitrana, fixes [#774](https://github.com/obra/superpowers/issues/774), [#780](https://github.com/obra/superpowers/issues/780), [#783](https://github.com/obra/superpowers/issues/783))
|
||||
- **Brainstorm owner-PID on Windows**: Skip `BRAINSTORM_OWNER_PID` lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js. Prevents the server from self-terminating after 60 seconds. The 30-minute idle timeout remains as the safety net. ([#770](https://github.com/obra/superpowers/issues/770), docs from [PR #768](https://github.com/obra/superpowers/pull/768) by @lucasyhzhu-debug)
|
||||
- **stop-server.sh reliability**: Verify the server process actually died before reporting success. Waits up to 2 seconds for graceful shutdown, escalates to `SIGKILL`, and reports failure if the process survives. ([#723](https://github.com/obra/superpowers/issues/723))
|
||||
|
||||
### Changed
|
||||
|
||||
- **Execution handoff**: Restore user choice between subagent-driven-development and executing-plans after plan writing. Subagent-driven is recommended but no longer mandatory. (Reverts `5e51c3e`)
|
||||
@@ -1,10 +1,52 @@
|
||||
# Superpowers Release Notes
|
||||
|
||||
## v5.0.5 (2026-03-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Brainstorm server ESM fix** — renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. (PR #784 by @sarbojitrana, fixes #774, #780, #783)
|
||||
- **Brainstorm owner-PID on Windows** — skip PID lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js, preventing the server from self-terminating after 60 seconds. (#770, docs from PR #768 by @lucasyhzlu-debug)
|
||||
- **stop-server.sh reliability** — verify the server process actually died before reporting success. SIGTERM + 2s wait + SIGKILL fallback. (#723)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Execution handoff** — restore user choice between subagent-driven and inline execution after plan writing. Subagent-driven is recommended but no longer mandatory.
|
||||
|
||||
## v5.0.4 (2026-03-16)
|
||||
|
||||
### Review Loop Refinements
|
||||
|
||||
Dramatically reduces token usage and speeds up spec and plan reviews by eliminating unnecessary review passes and tightening reviewer focus.
|
||||
|
||||
- **Single whole-plan review** — plan reviewer now reviews the complete plan in one pass instead of chunk-by-chunk. Removed all chunk-related concepts (`## Chunk N:` headings, 1000-line chunk limits, per-chunk dispatch).
|
||||
- **Raised the bar for blocking issues** — both spec and plan reviewer prompts now include a "Calibration" section: only flag issues that would cause real problems during implementation. Minor wording, stylistic preferences, and formatting quibbles should not block approval.
|
||||
- **Reduced max review iterations** — from 5 to 3 for both spec and plan review loops. If the reviewer is calibrated correctly, 3 rounds is plenty.
|
||||
- **Streamlined reviewer checklists** — spec reviewer trimmed from 7 categories to 5; plan reviewer from 7 to 4. Removed formatting-focused checks (task syntax, chunk size) in favor of substance (buildability, spec alignment).
|
||||
|
||||
### OpenCode
|
||||
|
||||
- **One-line plugin install** — OpenCode plugin now auto-registers the skills directory via a `config` hook. No symlinks or `skills.paths` config needed. Install is just adding one line to `opencode.json`. (PR #753)
|
||||
- **Added `package.json`** so OpenCode can install superpowers as an npm package from git.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Verify server actually stopped** — `stop-server.sh` now confirms the process is dead before reporting success. SIGTERM + 2s wait + SIGKILL fallback. Reports failure if the process survives. (PR #751)
|
||||
- **Generic agent language** — brainstorm companion waiting page now says "the agent" instead of "Claude".
|
||||
|
||||
## v5.0.3 (2026-03-15)
|
||||
|
||||
### Cursor Support
|
||||
|
||||
- **Cursor hooks** — added `hooks/hooks-cursor.json` with Cursor's camelCase format (`sessionStart`, `version: 1`) and updated `.cursor-plugin/plugin.json` to reference it. Fixed platform detection in `session-start` to check `CURSOR_PLUGIN_ROOT` first (Cursor may also set `CLAUDE_PLUGIN_ROOT`). (Based on PR #709)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Stop firing SessionStart hook on `--resume`** — the startup hook was re-injecting context on resumed sessions, which already have the context in their conversation history. The hook now fires only on `startup`, `clear`, and `compact`.
|
||||
- **Bash 5.3+ hook hang** — replaced heredoc (`cat <<EOF`) with `printf` in `hooks/session-start`. Fixes indefinite hang on macOS with Homebrew bash 5.3+ caused by a bash regression with large variable expansion in heredocs. (#572, #571)
|
||||
- **POSIX-safe hook script** — replaced `${BASH_SOURCE[0]:-$0}` with `$0` in `hooks/session-start`. Fixes "Bad substitution" error on Ubuntu/Debian where `/bin/sh` is dash. (#553)
|
||||
- **Portable shebangs** — replaced `#!/bin/bash` with `#!/usr/bin/env bash` in all shell scripts. Fixes execution on NixOS, FreeBSD, and macOS with Homebrew bash where `/bin/bash` is outdated or missing. (#700)
|
||||
- **Brainstorm server on Windows** — auto-detect Windows/Git Bash (`OSTYPE=msys*`, `MSYSTEM`) and switch to foreground mode, fixing silent server failure caused by `nohup`/`disown` process reaping. (#737)
|
||||
- **Codex docs fix** — replaced deprecated `collab` flag with `multi_agent` in Codex documentation. (PR #749)
|
||||
|
||||
## v5.0.2 (2026-03-11)
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp
|
||||
|
||||
3. Restart Codex.
|
||||
|
||||
4. **For subagent skills** (optional): Skills like `dispatching-parallel-agents` and `subagent-driven-development` require Codex's collab feature. Add to your Codex config:
|
||||
4. **For subagent skills** (optional): Skills like `dispatching-parallel-agents` and `subagent-driven-development` require Codex's multi-agent feature. Add to your Codex config:
|
||||
```toml
|
||||
[features]
|
||||
collab = true
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -2,169 +2,36 @@
|
||||
|
||||
Complete guide for using Superpowers with [OpenCode.ai](https://opencode.ai).
|
||||
|
||||
## Quick Install
|
||||
## Installation
|
||||
|
||||
Tell OpenCode:
|
||||
Add superpowers to the `plugin` array in your `opencode.json` (global or project-level):
|
||||
|
||||
```
|
||||
Clone https://github.com/obra/superpowers to ~/.config/opencode/superpowers, then create directory ~/.config/opencode/plugins, then symlink ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js to ~/.config/opencode/plugins/superpowers.js, then symlink ~/.config/opencode/superpowers/skills to ~/.config/opencode/skills/superpowers, then restart opencode.
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]
|
||||
}
|
||||
```
|
||||
|
||||
## Manual Installation
|
||||
Restart OpenCode. The plugin auto-installs via Bun and registers all skills automatically.
|
||||
|
||||
### Prerequisites
|
||||
Verify by asking: "Tell me about your superpowers"
|
||||
|
||||
- [OpenCode.ai](https://opencode.ai) installed
|
||||
- Git installed
|
||||
### Migrating from the old symlink-based install
|
||||
|
||||
### macOS / Linux
|
||||
If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
|
||||
|
||||
```bash
|
||||
# 1. Install Superpowers (or update existing)
|
||||
if [ -d ~/.config/opencode/superpowers ]; then
|
||||
cd ~/.config/opencode/superpowers && git pull
|
||||
else
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
fi
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove old symlinks/directories if they exist
|
||||
# Remove old symlinks
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
|
||||
# 4. Create symlinks
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
# Optionally remove the cloned repo
|
||||
rm -rf ~/.config/opencode/superpowers
|
||||
|
||||
# 5. Restart OpenCode
|
||||
# Remove skills.paths from opencode.json if you added one for superpowers
|
||||
```
|
||||
|
||||
#### Verify Installation
|
||||
|
||||
```bash
|
||||
ls -l ~/.config/opencode/plugins/superpowers.js
|
||||
ls -l ~/.config/opencode/skills/superpowers
|
||||
```
|
||||
|
||||
Both should show symlinks pointing to the superpowers directory.
|
||||
|
||||
### Windows
|
||||
|
||||
**Prerequisites:**
|
||||
- Git installed
|
||||
- Either **Developer Mode** enabled OR **Administrator privileges**
|
||||
- Windows 10: Settings → Update & Security → For developers
|
||||
- Windows 11: Settings → System → For developers
|
||||
|
||||
Pick your shell below: [Command Prompt](#command-prompt) | [PowerShell](#powershell) | [Git Bash](#git-bash)
|
||||
|
||||
#### Command Prompt
|
||||
|
||||
Run as Administrator, or with Developer Mode enabled:
|
||||
|
||||
```cmd
|
||||
:: 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git "%USERPROFILE%\.config\opencode\superpowers"
|
||||
|
||||
:: 2. Create directories
|
||||
mkdir "%USERPROFILE%\.config\opencode\plugins" 2>nul
|
||||
mkdir "%USERPROFILE%\.config\opencode\skills" 2>nul
|
||||
|
||||
:: 3. Remove existing links (safe for reinstalls)
|
||||
del "%USERPROFILE%\.config\opencode\plugins\superpowers.js" 2>nul
|
||||
rmdir "%USERPROFILE%\.config\opencode\skills\superpowers" 2>nul
|
||||
|
||||
:: 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
mklink "%USERPROFILE%\.config\opencode\plugins\superpowers.js" "%USERPROFILE%\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
|
||||
:: 5. Create skills junction (works without special privileges)
|
||||
mklink /J "%USERPROFILE%\.config\opencode\skills\superpowers" "%USERPROFILE%\.config\opencode\superpowers\skills"
|
||||
|
||||
:: 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
||||
Run as Administrator, or with Developer Mode enabled:
|
||||
|
||||
```powershell
|
||||
# 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git "$env:USERPROFILE\.config\opencode\superpowers"
|
||||
|
||||
# 2. Create directories
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\plugins"
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\skills"
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\skills\superpowers" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Target "$env:USERPROFILE\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
New-Item -ItemType Junction -Path "$env:USERPROFILE\.config\opencode\skills\superpowers" -Target "$env:USERPROFILE\.config\opencode\superpowers\skills"
|
||||
|
||||
# 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### Git Bash
|
||||
|
||||
Note: Git Bash's native `ln` command copies files instead of creating symlinks. Use `cmd //c mklink` instead (the `//c` is Git Bash syntax for `/c`).
|
||||
|
||||
```bash
|
||||
# 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js 2>/dev/null
|
||||
rm -rf ~/.config/opencode/skills/superpowers 2>/dev/null
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
cmd //c "mklink \"$(cygpath -w ~/.config/opencode/plugins/superpowers.js)\" \"$(cygpath -w ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js)\""
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
cmd //c "mklink /J \"$(cygpath -w ~/.config/opencode/skills/superpowers)\" \"$(cygpath -w ~/.config/opencode/superpowers/skills)\""
|
||||
|
||||
# 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### WSL Users
|
||||
|
||||
If running OpenCode inside WSL, use the [macOS / Linux](#macos--linux) instructions instead.
|
||||
|
||||
#### Verify Installation
|
||||
|
||||
**Command Prompt:**
|
||||
```cmd
|
||||
dir /AL "%USERPROFILE%\.config\opencode\plugins"
|
||||
dir /AL "%USERPROFILE%\.config\opencode\skills"
|
||||
```
|
||||
|
||||
**PowerShell:**
|
||||
```powershell
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\plugins" | Where-Object { $_.LinkType }
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\skills" | Where-Object { $_.LinkType }
|
||||
```
|
||||
|
||||
Look for `<SYMLINK>` or `<JUNCTION>` in the output.
|
||||
|
||||
#### Troubleshooting Windows
|
||||
|
||||
**"You do not have sufficient privilege" error:**
|
||||
- Enable Developer Mode in Windows Settings, OR
|
||||
- Right-click your terminal → "Run as Administrator"
|
||||
|
||||
**"Cannot create a file when that file already exists":**
|
||||
- Run the removal commands (step 3) first, then retry
|
||||
|
||||
**Symlinks not working after git clone:**
|
||||
- Run `git config --global core.symlinks true` and re-clone
|
||||
Then follow the installation steps above.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -178,8 +45,6 @@ use skill tool to list skills
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
Use OpenCode's native `skill` tool to load a specific skill:
|
||||
|
||||
```
|
||||
use skill tool to load superpowers/brainstorming
|
||||
```
|
||||
@@ -207,124 +72,59 @@ description: Use when [condition] - [what it does]
|
||||
|
||||
### Project Skills
|
||||
|
||||
Create project-specific skills in your OpenCode project:
|
||||
Create project-specific skills in `.opencode/skills/` within your project.
|
||||
|
||||
```bash
|
||||
# In your OpenCode project
|
||||
mkdir -p .opencode/skills/my-project-skill
|
||||
**Skill Priority:** Project skills > Personal skills > Superpowers skills
|
||||
|
||||
## Updating
|
||||
|
||||
Superpowers updates automatically when you restart OpenCode. The plugin is re-installed from the git repository on each launch.
|
||||
|
||||
To pin a specific version, use a branch or tag:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git#v5.0.3"]
|
||||
}
|
||||
```
|
||||
|
||||
Create `.opencode/skills/my-project-skill/SKILL.md`:
|
||||
## How It Works
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-project-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
The plugin does two things:
|
||||
|
||||
# My Project Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
## Skill Locations
|
||||
|
||||
OpenCode discovers skills from these locations:
|
||||
|
||||
1. **Project skills** (`.opencode/skills/`) - Highest priority
|
||||
2. **Personal skills** (`~/.config/opencode/skills/`)
|
||||
3. **Superpowers skills** (`~/.config/opencode/skills/superpowers/`) - via symlink
|
||||
|
||||
## Features
|
||||
|
||||
### Automatic Context Injection
|
||||
|
||||
The plugin automatically injects superpowers context via the `experimental.chat.system.transform` hook. This adds the "using-superpowers" skill content to the system prompt on every request.
|
||||
|
||||
### Native Skills Integration
|
||||
|
||||
Superpowers uses OpenCode's native `skill` tool for skill discovery and loading. Skills are symlinked into `~/.config/opencode/skills/superpowers/` so they appear alongside your personal and project skills.
|
||||
1. **Injects bootstrap context** via the `experimental.chat.system.transform` hook, adding superpowers awareness to every conversation.
|
||||
2. **Registers the skills directory** via the `config` hook, so OpenCode discovers all superpowers skills without symlinks or manual config.
|
||||
|
||||
### Tool Mapping
|
||||
|
||||
Skills written for Claude Code are automatically adapted for OpenCode. The bootstrap provides mapping instructions:
|
||||
Skills written for Claude Code are automatically adapted for OpenCode:
|
||||
|
||||
- `TodoWrite` → `todowrite`
|
||||
- `Task` with subagents → OpenCode's `@mention` system
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → Native OpenCode tools
|
||||
|
||||
## Architecture
|
||||
|
||||
### Plugin Structure
|
||||
|
||||
**Location:** `~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
|
||||
**Components:**
|
||||
- `experimental.chat.system.transform` hook for bootstrap injection
|
||||
- Reads and injects the "using-superpowers" skill content
|
||||
|
||||
### Skills
|
||||
|
||||
**Location:** `~/.config/opencode/skills/superpowers/` (symlink to `~/.config/opencode/superpowers/skills/`)
|
||||
|
||||
Skills are discovered by OpenCode's native skill system. Each skill has a `SKILL.md` file with YAML frontmatter.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode/superpowers
|
||||
git pull
|
||||
```
|
||||
|
||||
Restart OpenCode to load the updates.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
2. Check symlink/junction: `ls -l ~/.config/opencode/plugins/` (macOS/Linux) or `dir /AL %USERPROFILE%\.config\opencode\plugins` (Windows)
|
||||
3. Check OpenCode logs: `opencode run "test" --print-logs --log-level DEBUG`
|
||||
4. Look for plugin loading message in logs
|
||||
1. Check OpenCode logs: `opencode run --print-logs "hello" 2>&1 | grep -i superpowers`
|
||||
2. Verify the plugin line in your `opencode.json` is correct
|
||||
3. Make sure you're running a recent version of OpenCode
|
||||
|
||||
### Skills not found
|
||||
|
||||
1. Verify skills symlink: `ls -l ~/.config/opencode/skills/superpowers` (should point to superpowers/skills/)
|
||||
2. Use OpenCode's `skill` tool to list available skills
|
||||
3. Check skill structure: each skill needs a `SKILL.md` file with valid frontmatter
|
||||
|
||||
### Windows: Module not found error
|
||||
|
||||
If you see `Cannot find module` errors on Windows:
|
||||
- **Cause:** Git Bash `ln -sf` copies files instead of creating symlinks
|
||||
- **Fix:** Use `mklink /J` directory junctions instead (see Windows installation steps)
|
||||
1. Use OpenCode's `skill` tool to list available skills
|
||||
2. Check that the plugin is loading (see above)
|
||||
3. Each skill needs a `SKILL.md` file with valid YAML frontmatter
|
||||
|
||||
### Bootstrap not appearing
|
||||
|
||||
1. Verify using-superpowers skill exists: `ls ~/.config/opencode/superpowers/skills/using-superpowers/SKILL.md`
|
||||
2. Check OpenCode version supports `experimental.chat.system.transform` hook
|
||||
3. Restart OpenCode after plugin changes
|
||||
1. Check OpenCode version supports `experimental.chat.system.transform` hook
|
||||
2. Restart OpenCode after config changes
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Report issues: https://github.com/obra/superpowers/issues
|
||||
- Main documentation: https://github.com/obra/superpowers
|
||||
- OpenCode docs: https://opencode.ai/docs/
|
||||
|
||||
## Testing
|
||||
|
||||
Verify your installation:
|
||||
|
||||
```bash
|
||||
# Check plugin loads
|
||||
opencode run --print-logs "hello" 2>&1 | grep -i superpowers
|
||||
|
||||
# Check skills are discoverable
|
||||
opencode run "use skill tool to list all skills" 2>&1 | grep -i superpowers
|
||||
|
||||
# Check bootstrap injection
|
||||
opencode run "what superpowers do you have?"
|
||||
```
|
||||
|
||||
The agent should mention having superpowers and be able to list skills from `superpowers/`.
|
||||
|
||||
564
docs/superpowers/plans/2026-03-23-codex-app-compatibility.md
Normal file
564
docs/superpowers/plans/2026-03-23-codex-app-compatibility.md
Normal file
@@ -0,0 +1,564 @@
|
||||
# Codex App Compatibility Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make `using-git-worktrees`, `finishing-a-development-branch`, and related skills work in the Codex App's sandboxed worktree environment without breaking existing behavior.
|
||||
|
||||
**Architecture:** Read-only environment detection (`git-dir` vs `git-common-dir`) at the start of two skills. If already in a linked worktree, skip creation. If on detached HEAD, emit a handoff payload instead of the 4-option menu. Sandbox fallback catches permission errors during worktree creation.
|
||||
|
||||
**Tech Stack:** Git, Markdown (skill files are instruction documents, not executable code)
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-03-23-codex-app-compatibility-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| File | Responsibility | Action |
|
||||
|---|---|---|
|
||||
| `skills/using-git-worktrees/SKILL.md` | Worktree creation + isolation | Add Step 0 detection + sandbox fallback |
|
||||
| `skills/finishing-a-development-branch/SKILL.md` | Branch finishing workflow | Add Step 1.5 detection + cleanup guard |
|
||||
| `skills/subagent-driven-development/SKILL.md` | Plan execution with subagents | Update Integration description |
|
||||
| `skills/executing-plans/SKILL.md` | Plan execution inline | Update Integration description |
|
||||
| `skills/using-superpowers/references/codex-tools.md` | Codex platform reference | Add detection + finishing docs |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Step 0 to `using-git-worktrees`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-git-worktrees/SKILL.md:14-15` (insert after Overview, before Directory Selection Process)
|
||||
|
||||
- [ ] **Step 1: Read the current skill file**
|
||||
|
||||
Read `skills/using-git-worktrees/SKILL.md` in full. Identify the exact insertion point: after the "Announce at start" line (line 14) and before "## Directory Selection Process" (line 16).
|
||||
|
||||
- [ ] **Step 2: Insert Step 0 section**
|
||||
|
||||
Insert the following between the Overview section and "## Directory Selection Process":
|
||||
|
||||
```markdown
|
||||
## Step 0: Check if Already in an Isolated Workspace
|
||||
|
||||
Before creating a worktree, check if one already exists:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
**If `GIT_DIR` differs from `GIT_COMMON`:** You are already inside a linked worktree (created by the Codex App, Claude Code's Agent tool, a previous skill run, or the user). Do NOT create another worktree. Instead:
|
||||
|
||||
1. Run project setup (auto-detect package manager as in "Run Project Setup" below)
|
||||
2. Verify clean baseline (run tests as in "Verify Clean Baseline" below)
|
||||
3. Report with branch state:
|
||||
- On a branch: "Already in an isolated workspace at `<path>` on branch `<name>`. Tests passing. Ready to implement."
|
||||
- Detached HEAD: "Already in an isolated workspace at `<path>` (detached HEAD, externally managed). Tests passing. Note: branch creation needed at finish time. Ready to implement."
|
||||
|
||||
After reporting, STOP. Do not continue to Directory Selection or Creation Steps.
|
||||
|
||||
**If `GIT_DIR` equals `GIT_COMMON`:** Proceed with the full worktree creation flow below.
|
||||
|
||||
**Sandbox fallback:** If you proceed to Creation Steps but `git worktree add -b` fails with a permission error (e.g., "Operation not permitted"), treat this as a late-detected restricted environment. Fall back to the behavior above — run setup and baseline tests in the current directory, report accordingly, and STOP.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the insertion**
|
||||
|
||||
Read the file again. Confirm:
|
||||
- Step 0 appears between Overview and Directory Selection Process
|
||||
- The rest of the file (Directory Selection, Safety Verification, Creation Steps, etc.) is unchanged
|
||||
- No duplicate sections or broken markdown
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-git-worktrees/SKILL.md
|
||||
git commit -m "feat(using-git-worktrees): add Step 0 environment detection (PRI-823)
|
||||
|
||||
Skip worktree creation when already in a linked worktree. Includes
|
||||
sandbox fallback for permission errors on git worktree add."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Update `using-git-worktrees` Integration section
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-git-worktrees/SKILL.md:211-215` (Integration > Called by)
|
||||
|
||||
- [ ] **Step 1: Update the three "Called by" entries**
|
||||
|
||||
Change lines 212-214 from:
|
||||
|
||||
```markdown
|
||||
- **brainstorming** (Phase 4) - REQUIRED when design is approved and implementation follows
|
||||
- **subagent-driven-development** - REQUIRED before executing any tasks
|
||||
- **executing-plans** - REQUIRED before executing any tasks
|
||||
```
|
||||
|
||||
To:
|
||||
|
||||
```markdown
|
||||
- **brainstorming** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **subagent-driven-development** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **executing-plans** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the Integration section**
|
||||
|
||||
Read the Integration section. Confirm all three entries are updated, "Pairs with" is unchanged.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-git-worktrees/SKILL.md
|
||||
git commit -m "docs(using-git-worktrees): update Integration descriptions (PRI-823)
|
||||
|
||||
Clarify that skill ensures a workspace exists, not that it always creates one."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Add Step 1.5 to `finishing-a-development-branch`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/finishing-a-development-branch/SKILL.md:38` (insert after Step 1, before Step 2)
|
||||
|
||||
- [ ] **Step 1: Read the current skill file**
|
||||
|
||||
Read `skills/finishing-a-development-branch/SKILL.md` in full. Identify the insertion point: after "**If tests pass:** Continue to Step 2." (line 38) and before "### Step 2: Determine Base Branch" (line 40).
|
||||
|
||||
- [ ] **Step 2: Insert Step 1.5 section**
|
||||
|
||||
Insert the following between Step 1 and Step 2:
|
||||
|
||||
```markdown
|
||||
### Step 1.5: Detect Environment
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
**Path A — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` is empty (externally managed worktree, detached HEAD):**
|
||||
|
||||
First, ensure all work is staged and committed (`git add` + `git commit`).
|
||||
|
||||
Then present this to the user (do NOT present the 4-option menu):
|
||||
|
||||
```
|
||||
Implementation complete. All tests passing.
|
||||
Current HEAD: <full-commit-sha>
|
||||
|
||||
This workspace is externally managed (detached HEAD).
|
||||
I cannot create branches, push, or open PRs from here.
|
||||
|
||||
⚠ These commits are on a detached HEAD. If you do not create a branch,
|
||||
they may be lost when this workspace is cleaned up.
|
||||
|
||||
If your host application provides these controls:
|
||||
- "Create branch" — to name a branch, then commit/push/PR
|
||||
- "Hand off to local" — to move changes to your local checkout
|
||||
|
||||
Suggested branch name: <ticket-id/short-description>
|
||||
Suggested commit message: <summary-of-work>
|
||||
```
|
||||
|
||||
Branch name: use ticket ID if available (e.g., `pri-823/codex-compat`), otherwise slugify the first 5 words of the plan title, otherwise omit. Avoid sensitive content in branch names.
|
||||
|
||||
Skip to Step 5 (cleanup is a no-op — see guard below).
|
||||
|
||||
**Path B — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` exists (externally managed worktree, named branch):**
|
||||
|
||||
Proceed to Step 2 and present the 4-option menu as normal.
|
||||
|
||||
**Path C — `GIT_DIR` equals `GIT_COMMON` (normal environment):**
|
||||
|
||||
Proceed to Step 2 and present the 4-option menu as normal.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the insertion**
|
||||
|
||||
Read the file again. Confirm:
|
||||
- Step 1.5 appears between Step 1 and Step 2
|
||||
- Steps 2-5 are unchanged
|
||||
- Path A handoff includes commit SHA and data loss warning
|
||||
- Paths B and C proceed to Step 2 normally
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/finishing-a-development-branch/SKILL.md
|
||||
git commit -m "feat(finishing-a-development-branch): add Step 1.5 environment detection (PRI-823)
|
||||
|
||||
Detect externally managed worktrees with detached HEAD and emit handoff
|
||||
payload instead of 4-option menu. Includes commit SHA and data loss warning."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Add Step 5 cleanup guard to `finishing-a-development-branch`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/finishing-a-development-branch/SKILL.md` (Step 5: Cleanup Worktree — find by section heading, line numbers will have shifted after Task 3)
|
||||
|
||||
- [ ] **Step 1: Read the current Step 5 section**
|
||||
|
||||
Find the "### Step 5: Cleanup Worktree" section in `skills/finishing-a-development-branch/SKILL.md` (line numbers will have shifted after Task 3's insertion). The current Step 5 is:
|
||||
|
||||
```markdown
|
||||
### Step 5: Cleanup Worktree
|
||||
|
||||
**For Options 1, 2, 4:**
|
||||
|
||||
Check if in worktree:
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
```
|
||||
|
||||
If yes:
|
||||
```bash
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
**For Option 3:** Keep worktree.
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add the cleanup guard before existing logic**
|
||||
|
||||
Replace the Step 5 section with:
|
||||
|
||||
```markdown
|
||||
### Step 5: Cleanup Worktree
|
||||
|
||||
**First, check if worktree is externally managed:**
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
```
|
||||
|
||||
If `GIT_DIR` differs from `GIT_COMMON`: skip worktree removal — the host environment owns this workspace.
|
||||
|
||||
**Otherwise, for Options 1 and 4:**
|
||||
|
||||
Check if in worktree:
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
```
|
||||
|
||||
If yes:
|
||||
```bash
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
**For Option 3:** Keep worktree.
|
||||
```
|
||||
|
||||
Note: the original text said "For Options 1, 2, 4" but the Quick Reference table and Common Mistakes section say "Options 1 & 4 only." This edit aligns Step 5 with those sections.
|
||||
|
||||
- [ ] **Step 3: Verify the replacement**
|
||||
|
||||
Read Step 5. Confirm:
|
||||
- Cleanup guard (re-detection) appears first
|
||||
- Existing removal logic preserved for non-externally-managed worktrees
|
||||
- "Options 1 and 4" (not "1, 2, 4") matches Quick Reference and Common Mistakes
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/finishing-a-development-branch/SKILL.md
|
||||
git commit -m "feat(finishing-a-development-branch): add Step 5 cleanup guard (PRI-823)
|
||||
|
||||
Re-detect externally managed worktree at cleanup time and skip removal.
|
||||
Also fixes pre-existing inconsistency: cleanup now correctly says
|
||||
Options 1 and 4 only, matching Quick Reference and Common Mistakes."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Update Integration lines in `subagent-driven-development` and `executing-plans`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/subagent-driven-development/SKILL.md:268`
|
||||
- Modify: `skills/executing-plans/SKILL.md:68`
|
||||
|
||||
- [ ] **Step 1: Update `subagent-driven-development`**
|
||||
|
||||
Change line 268 from:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update `executing-plans`**
|
||||
|
||||
Change line 68 from:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify both files**
|
||||
|
||||
Read line 268 of `skills/subagent-driven-development/SKILL.md` and line 68 of `skills/executing-plans/SKILL.md`. Confirm both say "Ensures isolated workspace (creates one or verifies existing)".
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/subagent-driven-development/SKILL.md skills/executing-plans/SKILL.md
|
||||
git commit -m "docs(sdd, executing-plans): update worktree Integration descriptions (PRI-823)
|
||||
|
||||
Clarify that using-git-worktrees ensures a workspace exists rather than
|
||||
always creating one."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Add environment detection docs to `codex-tools.md`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-superpowers/references/codex-tools.md:25` (append at end)
|
||||
|
||||
- [ ] **Step 1: Read the current file**
|
||||
|
||||
Read `skills/using-superpowers/references/codex-tools.md` in full. Confirm it ends at line 25-26 after the multi_agent section.
|
||||
|
||||
- [ ] **Step 2: Append two new sections**
|
||||
|
||||
Add at the end of the file:
|
||||
|
||||
```markdown
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1.5 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the additions**
|
||||
|
||||
Read the full file. Confirm:
|
||||
- Two new sections appear after the existing content
|
||||
- Bash code block renders correctly (not escaped)
|
||||
- Cross-references to Step 0 and Step 1.5 are present
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-superpowers/references/codex-tools.md
|
||||
git commit -m "docs(codex-tools): add environment detection and App finishing docs (PRI-823)
|
||||
|
||||
Document the git-dir vs git-common-dir detection pattern and the Codex
|
||||
App's native finishing flow for skills that need to adapt."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Automated test — environment detection
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/codex-app-compat/test-environment-detection.sh`
|
||||
|
||||
- [ ] **Step 1: Create test directory**
|
||||
|
||||
```bash
|
||||
mkdir -p tests/codex-app-compat
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write the detection test script**
|
||||
|
||||
Create `tests/codex-app-compat/test-environment-detection.sh`:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Test environment detection logic from PRI-823
|
||||
# Tests the git-dir vs git-common-dir comparison used by
|
||||
# using-git-worktrees Step 0 and finishing-a-development-branch Step 1.5
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
log_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
||||
log_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
# Helper: run detection and return "linked" or "normal"
|
||||
detect_worktree() {
|
||||
local git_dir git_common
|
||||
git_dir=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
git_common=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
if [ "$git_dir" != "$git_common" ]; then
|
||||
echo "linked"
|
||||
else
|
||||
echo "normal"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Test 1: Normal repo detection ==="
|
||||
cd "$TEMP_DIR"
|
||||
git init test-repo > /dev/null 2>&1
|
||||
cd test-repo
|
||||
git commit --allow-empty -m "init" > /dev/null 2>&1
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Normal repo detected as normal"
|
||||
else
|
||||
log_fail "Normal repo detected as '$result' (expected 'normal')"
|
||||
fi
|
||||
|
||||
echo "=== Test 2: Linked worktree detection ==="
|
||||
git worktree add "$TEMP_DIR/test-wt" -b test-branch > /dev/null 2>&1
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Linked worktree detected as linked"
|
||||
else
|
||||
log_fail "Linked worktree detected as '$result' (expected 'linked')"
|
||||
fi
|
||||
|
||||
echo "=== Test 3: Detached HEAD detection ==="
|
||||
git checkout --detach HEAD > /dev/null 2>&1
|
||||
branch=$(git branch --show-current)
|
||||
if [ -z "$branch" ]; then
|
||||
log_pass "Detached HEAD: branch is empty"
|
||||
else
|
||||
log_fail "Detached HEAD: branch is '$branch' (expected empty)"
|
||||
fi
|
||||
|
||||
echo "=== Test 4: Linked worktree + detached HEAD (Codex App simulation) ==="
|
||||
result=$(detect_worktree)
|
||||
branch=$(git branch --show-current)
|
||||
if [ "$result" = "linked" ] && [ -z "$branch" ]; then
|
||||
log_pass "Codex App simulation: linked + detached HEAD"
|
||||
else
|
||||
log_fail "Codex App simulation: result='$result', branch='$branch'"
|
||||
fi
|
||||
|
||||
echo "=== Test 5: Cleanup guard — linked worktree should NOT remove ==="
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Cleanup guard: linked worktree correctly detected (would skip removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'linked', got '$result'"
|
||||
fi
|
||||
|
||||
echo "=== Test 6: Cleanup guard — main repo SHOULD remove ==="
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Cleanup guard: main repo correctly detected (would proceed with removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'normal', got '$result'"
|
||||
fi
|
||||
|
||||
# Cleanup worktree before temp dir removal
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
git worktree remove "$TEMP_DIR/test-wt" > /dev/null 2>&1 || true
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Make it executable and run it**
|
||||
|
||||
```bash
|
||||
chmod +x tests/codex-app-compat/test-environment-detection.sh
|
||||
./tests/codex-app-compat/test-environment-detection.sh
|
||||
```
|
||||
|
||||
Expected output: 6 passed, 0 failed.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/codex-app-compat/test-environment-detection.sh
|
||||
git commit -m "test: add environment detection tests for Codex App compat (PRI-823)
|
||||
|
||||
Tests git-dir vs git-common-dir comparison in normal repo, linked
|
||||
worktree, detached HEAD, and cleanup guard scenarios."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Final verification
|
||||
|
||||
**Files:**
|
||||
- Read: all 5 modified skill files
|
||||
|
||||
- [ ] **Step 1: Run the automated detection tests**
|
||||
|
||||
```bash
|
||||
./tests/codex-app-compat/test-environment-detection.sh
|
||||
```
|
||||
|
||||
Expected: 6 passed, 0 failed.
|
||||
|
||||
- [ ] **Step 2: Read each modified file and verify changes**
|
||||
|
||||
Read each file end-to-end:
|
||||
- `skills/using-git-worktrees/SKILL.md` — Step 0 present, rest unchanged
|
||||
- `skills/finishing-a-development-branch/SKILL.md` — Step 1.5 present, cleanup guard present, rest unchanged
|
||||
- `skills/subagent-driven-development/SKILL.md` — line 268 updated
|
||||
- `skills/executing-plans/SKILL.md` — line 68 updated
|
||||
- `skills/using-superpowers/references/codex-tools.md` — two new sections at end
|
||||
|
||||
- [ ] **Step 3: Verify no unintended changes**
|
||||
|
||||
```bash
|
||||
git diff --stat HEAD~7
|
||||
```
|
||||
|
||||
Should show exactly 6 files changed (5 skill files + 1 test file). No other files modified.
|
||||
|
||||
- [ ] **Step 4: Run existing test suite**
|
||||
|
||||
If test runner exists:
|
||||
```bash
|
||||
# Run skill-triggering tests
|
||||
./tests/skill-triggering/run-all.sh 2>/dev/null || echo "Skill triggering tests not available in this environment"
|
||||
|
||||
# Run SDD integration test
|
||||
./tests/claude-code/test-subagent-driven-development-integration.sh 2>/dev/null || echo "SDD integration test not available in this environment"
|
||||
```
|
||||
|
||||
Note: these tests require Claude Code with `--dangerously-skip-permissions`. If not available, document that regression tests should be run manually.
|
||||
@@ -0,0 +1,256 @@
|
||||
# Codex App Compatibility: Worktree and Finishing Skill Adaptation
|
||||
|
||||
Make superpowers skills work in the Codex App's sandboxed worktree environment without breaking existing Claude Code or Codex CLI behavior.
|
||||
|
||||
**Ticket:** PRI-823
|
||||
|
||||
## Motivation
|
||||
|
||||
The Codex App runs agents inside git worktrees it manages — detached HEAD, located under `$CODEX_HOME/worktrees/`, with a Seatbelt sandbox that blocks `git checkout -b`, `git push`, and network access. Three superpowers skills assume unrestricted git access: `using-git-worktrees` creates manual worktrees with named branches, `finishing-a-development-branch` merges/pushes/PRs by branch name, and `subagent-driven-development` requires both.
|
||||
|
||||
The Codex CLI (open source terminal tool) does NOT have this conflict — it has no built-in worktree management. Our manual worktree approach fills an isolation gap there. The problem is specifically with the Codex App.
|
||||
|
||||
## Empirical Findings
|
||||
|
||||
Tested in the Codex App on 2026-03-23:
|
||||
|
||||
| Operation | workspace-write sandbox | Full access sandbox |
|
||||
|---|---|---|
|
||||
| `git add` | Works | Works |
|
||||
| `git commit` | Works | Works |
|
||||
| `git checkout -b` | **Blocked** (can't write `.git/refs/heads/`) | Works |
|
||||
| `git push` | **Blocked** (network + `.git/refs/remotes/`) | Works |
|
||||
| `gh pr create` | **Blocked** (network) | Works |
|
||||
| `git status/diff/log` | Works | Works |
|
||||
|
||||
Additional findings:
|
||||
- `spawn_agent` subagents **share** the parent thread's filesystem (confirmed via marker file test)
|
||||
- "Create branch" button appears in the App header regardless of which branch the worktree was started from
|
||||
- The App's native finishing flow: Create branch → Commit modal → Commit and push / Commit and create PR
|
||||
- `network_access = true` config is silently broken on macOS (issue #10390)
|
||||
|
||||
## Design: Read-Only Environment Detection
|
||||
|
||||
Three read-only git commands detect the environment without side effects:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
Two signals derived:
|
||||
|
||||
- **IN_LINKED_WORKTREE:** `GIT_DIR != GIT_COMMON` — the agent is in a worktree created by something else (Codex App, Claude Code Agent tool, previous skill run, or the user)
|
||||
- **ON_DETACHED_HEAD:** `BRANCH` is empty — no named branch exists
|
||||
|
||||
Why `git-dir != git-common-dir` instead of checking `show-toplevel`:
|
||||
- In a normal repo, both resolve to the same `.git` directory
|
||||
- In a linked worktree, `git-dir` is `.git/worktrees/<name>` while `git-common-dir` is `.git`
|
||||
- In a submodule, both are equal — avoiding a false positive that `show-toplevel` would produce
|
||||
- Resolving via `cd && pwd -P` handles the relative-path problem (`git-common-dir` returns `.git` relative in normal repos but absolute in worktrees) and symlinks (macOS `/tmp` → `/private/tmp`)
|
||||
|
||||
### Decision Matrix
|
||||
|
||||
| Linked Worktree? | Detached HEAD? | Environment | Action |
|
||||
|---|---|---|---|
|
||||
| No | No | Claude Code / Codex CLI / normal git | Full skill behavior (unchanged) |
|
||||
| Yes | Yes | Codex App worktree (workspace-write) | Skip worktree creation; handoff payload at finish |
|
||||
| Yes | No | Codex App (Full access) or manual worktree | Skip worktree creation; full finishing flow |
|
||||
| No | Yes | Unusual (manual detached HEAD) | Create worktree normally; warn at finish |
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. `using-git-worktrees/SKILL.md` — Add Step 0 (~12 lines)
|
||||
|
||||
New section between "Overview" and "Directory Selection Process":
|
||||
|
||||
**Step 0: Check if Already in an Isolated Workspace**
|
||||
|
||||
Run the detection commands. If `GIT_DIR != GIT_COMMON`, skip worktree creation entirely. Instead:
|
||||
1. Skip to "Run Project Setup" subsection under Creation Steps — `npm install` etc. is idempotent, worth running for safety
|
||||
2. Then "Verify Clean Baseline" — run tests
|
||||
3. Report with branch state:
|
||||
- On a branch: "Already in an isolated workspace at `<path>` on branch `<name>`. Tests passing. Ready to implement."
|
||||
- Detached HEAD: "Already in an isolated workspace at `<path>` (detached HEAD, externally managed). Tests passing. Note: branch creation needed at finish time. Ready to implement."
|
||||
|
||||
If `GIT_DIR == GIT_COMMON`, proceed with the full worktree creation flow (unchanged).
|
||||
|
||||
Safety verification (.gitignore check) is skipped when Step 0 fires — irrelevant for externally-created worktrees.
|
||||
|
||||
Update the Integration section's "Called by" entries. Change the description on each from context-specific text to: "Ensures isolated workspace (creates one or verifies existing)". For example, the `subagent-driven-development` entry changes from "REQUIRED: Set up isolated workspace before starting" to "REQUIRED: Ensures isolated workspace (creates one or verifies existing)".
|
||||
|
||||
**Sandbox fallback:** If `GIT_DIR == GIT_COMMON` and the skill proceeds to Creation Steps, but `git worktree add -b` fails with a permission error (e.g., Seatbelt sandbox denial), treat this as a late-detected restricted environment. Fall back to the Step 0 "already in workspace" behavior — skip creation, run setup and baseline tests in the current directory, report accordingly.
|
||||
|
||||
After reporting in Step 0, STOP. Do not continue to Directory Selection or Creation Steps.
|
||||
|
||||
**Everything else unchanged:** Directory Selection, Safety Verification, Creation Steps, Project Setup, Baseline Tests, Quick Reference, Common Mistakes, Red Flags.
|
||||
|
||||
### 2. `finishing-a-development-branch/SKILL.md` — Add Step 1.5 + cleanup guard (~20 lines)
|
||||
|
||||
**Step 1.5: Detect Environment** (after Step 1 "Verify Tests", before Step 2 "Determine Base Branch")
|
||||
|
||||
Run the detection commands. Three paths:
|
||||
|
||||
- **Path A** skips Steps 2 and 3 entirely (no base branch or options needed).
|
||||
- **Paths B and C** proceed through Step 2 (Determine Base Branch) and Step 3 (Present Options) as normal.
|
||||
|
||||
**Path A — Externally managed worktree + detached HEAD** (`GIT_DIR != GIT_COMMON` AND `BRANCH` empty):
|
||||
|
||||
First, ensure all work is staged and committed (`git add` + `git commit`). The Codex App's finishing controls operate on committed work.
|
||||
|
||||
Then present this to the user (do NOT present the 4-option menu):
|
||||
|
||||
```
|
||||
Implementation complete. All tests passing.
|
||||
Current HEAD: <full-commit-sha>
|
||||
|
||||
This workspace is externally managed (detached HEAD).
|
||||
I cannot create branches, push, or open PRs from here.
|
||||
|
||||
⚠ These commits are on a detached HEAD. If you do not create a branch,
|
||||
they may be lost when this workspace is cleaned up.
|
||||
|
||||
If your host application provides these controls:
|
||||
- "Create branch" — to name a branch, then commit/push/PR
|
||||
- "Hand off to local" — to move changes to your local checkout
|
||||
|
||||
Suggested branch name: <ticket-id/short-description>
|
||||
Suggested commit message: <summary-of-work>
|
||||
```
|
||||
|
||||
Branch name derivation: use the ticket ID if available (e.g., `pri-823/codex-compat`), otherwise slugify the first 5 words of the plan title, otherwise omit the suggestion. Avoid including sensitive content (vulnerability descriptions, customer names) in branch names.
|
||||
|
||||
Skip to Step 5 (cleanup is a no-op for externally managed worktrees).
|
||||
|
||||
**Path B — Externally managed worktree + named branch** (`GIT_DIR != GIT_COMMON` AND `BRANCH` exists):
|
||||
|
||||
Present the 4-option menu as normal. (The Step 5 cleanup guard will re-detect the externally managed state independently.)
|
||||
|
||||
**Path C — Normal environment** (`GIT_DIR == GIT_COMMON`):
|
||||
|
||||
Present the 4-option menu as today (unchanged).
|
||||
|
||||
**Step 5 cleanup guard:**
|
||||
|
||||
Re-run the `GIT_DIR` vs `GIT_COMMON` detection at cleanup time (do not rely on earlier skill output — the finishing skill may run in a different session). If `GIT_DIR != GIT_COMMON`, skip `git worktree remove` — the host environment owns this workspace.
|
||||
|
||||
Otherwise, check and remove as today. Note: the existing Step 5 text says "For Options 1, 2, 4" but the Quick Reference table and Common Mistakes section say "Options 1 & 4 only." The new guard is added before this existing logic and does not change which options trigger cleanup.
|
||||
|
||||
**Everything else unchanged:** Options 1-4 logic, Quick Reference, Common Mistakes, Red Flags.
|
||||
|
||||
### 3. `subagent-driven-development/SKILL.md` and `executing-plans/SKILL.md` — 1 line edit each
|
||||
|
||||
Both skills have an identical Integration section line. Change from:
|
||||
```
|
||||
- superpowers:using-git-worktrees - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- superpowers:using-git-worktrees - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
**Everything else unchanged:** Dispatch/review loop, prompt templates, model selection, status handling, red flags.
|
||||
|
||||
### 4. `codex-tools.md` — Add environment detection docs (~15 lines)
|
||||
|
||||
Two new sections at the end:
|
||||
|
||||
**Environment Detection:**
|
||||
|
||||
```markdown
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
\```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
\```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1.5 for how each skill uses these signals.
|
||||
```
|
||||
|
||||
**Codex App Finishing:**
|
||||
|
||||
```markdown
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
```
|
||||
|
||||
## What Does NOT Change
|
||||
|
||||
- `implementer-prompt.md`, `spec-reviewer-prompt.md`, `code-quality-reviewer-prompt.md` — subagent prompts untouched
|
||||
- `executing-plans/SKILL.md` — only the 1-line Integration description changes (same as `subagent-driven-development`); all runtime behavior is unchanged
|
||||
- `dispatching-parallel-agents/SKILL.md` — no worktree or finishing operations
|
||||
- `.codex/INSTALL.md` — installation process unchanged
|
||||
- The 4-option finishing menu — preserved exactly for Claude Code and Codex CLI
|
||||
- The full worktree creation flow — preserved exactly for non-worktree environments
|
||||
- Subagent dispatch/review/iterate loop — unchanged (filesystem sharing confirmed)
|
||||
|
||||
## Scope Summary
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `skills/using-git-worktrees/SKILL.md` | +12 lines (Step 0) |
|
||||
| `skills/finishing-a-development-branch/SKILL.md` | +20 lines (Step 1.5 + cleanup guard) |
|
||||
| `skills/subagent-driven-development/SKILL.md` | 1 line edit |
|
||||
| `skills/executing-plans/SKILL.md` | 1 line edit |
|
||||
| `skills/using-superpowers/references/codex-tools.md` | +15 lines |
|
||||
|
||||
~50 lines added/changed across 5 files. Zero new files. Zero breaking changes.
|
||||
|
||||
## Future Considerations
|
||||
|
||||
If a third skill needs the same detection pattern, extract it into a shared `references/environment-detection.md` file (Approach B). Not needed now — only 2 skills use it.
|
||||
|
||||
## Test Plan
|
||||
|
||||
### Automated (run in Claude Code after implementation)
|
||||
|
||||
1. Normal repo detection — assert IN_LINKED_WORKTREE=false
|
||||
2. Linked worktree detection — `git worktree add` test worktree, assert IN_LINKED_WORKTREE=true
|
||||
3. Detached HEAD detection — `git checkout --detach`, assert ON_DETACHED_HEAD=true
|
||||
4. Finishing skill handoff output — verify handoff message (not 4-option menu) in restricted environment
|
||||
5. **Step 5 cleanup guard** — create a linked worktree (`git worktree add /tmp/test-cleanup -b test-cleanup`), `cd` into it, run the Step 5 cleanup detection (`GIT_DIR` vs `GIT_COMMON`), assert it would NOT call `git worktree remove`. Then `cd` back to main repo, run the same detection, assert it WOULD call `git worktree remove`. Clean up test worktree afterward.
|
||||
|
||||
### Manual Codex App Tests (5 tests)
|
||||
|
||||
1. Detection in Worktree thread (workspace-write) — verify GIT_DIR != GIT_COMMON, empty branch
|
||||
2. Detection in Worktree thread (Full access) — same detection, different sandbox behavior
|
||||
3. Finishing skill handoff format — verify agent emits handoff payload, not 4-option menu
|
||||
4. Full lifecycle — detection → commit → finishing detection → correct behavior → cleanup
|
||||
5. **Sandbox fallback in Local thread** — Start a Codex App **Local thread** (workspace-write sandbox). Prompt: "Use the superpowers skill `using-git-worktrees` to set up an isolated workspace for implementing a small change." Pre-check: `git checkout -b test-sandbox-check` should fail with `Operation not permitted`. Expected: the skill detects `GIT_DIR == GIT_COMMON` (normal repo), attempts `git worktree add -b`, hits Seatbelt denial, falls back to Step 0 "already in workspace" behavior — runs setup, baseline tests, reports ready from current directory. Pass: agent recovers gracefully without cryptic error messages. Fail: agent prints raw Seatbelt error, retries, or gives up with confusing output.
|
||||
|
||||
### Manual Test Results (2026-03-23)
|
||||
|
||||
| Test | Result | Notes |
|
||||
|------|--------|-------|
|
||||
| 1. Detection in Worktree thread (workspace-write) | PASS | GIT_DIR != GIT_COMMON, BRANCH empty |
|
||||
| 2. Detection in Worktree thread (Full access) | PASS | Same detection; Full access allows `git checkout -b` |
|
||||
| 3. Finishing skill handoff format | PASS (after fix) | Initially FAILED — Step 1.5 was unreachable because Step 1 (test verification) halted first. Fixed by reordering: environment detection is now Step 1, test verification is Step 2. Path A skips tests entirely. |
|
||||
| 4. Full lifecycle | PASS | Detection → commit → handoff payload → no cleanup attempt |
|
||||
| 5. Sandbox fallback in Local thread | N/A | Local thread workspace-write sandbox does not block `git checkout -b`; Seatbelt restriction not triggered in current Codex App version |
|
||||
|
||||
**Fix applied:** `c5d93ac` — moved environment detection before test verification in `finishing-a-development-branch/SKILL.md`. Step numbering changed: old Step 1.5 → new Step 1, old Step 1 → new Step 2, all downstream steps renumbered.
|
||||
|
||||
### Regression
|
||||
|
||||
- Existing Claude Code skill-triggering tests still pass
|
||||
- Existing subagent-driven-development integration tests still pass
|
||||
- Normal Claude Code session: full worktree creation + 4-option finishing still works
|
||||
@@ -148,7 +148,7 @@ exit /b
|
||||
CMDBLOCK
|
||||
|
||||
# Unix shell runs from here
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT_NAME="$1"
|
||||
shift
|
||||
"${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
||||
|
||||
10
hooks/hooks-cursor.json
Normal file
10
hooks/hooks-cursor.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"command": "./hooks/session-start"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
# Determine plugin root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# Check if legacy skills directory exists and build warning
|
||||
@@ -39,23 +39,19 @@ session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the
|
||||
# Claude Code hooks expect hookSpecificOutput.additionalContext.
|
||||
# Claude Code reads BOTH fields without deduplication, so we must only
|
||||
# emit the field consumed by the current platform to avoid double injection.
|
||||
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
||||
#
|
||||
# Uses printf instead of heredoc (cat <<EOF) to work around a bash 5.3+
|
||||
# bug where heredoc variable expansion hangs when content exceeds ~512 bytes.
|
||||
# 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) — emit additional_context
|
||||
printf '{\n "additional_context": "%s"\n}\n' "$session_context"
|
||||
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
||||
# Claude Code sets CLAUDE_PLUGIN_ROOT — emit only hookSpecificOutput
|
||||
cat <<EOF
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "${session_context}"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
|
||||
else
|
||||
# Other platforms (Cursor, etc.) — emit only additional_context
|
||||
cat <<EOF
|
||||
{
|
||||
"additional_context": "${session_context}"
|
||||
}
|
||||
EOF
|
||||
# Other platforms — emit additional_context as fallback
|
||||
printf '{\n "additional_context": "%s"\n}\n' "$session_context"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
6
package.json
Normal file
6
package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "5.0.4",
|
||||
"type": "module",
|
||||
"main": ".opencode/plugins/superpowers.js"
|
||||
}
|
||||
@@ -27,7 +27,7 @@ You MUST create a task for each of these items and complete them in order:
|
||||
4. **Propose 2-3 approaches** — with trade-offs and your recommendation
|
||||
5. **Present design** — in sections scaled to their complexity, get user approval after each section
|
||||
6. **Write design doc** — save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit
|
||||
7. **Spec review loop** — dispatch spec-document-reviewer subagent with precisely crafted review context (never your session history); fix issues and re-dispatch until approved (max 5 iterations, then surface to human)
|
||||
7. **Spec review loop** — dispatch spec-document-reviewer subagent with precisely crafted review context (never your session history); fix issues and re-dispatch until approved (max 3 iterations, then surface to human)
|
||||
8. **User reviews written spec** — ask user to review the spec file before proceeding
|
||||
9. **Transition to implementation** — invoke writing-plans skill to create implementation plan
|
||||
|
||||
@@ -121,7 +121,7 @@ After writing the spec document:
|
||||
|
||||
1. Dispatch spec-document-reviewer subagent (see spec-document-reviewer-prompt.md)
|
||||
2. If Issues Found: fix, re-dispatch, repeat until Approved
|
||||
3. If loop exceeds 5 iterations, surface to human for guidance
|
||||
3. If loop exceeds 3 iterations, surface to human for guidance
|
||||
|
||||
**User Review Gate:**
|
||||
After the spec review loop passes, ask the user to review the written spec before proceeding:
|
||||
|
||||
@@ -94,7 +94,7 @@ const WAITING_PAGE = `<!DOCTYPE html>
|
||||
h1 { color: #333; } p { color: #666; }</style>
|
||||
</head>
|
||||
<body><h1>Brainstorm Companion</h1>
|
||||
<p>Waiting for Claude to push a screen...</p></body></html>`;
|
||||
<p>Waiting for the agent to push a screen...</p></body></html>`;
|
||||
|
||||
const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8');
|
||||
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Start the brainstorm server and output connection info
|
||||
# Usage: start-server.sh [--project-dir <path>] [--host <bind-host>] [--url-host <display-host>] [--foreground] [--background]
|
||||
#
|
||||
@@ -64,6 +64,16 @@ if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "t
|
||||
FOREGROUND="true"
|
||||
fi
|
||||
|
||||
# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected.
|
||||
if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) FOREGROUND="true" ;;
|
||||
esac
|
||||
if [[ -n "${MSYSTEM:-}" ]]; then
|
||||
FOREGROUND="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate unique session directory
|
||||
SESSION_ID="$$-$(date +%s)"
|
||||
|
||||
@@ -96,16 +106,22 @@ if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then
|
||||
OWNER_PID="$PPID"
|
||||
fi
|
||||
|
||||
# On Windows/MSYS2, the MSYS2 PID namespace is invisible to Node.js.
|
||||
# Skip owner-PID monitoring — the 30-minute idle timeout prevents orphans.
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) OWNER_PID="" ;;
|
||||
esac
|
||||
|
||||
# Foreground mode for environments that reap detached/background processes.
|
||||
if [[ "$FOREGROUND" == "true" ]]; then
|
||||
echo "$$" > "$PID_FILE"
|
||||
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.js
|
||||
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Start server, capturing output to log file
|
||||
# Use nohup to survive shell exit; disown to remove from job table
|
||||
nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.js > "$LOG_FILE" 2>&1 &
|
||||
nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
disown "$SERVER_PID" 2>/dev/null
|
||||
echo "$SERVER_PID" > "$PID_FILE"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Stop the brainstorm server and clean up
|
||||
# Usage: stop-server.sh <screen_dir>
|
||||
#
|
||||
@@ -17,7 +17,31 @@ PID_FILE="${SCREEN_DIR}/.server.pid"
|
||||
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
kill "$pid" 2>/dev/null
|
||||
|
||||
# Try to stop gracefully, fallback to force if still alive
|
||||
kill "$pid" 2>/dev/null || true
|
||||
|
||||
# Wait for graceful shutdown (up to ~2s)
|
||||
for i in {1..20}; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
# If still running, escalate to SIGKILL
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
|
||||
# Give SIGKILL a moment to take effect
|
||||
sleep 0.1
|
||||
fi
|
||||
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo '{"status": "failed", "error": "process still running"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$PID_FILE" "${SCREEN_DIR}/.server.log"
|
||||
|
||||
# Only delete ephemeral /tmp directories
|
||||
|
||||
@@ -19,32 +19,31 @@ Task tool (general-purpose):
|
||||
| Category | What to Look For |
|
||||
|----------|------------------|
|
||||
| Completeness | TODOs, placeholders, "TBD", incomplete sections |
|
||||
| Coverage | Missing error handling, edge cases, integration points |
|
||||
| Consistency | Internal contradictions, conflicting requirements |
|
||||
| Clarity | Ambiguous requirements |
|
||||
| YAGNI | Unrequested features, over-engineering |
|
||||
| Clarity | Requirements ambiguous enough to cause someone to build the wrong thing |
|
||||
| Scope | Focused enough for a single plan — not covering multiple independent subsystems |
|
||||
| Architecture | Units with clear boundaries, well-defined interfaces, independently understandable and testable |
|
||||
| YAGNI | Unrequested features, over-engineering |
|
||||
|
||||
## CRITICAL
|
||||
## Calibration
|
||||
|
||||
Look especially hard for:
|
||||
- Any TODO markers or placeholder text
|
||||
- Sections saying "to be defined later" or "will spec when X is done"
|
||||
- Sections noticeably less detailed than others
|
||||
- Units that lack clear boundaries or interfaces — can you understand what each unit does without reading its internals?
|
||||
**Only flag issues that would cause real problems during implementation planning.**
|
||||
A missing section, a contradiction, or a requirement so ambiguous it could be
|
||||
interpreted two different ways — those are issues. Minor wording improvements,
|
||||
stylistic preferences, and "sections less detailed than others" are not.
|
||||
|
||||
Approve unless there are serious gaps that would lead to a flawed plan.
|
||||
|
||||
## Output Format
|
||||
|
||||
## Spec Review
|
||||
|
||||
**Status:** ✅ Approved | ❌ Issues Found
|
||||
**Status:** Approved | Issues Found
|
||||
|
||||
**Issues (if any):**
|
||||
- [Section X]: [specific issue] - [why it matters]
|
||||
- [Section X]: [specific issue] - [why it matters for planning]
|
||||
|
||||
**Recommendations (advisory):**
|
||||
- [suggestions that don't block approval]
|
||||
**Recommendations (advisory, do not block approval):**
|
||||
- [suggestions for improvement]
|
||||
```
|
||||
|
||||
**Reviewer returns:** Status, Issues (if any), Recommendations
|
||||
|
||||
@@ -48,12 +48,21 @@ Save `screen_dir` from the response. Tell user to open the URL.
|
||||
|
||||
**Launching the server by platform:**
|
||||
|
||||
**Claude Code:**
|
||||
**Claude Code (macOS / Linux):**
|
||||
```bash
|
||||
# Default mode works — the script backgrounds the server itself
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Claude Code (Windows):**
|
||||
```bash
|
||||
# Windows auto-detects and uses foreground mode, which blocks the tool call.
|
||||
# Use run_in_background: true on the Bash tool call so the server survives
|
||||
# across conversation turns.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
When calling this via the Bash tool, set `run_in_background: true`. Then read `$SCREEN_DIR/.server-info` on the next turn to get the URL and port.
|
||||
|
||||
**Codex:**
|
||||
```bash
|
||||
# Codex reaps background processes. The script auto-detects CODEX_CI and
|
||||
|
||||
@@ -65,6 +65,6 @@ After all tasks complete and verified:
|
||||
## Integration
|
||||
|
||||
**Required workflow skills:**
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **superpowers:writing-plans** - Creates the plan this skill executes
|
||||
- **superpowers:finishing-a-development-branch** - Complete development after all tasks
|
||||
|
||||
@@ -15,7 +15,55 @@ Guide completion of development work by presenting clear options and handling ch
|
||||
|
||||
## The Process
|
||||
|
||||
### Step 1: Verify Tests
|
||||
### Step 1: Detect Environment
|
||||
|
||||
Run this FIRST, before test verification:
|
||||
|
||||
````bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
````
|
||||
|
||||
**Path A — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` is empty (externally managed worktree, detached HEAD):**
|
||||
|
||||
This is a restricted sandbox environment (e.g., Codex App worktree thread). The test toolchain may not be available. Do NOT attempt test verification — skip directly to the handoff.
|
||||
|
||||
First, ensure all work is staged and committed (`git add` + `git commit`). If staging/committing fails due to sandbox restrictions, note the uncommitted files in the handoff message.
|
||||
|
||||
Then present this to the user (do NOT present the 4-option menu):
|
||||
|
||||
```
|
||||
Implementation complete.
|
||||
Current HEAD: <full-commit-sha>
|
||||
|
||||
This workspace is externally managed (detached HEAD).
|
||||
I cannot create branches, push, or open PRs from here.
|
||||
|
||||
⚠ These commits are on a detached HEAD. If you do not create a branch,
|
||||
they may be lost when this workspace is cleaned up.
|
||||
|
||||
If your host application provides these controls:
|
||||
- "Create branch" — to name a branch, then commit/push/PR
|
||||
- "Hand off to local" — to move changes to your local checkout
|
||||
|
||||
Suggested branch name: <ticket-id/short-description>
|
||||
Suggested commit message: <summary-of-work>
|
||||
```
|
||||
|
||||
Branch name: use ticket ID if available (e.g., `pri-823/codex-compat`), otherwise slugify the first 5 words of the plan title, otherwise omit. Avoid sensitive content in branch names.
|
||||
|
||||
Skip to Step 6 (cleanup is a no-op — see guard below).
|
||||
|
||||
**Path B — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` exists (externally managed worktree, named branch):**
|
||||
|
||||
Proceed to Step 2 (verify tests, then 4-option menu).
|
||||
|
||||
**Path C — `GIT_DIR` equals `GIT_COMMON` (normal environment):**
|
||||
|
||||
Proceed to Step 2 (verify tests, then 4-option menu).
|
||||
|
||||
### Step 2: Verify Tests
|
||||
|
||||
**Before presenting options, verify tests pass:**
|
||||
|
||||
@@ -33,11 +81,11 @@ Tests failing (<N> failures). Must fix before completing:
|
||||
Cannot proceed with merge/PR until tests pass.
|
||||
```
|
||||
|
||||
Stop. Don't proceed to Step 2.
|
||||
Stop. Don't proceed to Step 3.
|
||||
|
||||
**If tests pass:** Continue to Step 2.
|
||||
**If tests pass:** Continue to Step 3.
|
||||
|
||||
### Step 2: Determine Base Branch
|
||||
### Step 3: Determine Base Branch
|
||||
|
||||
```bash
|
||||
# Try common base branches
|
||||
@@ -46,7 +94,7 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
|
||||
|
||||
Or ask: "This branch split from main - is that correct?"
|
||||
|
||||
### Step 3: Present Options
|
||||
### Step 4: Present Options
|
||||
|
||||
Present exactly these 4 options:
|
||||
|
||||
@@ -63,7 +111,7 @@ Which option?
|
||||
|
||||
**Don't add explanation** - keep options concise.
|
||||
|
||||
### Step 4: Execute Choice
|
||||
### Step 5: Execute Choice
|
||||
|
||||
#### Option 1: Merge Locally
|
||||
|
||||
@@ -84,7 +132,7 @@ git merge <feature-branch>
|
||||
git branch -d <feature-branch>
|
||||
```
|
||||
|
||||
Then: Cleanup worktree (Step 5)
|
||||
Then: Cleanup worktree (Step 6)
|
||||
|
||||
#### Option 2: Push and Create PR
|
||||
|
||||
@@ -103,7 +151,7 @@ EOF
|
||||
)"
|
||||
```
|
||||
|
||||
Then: Cleanup worktree (Step 5)
|
||||
Then: Cleanup worktree (Step 6)
|
||||
|
||||
#### Option 3: Keep As-Is
|
||||
|
||||
@@ -131,11 +179,20 @@ git checkout <base-branch>
|
||||
git branch -D <feature-branch>
|
||||
```
|
||||
|
||||
Then: Cleanup worktree (Step 5)
|
||||
Then: Cleanup worktree (Step 6)
|
||||
|
||||
### Step 5: Cleanup Worktree
|
||||
### Step 6: Cleanup Worktree
|
||||
|
||||
**For Options 1, 2, 4:**
|
||||
**First, check if worktree is externally managed:**
|
||||
|
||||
````bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
````
|
||||
|
||||
If `GIT_DIR` differs from `GIT_COMMON`: skip worktree removal — the host environment owns this workspace.
|
||||
|
||||
**Otherwise, for Options 1 and 4:**
|
||||
|
||||
Check if in worktree:
|
||||
```bash
|
||||
|
||||
@@ -265,7 +265,7 @@ Done!
|
||||
## Integration
|
||||
|
||||
**Required workflow skills:**
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **superpowers:writing-plans** - Creates the plan this skill executes
|
||||
- **superpowers:requesting-code-review** - Code review template for reviewer subagents
|
||||
- **superpowers:finishing-a-development-branch** - Complete development after all tasks
|
||||
|
||||
@@ -13,6 +13,30 @@ Git worktrees create isolated workspaces sharing the same repository, allowing w
|
||||
|
||||
**Announce at start:** "I'm using the using-git-worktrees skill to set up an isolated workspace."
|
||||
|
||||
## Step 0: Check if Already in an Isolated Workspace
|
||||
|
||||
Before creating a worktree, check if one already exists:
|
||||
|
||||
````bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
````
|
||||
|
||||
**If `GIT_DIR` differs from `GIT_COMMON`:** You are already inside a linked worktree (created by the Codex App, Claude Code's Agent tool, a previous skill run, or the user). Do NOT create another worktree. Instead:
|
||||
|
||||
1. Run project setup (auto-detect package manager as in "Run Project Setup" below)
|
||||
2. Verify clean baseline (run tests as in "Verify Clean Baseline" below)
|
||||
3. Report with branch state:
|
||||
- On a branch: "Already in an isolated workspace at `<path>` on branch `<name>`. Tests passing. Ready to implement."
|
||||
- Detached HEAD: "Already in an isolated workspace at `<path>` (detached HEAD, externally managed). Tests passing. Note: branch creation needed at finish time. Ready to implement."
|
||||
|
||||
After reporting, STOP. Do not continue to Directory Selection or Creation Steps.
|
||||
|
||||
**If `GIT_DIR` equals `GIT_COMMON`:** Proceed with the full worktree creation flow below.
|
||||
|
||||
**Sandbox fallback:** If you proceed to Creation Steps but `git worktree add -b` fails with a permission error (e.g., "Operation not permitted"), treat this as a late-detected restricted environment. Fall back to the behavior above — run setup and baseline tests in the current directory, report accordingly, and STOP.
|
||||
|
||||
## Directory Selection Process
|
||||
|
||||
Follow this priority order:
|
||||
@@ -209,9 +233,9 @@ Ready to implement auth feature
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **brainstorming** (Phase 4) - REQUIRED when design is approved and implementation follows
|
||||
- **subagent-driven-development** - REQUIRED before executing any tasks
|
||||
- **executing-plans** - REQUIRED before executing any tasks
|
||||
- **brainstorming** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **subagent-driven-development** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **executing-plans** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- Any skill needing isolated workspace
|
||||
|
||||
**Pairs with:**
|
||||
|
||||
@@ -4,7 +4,7 @@ Skills use Claude Code tool names. When you encounter these in a skill, use your
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` |
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| Task completes automatically | `close_agent` to free slot |
|
||||
@@ -13,13 +13,88 @@ Skills use Claude Code tool names. When you encounter these in a skill, use your
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
|
||||
## Subagent dispatch requires collab
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
Add to your Codex config (`~/.codex/config.toml`):
|
||||
|
||||
```toml
|
||||
[features]
|
||||
collab = true
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
## Named agent dispatch
|
||||
|
||||
Claude Code skills reference named agent types like `superpowers:code-reviewer`.
|
||||
Codex does not have a named agent registry — `spawn_agent` creates generic agents
|
||||
from built-in roles (`default`, `explorer`, `worker`).
|
||||
|
||||
When a skill says to dispatch a named agent type:
|
||||
|
||||
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
|
||||
local prompt template like `code-quality-reviewer-prompt.md`)
|
||||
2. Read the prompt content
|
||||
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
|
||||
4. Spawn a `worker` agent with the filled content as the `message`
|
||||
|
||||
| Skill instruction | Codex equivalent |
|
||||
|-------------------|------------------|
|
||||
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
|
||||
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
|
||||
|
||||
### Message framing
|
||||
|
||||
The `message` parameter is user-level input, not a system prompt. Structure it
|
||||
for maximum instruction adherence:
|
||||
|
||||
```
|
||||
Your task is to perform the following. Follow the instructions below exactly.
|
||||
|
||||
<agent-instructions>
|
||||
[filled prompt content from the agent's .md file]
|
||||
</agent-instructions>
|
||||
|
||||
Execute this now. Output ONLY the structured response following the format
|
||||
specified in the instructions above.
|
||||
```
|
||||
|
||||
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
|
||||
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
|
||||
- End with an explicit execution directive to prevent summarization of the instructions
|
||||
|
||||
### When this workaround can be removed
|
||||
|
||||
This approach compensates for Codex's plugin system not yet supporting an `agents`
|
||||
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
|
||||
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
|
||||
skills can dispatch named agent types directly.
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
|
||||
@@ -49,7 +49,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
```markdown
|
||||
# [Feature Name] Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** [One sentence describing what this builds]
|
||||
|
||||
@@ -112,36 +112,34 @@ git commit -m "feat: add specific feature"
|
||||
|
||||
## Plan Review Loop
|
||||
|
||||
After completing each chunk of the plan:
|
||||
After writing the complete plan:
|
||||
|
||||
1. Dispatch plan-document-reviewer subagent (see plan-document-reviewer-prompt.md) with precisely crafted review context — never your session history. This keeps the reviewer focused on the plan, not your thought process.
|
||||
- Provide: chunk content, path to spec document
|
||||
2. If ❌ Issues Found:
|
||||
- Fix the issues in the chunk
|
||||
- Re-dispatch reviewer for that chunk
|
||||
- Repeat until ✅ Approved
|
||||
3. If ✅ Approved: proceed to next chunk (or execution handoff if last chunk)
|
||||
|
||||
**Chunk boundaries:** Use `## Chunk N: <name>` headings to delimit chunks. Each chunk should be ≤1000 lines and logically self-contained.
|
||||
1. Dispatch a single plan-document-reviewer subagent (see plan-document-reviewer-prompt.md) with precisely crafted review context — never your session history. This keeps the reviewer focused on the plan, not your thought process.
|
||||
- Provide: path to the plan document, path to spec document
|
||||
2. If ❌ Issues Found: fix the issues, re-dispatch reviewer for the whole plan
|
||||
3. If ✅ Approved: proceed to execution handoff
|
||||
|
||||
**Review loop guidance:**
|
||||
- Same agent that wrote the plan fixes it (preserves context)
|
||||
- If loop exceeds 5 iterations, surface to human for guidance
|
||||
- Reviewers are advisory - explain disagreements if you believe feedback is incorrect
|
||||
- If loop exceeds 3 iterations, surface to human for guidance
|
||||
- Reviewers are advisory — explain disagreements if you believe feedback is incorrect
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
After saving the plan:
|
||||
After saving the plan, offer execution choice:
|
||||
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Ready to execute?"**
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Two execution options:**
|
||||
|
||||
**Execution path depends on harness capabilities:**
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**If harness has subagents (Claude Code, etc.):**
|
||||
- **REQUIRED:** Use superpowers:subagent-driven-development
|
||||
- Do NOT offer a choice - subagent-driven is the standard approach
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?"**
|
||||
|
||||
**If Subagent-Driven chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development
|
||||
- Fresh subagent per task + two-stage review
|
||||
|
||||
**If harness does NOT have subagents:**
|
||||
- Execute plan in current session using superpowers:executing-plans
|
||||
**If Inline Execution chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:executing-plans
|
||||
- Batch execution with checkpoints for review
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
Use this template when dispatching a plan document reviewer subagent.
|
||||
|
||||
**Purpose:** Verify the plan chunk is complete, matches the spec, and has proper task decomposition.
|
||||
**Purpose:** Verify the plan is complete, matches the spec, and has proper task decomposition.
|
||||
|
||||
**Dispatch after:** Each plan chunk is written
|
||||
**Dispatch after:** The complete plan is written.
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
description: "Review plan chunk N"
|
||||
description: "Review plan document"
|
||||
prompt: |
|
||||
You are a plan document reviewer. Verify this plan chunk is complete and ready for implementation.
|
||||
You are a plan document reviewer. Verify this plan is complete and ready for implementation.
|
||||
|
||||
**Plan chunk to review:** [PLAN_FILE_PATH] - Chunk N only
|
||||
**Plan to review:** [PLAN_FILE_PATH]
|
||||
**Spec for reference:** [SPEC_FILE_PATH]
|
||||
|
||||
## What to Check
|
||||
@@ -20,33 +20,30 @@ Task tool (general-purpose):
|
||||
| Category | What to Look For |
|
||||
|----------|------------------|
|
||||
| Completeness | TODOs, placeholders, incomplete tasks, missing steps |
|
||||
| Spec Alignment | Chunk covers relevant spec requirements, no scope creep |
|
||||
| Task Decomposition | Tasks atomic, clear boundaries, steps actionable |
|
||||
| File Structure | Files have clear single responsibilities, split by responsibility not layer |
|
||||
| File Size | Would any new or modified file likely grow large enough to be hard to reason about as a whole? |
|
||||
| Task Syntax | Checkbox syntax (`- [ ]`) on steps for tracking |
|
||||
| Chunk Size | Each chunk under 1000 lines |
|
||||
| Spec Alignment | Plan covers spec requirements, no major scope creep |
|
||||
| Task Decomposition | Tasks have clear boundaries, steps are actionable |
|
||||
| Buildability | Could an engineer follow this plan without getting stuck? |
|
||||
|
||||
## CRITICAL
|
||||
## Calibration
|
||||
|
||||
Look especially hard for:
|
||||
- Any TODO markers or placeholder text
|
||||
- Steps that say "similar to X" without actual content
|
||||
- Incomplete task definitions
|
||||
- Missing verification steps or expected outputs
|
||||
- Files planned to hold multiple responsibilities or likely to grow unwieldy
|
||||
**Only flag issues that would cause real problems during implementation.**
|
||||
An implementer building the wrong thing or getting stuck is an issue.
|
||||
Minor wording, stylistic preferences, and "nice to have" suggestions are not.
|
||||
|
||||
Approve unless there are serious gaps — missing requirements from the spec,
|
||||
contradictory steps, placeholder content, or tasks so vague they can't be acted on.
|
||||
|
||||
## Output Format
|
||||
|
||||
## Plan Review - Chunk N
|
||||
## Plan Review
|
||||
|
||||
**Status:** Approved | Issues Found
|
||||
|
||||
**Issues (if any):**
|
||||
- [Task X, Step Y]: [specific issue] - [why it matters]
|
||||
- [Task X, Step Y]: [specific issue] - [why it matters for implementation]
|
||||
|
||||
**Recommendations (advisory):**
|
||||
- [suggestions that don't block approval]
|
||||
**Recommendations (advisory, do not block approval):**
|
||||
- [suggestions for improvement]
|
||||
```
|
||||
|
||||
**Reviewer returns:** Status, Issues (if any), Recommendations
|
||||
|
||||
@@ -93,7 +93,7 @@ skills/
|
||||
## SKILL.md Structure
|
||||
|
||||
**Frontmatter (YAML):**
|
||||
- Only two fields supported: `name` and `description`
|
||||
- Two required fields: `name` and `description` (see [agentskills.io/specification](https://agentskills.io/specification) for all supported fields)
|
||||
- Max 1024 characters total
|
||||
- `name`: Use letters, numbers, and hyphens only (no parentheses, special chars)
|
||||
- `description`: Third-person, describes ONLY when to use (NOT what it does)
|
||||
@@ -604,7 +604,7 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
**GREEN Phase - Write Minimal Skill:**
|
||||
- [ ] Name uses only letters, numbers, hyphens (no parentheses/special chars)
|
||||
- [ ] YAML frontmatter with only name and description (max 1024 chars)
|
||||
- [ ] YAML frontmatter with required `name` and `description` fields (max 1024 chars; see [spec](https://agentskills.io/specification))
|
||||
- [ ] Description starts with "Use when..." and includes specific triggers/symptoms
|
||||
- [ ] Description written in third person
|
||||
- [ ] Keywords throughout for search (errors, symptoms, tools)
|
||||
|
||||
@@ -144,7 +144,7 @@ What works perfectly for Opus might need more detail for Haiku. If you plan to u
|
||||
## Skill structure
|
||||
|
||||
<Note>
|
||||
**YAML Frontmatter**: The SKILL.md frontmatter supports two fields:
|
||||
**YAML Frontmatter**: The SKILL.md frontmatter requires two fields:
|
||||
|
||||
* `name` - Human-readable name of the Skill (64 characters maximum)
|
||||
* `description` - One-line description of what the Skill does and when to use it (1024 characters maximum)
|
||||
@@ -1092,7 +1092,7 @@ reader = PdfReader("file.pdf")
|
||||
|
||||
### YAML frontmatter requirements
|
||||
|
||||
The SKILL.md frontmatter includes only `name` (64 characters max) and `description` (1024 characters max) fields. See the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview#skill-structure) for complete structure details.
|
||||
The SKILL.md frontmatter requires `name` (64 characters max) and `description` (1024 characters max) fields. See the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview#skill-structure) for complete structure details.
|
||||
|
||||
### Token budgets
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.js');
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs');
|
||||
const TEST_PORT = 3334;
|
||||
const TEST_DIR = '/tmp/brainstorm-test';
|
||||
|
||||
|
||||
351
tests/brainstorm-server/windows-lifecycle.test.sh
Executable file
351
tests/brainstorm-server/windows-lifecycle.test.sh
Executable file
@@ -0,0 +1,351 @@
|
||||
#!/usr/bin/env bash
|
||||
# Windows lifecycle tests for the brainstorm server.
|
||||
#
|
||||
# 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
|
||||
# - Run from the repository root, or set SUPERPOWERS_ROOT
|
||||
# - On Windows: Git Bash (OSTYPE=msys*)
|
||||
#
|
||||
# Usage:
|
||||
# bash tests/brainstorm-server/windows-lifecycle.test.sh
|
||||
set -uo pipefail
|
||||
|
||||
# ========== Configuration ==========
|
||||
|
||||
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_JS="$REPO_ROOT/skills/brainstorming/scripts/server.js"
|
||||
|
||||
TEST_DIR="${TMPDIR:-/tmp}/brainstorm-win-test-$$"
|
||||
|
||||
passed=0
|
||||
failed=0
|
||||
skipped=0
|
||||
|
||||
# ========== Helpers ==========
|
||||
|
||||
cleanup() {
|
||||
# Kill any server processes we started
|
||||
for pidvar in SERVER_PID CONTROL_PID STOP_TEST_PID; do
|
||||
pid="${!pidvar:-}"
|
||||
if [[ -n "$pid" ]]; then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
wait "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
if [[ -n "${TEST_DIR:-}" && -d "$TEST_DIR" ]]; then
|
||||
rm -rf "$TEST_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
pass() {
|
||||
echo " PASS: $1"
|
||||
passed=$((passed + 1))
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo " FAIL: $1"
|
||||
echo " $2"
|
||||
failed=$((failed + 1))
|
||||
}
|
||||
|
||||
skip() {
|
||||
echo " SKIP: $1 ($2)"
|
||||
skipped=$((skipped + 1))
|
||||
}
|
||||
|
||||
wait_for_server_info() {
|
||||
local dir="$1"
|
||||
for _ in $(seq 1 50); do
|
||||
if [[ -f "$dir/.server-info" ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
get_port_from_info() {
|
||||
# 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/.server-info" | head -1 | sed 's/"port"://'
|
||||
}
|
||||
|
||||
http_check() {
|
||||
local port="$1"
|
||||
node -e "
|
||||
const http = require('http');
|
||||
http.get('http://localhost:$port/', (res) => {
|
||||
process.exit(res.statusCode === 200 ? 0 : 1);
|
||||
}).on('error', () => process.exit(1));
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
# ========== Platform Detection ==========
|
||||
|
||||
echo ""
|
||||
echo "=== Brainstorm Server Windows Lifecycle Tests ==="
|
||||
echo "Platform: ${OSTYPE:-unknown}"
|
||||
echo "MSYSTEM: ${MSYSTEM:-unset}"
|
||||
echo "Node: $(node --version 2>/dev/null || echo 'not found')"
|
||||
echo ""
|
||||
|
||||
is_windows="false"
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) is_windows="true" ;;
|
||||
esac
|
||||
if [[ -n "${MSYSTEM:-}" ]]; then
|
||||
is_windows="true"
|
||||
fi
|
||||
|
||||
if [[ "$is_windows" != "true" ]]; then
|
||||
echo "NOTE: Not running on Windows/MSYS2 (OSTYPE=${OSTYPE:-unset})."
|
||||
echo "Windows-specific tests will be skipped. Tests 4-6 still run."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
mkdir -p "$TEST_DIR"
|
||||
|
||||
SERVER_PID=""
|
||||
CONTROL_PID=""
|
||||
STOP_TEST_PID=""
|
||||
|
||||
# ========== Test 1: OWNER_PID is empty on Windows ==========
|
||||
|
||||
echo "--- Owner PID Resolution ---"
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
# Replicate the PID resolution logic from start-server.sh lines 104-112
|
||||
TEST_OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ' || true)"
|
||||
if [[ -z "$TEST_OWNER_PID" || "$TEST_OWNER_PID" == "1" ]]; then
|
||||
TEST_OWNER_PID="$PPID"
|
||||
fi
|
||||
# The fix: clear on Windows
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) TEST_OWNER_PID="" ;;
|
||||
esac
|
||||
|
||||
if [[ -z "$TEST_OWNER_PID" ]]; then
|
||||
pass "OWNER_PID is empty on Windows after fix"
|
||||
else
|
||||
fail "OWNER_PID is empty on Windows after fix" \
|
||||
"Expected empty, got '$TEST_OWNER_PID'"
|
||||
fi
|
||||
else
|
||||
skip "OWNER_PID is empty on Windows" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 2: start-server.sh passes empty BRAINSTORM_OWNER_PID ==========
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
# Use a fake 'node' that captures the env var and exits
|
||||
FAKE_NODE_DIR="$TEST_DIR/fake-bin"
|
||||
mkdir -p "$FAKE_NODE_DIR"
|
||||
cat > "$FAKE_NODE_DIR/node" <<'FAKENODE'
|
||||
#!/usr/bin/env bash
|
||||
echo "CAPTURED_OWNER_PID=${BRAINSTORM_OWNER_PID:-__UNSET__}"
|
||||
exit 0
|
||||
FAKENODE
|
||||
chmod +x "$FAKE_NODE_DIR/node"
|
||||
|
||||
captured=$(PATH="$FAKE_NODE_DIR:$PATH" bash "$START_SCRIPT" --project-dir "$TEST_DIR/session" --foreground 2>/dev/null || true)
|
||||
owner_pid_value=$(echo "$captured" | grep "CAPTURED_OWNER_PID=" | head -1 | sed 's/CAPTURED_OWNER_PID=//')
|
||||
|
||||
if [[ "$owner_pid_value" == "" || "$owner_pid_value" == "__UNSET__" ]]; then
|
||||
pass "start-server.sh passes empty BRAINSTORM_OWNER_PID on Windows"
|
||||
else
|
||||
fail "start-server.sh passes empty BRAINSTORM_OWNER_PID on Windows" \
|
||||
"Expected empty or unset, got '$owner_pid_value'"
|
||||
fi
|
||||
|
||||
rm -rf "$FAKE_NODE_DIR" "$TEST_DIR/session"
|
||||
else
|
||||
skip "start-server.sh passes empty BRAINSTORM_OWNER_PID" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 3: Auto-foreground detection on Windows ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Foreground Mode Detection ---"
|
||||
|
||||
if [[ "$is_windows" == "true" ]]; then
|
||||
FAKE_NODE_DIR="$TEST_DIR/fake-bin"
|
||||
mkdir -p "$FAKE_NODE_DIR"
|
||||
cat > "$FAKE_NODE_DIR/node" <<'FAKENODE'
|
||||
#!/usr/bin/env bash
|
||||
echo "FOREGROUND_MODE=true"
|
||||
exit 0
|
||||
FAKENODE
|
||||
chmod +x "$FAKE_NODE_DIR/node"
|
||||
|
||||
# Run WITHOUT --foreground flag — Windows should auto-detect
|
||||
captured=$(PATH="$FAKE_NODE_DIR:$PATH" bash "$START_SCRIPT" --project-dir "$TEST_DIR/session2" 2>/dev/null || true)
|
||||
|
||||
if echo "$captured" | grep -q "FOREGROUND_MODE=true"; then
|
||||
pass "Windows auto-detects foreground mode"
|
||||
else
|
||||
fail "Windows auto-detects foreground mode" \
|
||||
"Expected foreground code path, output: $captured"
|
||||
fi
|
||||
|
||||
rm -rf "$FAKE_NODE_DIR" "$TEST_DIR/session2"
|
||||
else
|
||||
skip "Windows auto-detects foreground mode" "not on Windows"
|
||||
fi
|
||||
|
||||
# ========== Test 4: Server survives past 60-second lifecycle check ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Server Survival (lifecycle check) ---"
|
||||
|
||||
mkdir -p "$TEST_DIR/survival"
|
||||
|
||||
echo " Starting server (will wait ~75s to verify survival past lifecycle check)..."
|
||||
|
||||
BRAINSTORM_DIR="$TEST_DIR/survival" \
|
||||
BRAINSTORM_HOST="127.0.0.1" \
|
||||
BRAINSTORM_URL_HOST="localhost" \
|
||||
BRAINSTORM_OWNER_PID="" \
|
||||
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
|
||||
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 .server-info within 5 seconds"
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
SERVER_PID=""
|
||||
else
|
||||
pass "Server starts successfully with empty OWNER_PID"
|
||||
|
||||
SERVER_PORT=$(get_port_from_info "$TEST_DIR/survival")
|
||||
|
||||
sleep 75
|
||||
|
||||
if kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
pass "Server is still alive after 75 seconds"
|
||||
else
|
||||
fail "Server is still alive after 75 seconds" \
|
||||
"Server died. Log tail: $(tail -5 "$TEST_DIR/survival/.server.log" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
if http_check "$SERVER_PORT"; then
|
||||
pass "Server responds to HTTP after lifecycle check window"
|
||||
else
|
||||
fail "Server responds to HTTP after lifecycle check window" \
|
||||
"HTTP request to port $SERVER_PORT failed"
|
||||
fi
|
||||
|
||||
if grep -q "owner process exited" "$TEST_DIR/survival/.server.log" 2>/dev/null; then
|
||||
fail "No 'owner process exited' in logs" \
|
||||
"Found spurious owner-exit shutdown in log"
|
||||
else
|
||||
pass "No 'owner process exited' in logs"
|
||||
fi
|
||||
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
wait "$SERVER_PID" 2>/dev/null || true
|
||||
SERVER_PID=""
|
||||
fi
|
||||
|
||||
# ========== Test 5: Bad OWNER_PID causes shutdown (control) ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Control: Bad OWNER_PID causes shutdown ---"
|
||||
|
||||
mkdir -p "$TEST_DIR/control"
|
||||
|
||||
# Find a PID that does not exist
|
||||
BAD_PID=99999
|
||||
while kill -0 "$BAD_PID" 2>/dev/null; do
|
||||
BAD_PID=$((BAD_PID + 1))
|
||||
done
|
||||
|
||||
BRAINSTORM_DIR="$TEST_DIR/control" \
|
||||
BRAINSTORM_HOST="127.0.0.1" \
|
||||
BRAINSTORM_URL_HOST="localhost" \
|
||||
BRAINSTORM_OWNER_PID="$BAD_PID" \
|
||||
BRAINSTORM_PORT=$((49152 + RANDOM % 16383)) \
|
||||
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 .server-info within 5 seconds"
|
||||
kill "$CONTROL_PID" 2>/dev/null || true
|
||||
CONTROL_PID=""
|
||||
else
|
||||
pass "Control server starts with bad OWNER_PID=$BAD_PID"
|
||||
|
||||
echo " Waiting ~75s for lifecycle check to kill server..."
|
||||
sleep 75
|
||||
|
||||
if kill -0 "$CONTROL_PID" 2>/dev/null; then
|
||||
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
|
||||
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
|
||||
pass "Control server logs 'owner process exited'"
|
||||
else
|
||||
fail "Control server logs 'owner process exited'" \
|
||||
"Log tail: $(tail -5 "$TEST_DIR/control/.server.log" 2>/dev/null)"
|
||||
fi
|
||||
fi
|
||||
|
||||
wait "$CONTROL_PID" 2>/dev/null || true
|
||||
CONTROL_PID=""
|
||||
|
||||
# ========== Test 6: stop-server.sh cleanly stops the server ==========
|
||||
|
||||
echo ""
|
||||
echo "--- Clean Shutdown ---"
|
||||
|
||||
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_JS" > "$TEST_DIR/stop-test/.server.log" 2>&1 &
|
||||
STOP_TEST_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"
|
||||
kill "$STOP_TEST_PID" 2>/dev/null || true
|
||||
STOP_TEST_PID=""
|
||||
else
|
||||
bash "$STOP_SCRIPT" "$TEST_DIR/stop-test" >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 "$STOP_TEST_PID" 2>/dev/null; then
|
||||
pass "stop-server.sh cleanly stops the server"
|
||||
else
|
||||
fail "stop-server.sh cleanly stops the server" \
|
||||
"Server PID $STOP_TEST_PID is still alive after stop"
|
||||
kill "$STOP_TEST_PID" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
wait "$STOP_TEST_PID" 2>/dev/null || true
|
||||
STOP_TEST_PID=""
|
||||
|
||||
# ========== Summary ==========
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $passed passed, $failed failed, $skipped skipped ==="
|
||||
|
||||
if [[ $failed -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
@@ -16,7 +16,7 @@ const crypto = require('crypto');
|
||||
const path = require('path');
|
||||
|
||||
// The module under test — will be the new zero-dep server file
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.js');
|
||||
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs');
|
||||
let ws;
|
||||
|
||||
try {
|
||||
|
||||
94
tests/codex-app-compat/test-environment-detection.sh
Executable file
94
tests/codex-app-compat/test-environment-detection.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Test environment detection logic from PRI-823
|
||||
# Tests the git-dir vs git-common-dir comparison used by
|
||||
# using-git-worktrees Step 0 and finishing-a-development-branch Step 1.5
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
|
||||
log_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
||||
log_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
# Helper: run detection and return "linked" or "normal"
|
||||
detect_worktree() {
|
||||
local git_dir git_common
|
||||
git_dir=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
git_common=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
if [ "$git_dir" != "$git_common" ]; then
|
||||
echo "linked"
|
||||
else
|
||||
echo "normal"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Test 1: Normal repo detection ==="
|
||||
cd "$TEMP_DIR"
|
||||
git init test-repo > /dev/null 2>&1
|
||||
cd test-repo
|
||||
git commit --allow-empty -m "init" > /dev/null 2>&1
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Normal repo detected as normal"
|
||||
else
|
||||
log_fail "Normal repo detected as '$result' (expected 'normal')"
|
||||
fi
|
||||
|
||||
echo "=== Test 2: Linked worktree detection ==="
|
||||
git worktree add "$TEMP_DIR/test-wt" -b test-branch > /dev/null 2>&1
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Linked worktree detected as linked"
|
||||
else
|
||||
log_fail "Linked worktree detected as '$result' (expected 'linked')"
|
||||
fi
|
||||
|
||||
echo "=== Test 3: Detached HEAD detection ==="
|
||||
git checkout --detach HEAD > /dev/null 2>&1
|
||||
branch=$(git branch --show-current)
|
||||
if [ -z "$branch" ]; then
|
||||
log_pass "Detached HEAD: branch is empty"
|
||||
else
|
||||
log_fail "Detached HEAD: branch is '$branch' (expected empty)"
|
||||
fi
|
||||
|
||||
echo "=== Test 4: Linked worktree + detached HEAD (Codex App simulation) ==="
|
||||
result=$(detect_worktree)
|
||||
branch=$(git branch --show-current)
|
||||
if [ "$result" = "linked" ] && [ -z "$branch" ]; then
|
||||
log_pass "Codex App simulation: linked + detached HEAD"
|
||||
else
|
||||
log_fail "Codex App simulation: result='$result', branch='$branch'"
|
||||
fi
|
||||
|
||||
echo "=== Test 5: Cleanup guard — linked worktree should NOT remove ==="
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Cleanup guard: linked worktree correctly detected (would skip removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'linked', got '$result'"
|
||||
fi
|
||||
|
||||
echo "=== Test 6: Cleanup guard — main repo SHOULD remove ==="
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Cleanup guard: main repo correctly detected (would proceed with removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'normal', got '$result'"
|
||||
fi
|
||||
|
||||
# Cleanup worktree before temp dir removal
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
git worktree remove "$TEMP_DIR/test-wt" > /dev/null 2>&1 || true
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Run all explicit skill request tests
|
||||
# Usage: ./run-all.sh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Test where Claude explicitly describes subagent-driven-development before user requests it
|
||||
# This mimics the original failure scenario
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Extended multi-turn test with more conversation history
|
||||
# This tries to reproduce the failure by building more context
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Test with haiku model and user's CLAUDE.md
|
||||
# This tests whether a cheaper/faster model fails more easily
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Test explicit skill requests in multi-turn conversations
|
||||
# Usage: ./run-multiturn-test.sh
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Test explicit skill requests (user names a skill directly)
|
||||
# Usage: ./run-test.sh <skill-name> <prompt-file>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Run all skill triggering tests
|
||||
# Usage: ./run-all.sh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Test skill triggering with naive prompts
|
||||
# Usage: ./run-test.sh <skill-name> <prompt-file>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Scaffold the Go Fractals test project
|
||||
# Usage: ./scaffold.sh /path/to/target/directory
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Run a subagent-driven-development test
|
||||
# Usage: ./run-test.sh <test-name> [--plugin-dir <path>]
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Scaffold the Svelte Todo test project
|
||||
# Usage: ./scaffold.sh /path/to/target/directory
|
||||
|
||||
|
||||
Reference in New Issue
Block a user