Compare commits

...

14 Commits

Author SHA1 Message Date
Drew Ritter
07c5e799fa sync-to-codex-plugin: seed interface.defaultPrompt
Codex plugin pages use interface.defaultPrompt to show suggested
prompts on the plugin's app card; the generator now emits two
domain-neutral seed prompts so the superpowers listing isn't empty.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:53:05 -07:00
Jesse Vincent
f9b088f7b3 Merge pull request #1165 from obra/mirror-codex-plugin-tooling
Mirror codex plugin tooling
2026-04-14 14:13:31 -07:00
Drew Ritter
bc25777c6a sync-to-codex-plugin: anchor EXCLUDES patterns to source root
Rsync exclude patterns without a leading "/" match any directory of
the given name at any depth. The previous "scripts/" pattern was
meant to exclude upstream's top-level scripts/ dir (which contains
sync-to-codex-plugin.sh itself, bump-version.sh, etc.) but also
incorrectly excluded skills/brainstorming/scripts/ — a legitimate
skill-adjacent dir with 5 files (frame-template.html, helper.js,
server.cjs, start-server.sh, stop-server.sh).

Found during a determinism check: comparing the hand-crafted
add-superpowers-plugin bootstrap PR against an automated bootstrap
PR produced a diff showing those 5 files were missing from the
automated version.

Fix: anchor every top-level-only exclude with a leading "/".
.DS_Store stays unanchored because Finder creates them anywhere.

This also prevents future drift if anyone adds a tests/, hooks/,
docs/, lib/, etc. subdir inside a skill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:03:56 -07:00
Drew Ritter
bcdd7fa24c sync-to-codex-plugin: exclude assets/, add --bootstrap flag
Two coupled changes:

1. Add assets/ to EXCLUDES. A normal sync run was deleting
   plugins/superpowers/assets/ via --delete because the corresponding
   directory doesn't exist upstream. Confirmed via dry-run that the
   previous version would wipe both brand asset files on next sync.

2. Add --bootstrap and --assets-src flags to support creating the
   initial plugin PR from scratch. Bootstrap mode skips the
   "plugin must exist on base" preflight, creates the plugin
   directory, rsyncs upstream content, then copies
   PrimeRadiant_Favicon.{svg,png} from --assets-src into
   plugins/superpowers/assets/ as superpowers-small.svg and
   app-icon.png. Run once by one team member to open the initial
   PR; every subsequent run is a normal (non-bootstrap) sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:59:26 -07:00
Drew Ritter
6149f3635a sync-to-codex-plugin: align plugin.json heredoc with current live shape
The live .codex-plugin/plugin.json in the downstream fork was cleaned up
(websiteURL, privacyPolicyURL, termsOfServiceURL, and defaultPrompt
removed) and icon fields were added (composerIcon, logo pointing at
assets/superpowers-small.svg and assets/app-icon.png). Update the
heredoc to produce the same shape so future sync runs don't wipe the
icon fields or reintroduce the removed URL fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:48:05 -07:00
Drew Ritter
777a9770d8 sync-to-codex-plugin: mirror CODE_OF_CONDUCT.md, drop agents/openai.yaml overlay
- Remove CODE_OF_CONDUCT.md from EXCLUDES so it syncs from upstream
  (per PR #1165 review feedback on the exclude list)
- Remove the agents/openai.yaml overlay generator and its exclude entry
  — the file duplicates fields already in .codex-plugin/plugin.json and
  only 6 of 28 upstream plugins ship one, so we match the 22-plugin
  majority shape

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:27:59 -07:00
Drew Ritter
da283df058 remove things we dont need 2026-04-14 13:23:17 -07:00
Jesse Vincent
a569527b89 Merge pull request #1163 from shaanmajid/chore/remove-stray-changelog
chore: remove vestigial CHANGELOG.md
2026-04-14 13:22:24 -07:00
Drew Ritter
ac1c715ffb rewrites sync tool to clone the fork, open a PR, and regenerate overlays inline
The previous version was a local rsync helper that required a hand-maintained
destination path. This rewrite makes it path/user-agnostic and gives every team
member the same flow:

- Clones prime-radiant-inc/openai-codex-plugins fresh into a temp dir per run
  (trap EXIT cleans up)
- Auto-detects upstream from the script's own location
- Preflight: rsync, git, gh auth, python3, upstream package.json
- Reads upstream version from package.json and bakes it into the regenerated
  .codex-plugin/plugin.json, so version bumps flow through
- Regenerates both overlay files (.codex-plugin/plugin.json and
  agents/openai.yaml) inline via heredoc — single source of truth
- Pushes a sync/superpowers-<sha>-<UTC-timestamp> branch and opens a PR via
  gh pr create; prints PR URL and /files diff URL on completion
- --dry-run, --yes, --base BRANCH, --local PATH flags for all the usual modes
- Deterministic: two runs against the same upstream SHA produce PRs with
  identical diffs, so the tool itself can be sanity-checked by running twice

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:18:36 -07:00
Drew Ritter
8c8c5e87ce adds tooling to mirror superpowers as a codex plugin with the appropriate metadata changes 2026-04-14 12:03:59 -07:00
Shaan Majid
a5d36b1300 chore: remove vestigial CHANGELOG.md 2026-04-14 12:36:07 -05:00
Jesse Vincent
917e5f53b1 Fix Discord invite link 2026-04-06 15:48:58 -07:00
Jesse Vincent
a6b1a1fa0c Update Discord invite link 2026-04-06 15:46:52 -07:00
Jesse Vincent
b7a8f76985 Merge pull request #1029 from obra/readme-release-announcements
Add release announcements link, consolidate Community section
2026-04-01 19:34:36 -07:00
4 changed files with 388 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Help
url: https://discord.gg/Jd8Vphy9jq
url: https://discord.gg/35wsABTejz
about: For usage questions, troubleshooting help, and general discussion, please visit our Discord instead of opening an issue.

View File

@@ -1,13 +0,0 @@
# 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`)

View File

@@ -185,6 +185,6 @@ MIT License - see LICENSE file for details
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/Jd8Vphy9jq) for community support, questions, and sharing what you're building with Superpowers
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions

386
scripts/sync-to-codex-plugin.sh Executable file
View File

@@ -0,0 +1,386 @@
#!/usr/bin/env bash
#
# sync-to-codex-plugin.sh
#
# Sync this superpowers checkout → prime-radiant-inc/openai-codex-plugins.
# Clones the fork fresh into a temp dir, rsyncs upstream content, regenerates
# the Codex overlay file (.codex-plugin/plugin.json) inline, commits, pushes a
# sync branch, and opens a PR.
# Path/user agnostic — auto-detects upstream from script location.
#
# Deterministic: running twice against the same upstream SHA produces PRs with
# identical diffs, so two back-to-back runs can verify the tool itself.
#
# Usage:
# ./scripts/sync-to-codex-plugin.sh # full run
# ./scripts/sync-to-codex-plugin.sh -n # dry run
# ./scripts/sync-to-codex-plugin.sh -y # skip confirm
# ./scripts/sync-to-codex-plugin.sh --local PATH # existing checkout
# ./scripts/sync-to-codex-plugin.sh --base BRANCH # default: main
# ./scripts/sync-to-codex-plugin.sh --bootstrap --assets-src DIR # create initial plugin
#
# Bootstrap mode: skips the "plugin must exist on base" check and seeds
# plugins/superpowers/assets/ from --assets-src <dir> which must contain
# PrimeRadiant_Favicon.svg and PrimeRadiant_Favicon.png. Run once by one
# team member to create the initial PR; every subsequent run is a normal
# (non-bootstrap) sync.
#
# Requires: bash, rsync, git, gh (authenticated), python3.
set -euo pipefail
# =============================================================================
# Config — edit as upstream or canonical plugin shape evolves
# =============================================================================
FORK="prime-radiant-inc/openai-codex-plugins"
DEFAULT_BASE="main"
DEST_REL="plugins/superpowers"
# Paths in upstream that should NOT land in the embedded plugin.
# The Codex-only paths are here too — they're managed by generate/bootstrap
# steps, not by rsync.
#
# All patterns use a leading "/" to anchor them to the source root.
# Unanchored patterns like "scripts/" would match any directory named
# "scripts" at any depth — including legitimate nested dirs like
# skills/brainstorming/scripts/. Anchoring prevents that.
# (.DS_Store is intentionally unanchored — Finder creates them everywhere.)
EXCLUDES=(
# Dotfiles and infra — top-level only
"/.claude/"
"/.claude-plugin/"
"/.codex/"
"/.cursor-plugin/"
"/.git/"
"/.gitattributes"
"/.github/"
"/.gitignore"
"/.opencode/"
"/.version-bump.json"
"/.worktrees/"
".DS_Store"
# Root ceremony files
"/AGENTS.md"
"/CHANGELOG.md"
"/CLAUDE.md"
"/GEMINI.md"
"/RELEASE-NOTES.md"
"/gemini-extension.json"
"/package.json"
# Directories not shipped by canonical Codex plugins
"/commands/"
"/docs/"
"/hooks/"
"/lib/"
"/scripts/"
"/tests/"
"/tmp/"
# Codex-only paths — managed outside rsync
"/.codex-plugin/"
"/assets/"
)
# =============================================================================
# Generated overlay file
# =============================================================================
# Writes the Codex plugin manifest to "$1" with the given upstream version.
# Args: dest_path, version
generate_plugin_json() {
local dest="$1"
local version="$2"
mkdir -p "$(dirname "$dest")"
cat > "$dest" <<EOF
{
"name": "superpowers",
"version": "$version",
"description": "Core skills library for Codex: planning, TDD, debugging, and collaboration workflows.",
"author": {
"name": "Jesse Vincent",
"email": "jesse@fsck.com",
"url": "https://github.com/obra"
},
"homepage": "https://github.com/obra/superpowers",
"repository": "https://github.com/obra/superpowers",
"license": "MIT",
"keywords": [
"skills",
"planning",
"tdd",
"debugging",
"code-review",
"workflow"
],
"skills": "./skills/",
"interface": {
"displayName": "Superpowers",
"shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",
"longDescription": "Use Superpowers to guide agent work through brainstorming, implementation planning, test-driven development, systematic debugging, parallel execution, code review, and finish-the-branch workflows adapted for Codex.",
"developerName": "Jesse Vincent",
"category": "Coding",
"capabilities": [
"Interactive",
"Read",
"Write"
],
"defaultPrompt": [
"I've got an idea for something I'd like to build.",
"Let's add a feature to this project."
],
"brandColor": "#F59E0B",
"composerIcon": "./assets/superpowers-small.svg",
"logo": "./assets/app-icon.png",
"screenshots": []
}
}
EOF
}
# =============================================================================
# Args
# =============================================================================
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
UPSTREAM="$(cd "$SCRIPT_DIR/.." && pwd)"
BASE="$DEFAULT_BASE"
DRY_RUN=0
YES=0
LOCAL_CHECKOUT=""
BOOTSTRAP=0
ASSETS_SRC=""
usage() {
sed -n 's/^# \{0,1\}//;2,27p' "$0"
exit "${1:-0}"
}
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--dry-run) DRY_RUN=1; shift ;;
-y|--yes) YES=1; shift ;;
--local) LOCAL_CHECKOUT="$2"; shift 2 ;;
--base) BASE="$2"; shift 2 ;;
--bootstrap) BOOTSTRAP=1; shift ;;
--assets-src) ASSETS_SRC="$2"; shift 2 ;;
-h|--help) usage 0 ;;
*) echo "Unknown arg: $1" >&2; usage 2 ;;
esac
done
# =============================================================================
# Preflight
# =============================================================================
die() { echo "ERROR: $*" >&2; exit 1; }
command -v rsync >/dev/null || die "rsync not found in PATH"
command -v git >/dev/null || die "git not found in PATH"
command -v gh >/dev/null || die "gh not found — install GitHub CLI"
command -v python3 >/dev/null || die "python3 not found in PATH"
gh auth status >/dev/null 2>&1 || die "gh not authenticated — run 'gh auth login'"
[[ -d "$UPSTREAM/.git" ]] || die "upstream '$UPSTREAM' is not a git checkout"
[[ -f "$UPSTREAM/package.json" ]] || die "upstream has no package.json — cannot read version"
# Bootstrap-mode validation
if [[ $BOOTSTRAP -eq 1 ]]; then
[[ -n "$ASSETS_SRC" ]] || die "--bootstrap requires --assets-src <path>"
ASSETS_SRC="$(cd "$ASSETS_SRC" 2>/dev/null && pwd)" || die "assets source '$ASSETS_SRC' is not a directory"
[[ -f "$ASSETS_SRC/PrimeRadiant_Favicon.svg" ]] || die "assets source missing PrimeRadiant_Favicon.svg"
[[ -f "$ASSETS_SRC/PrimeRadiant_Favicon.png" ]] || die "assets source missing PrimeRadiant_Favicon.png"
fi
# Read the upstream version from package.json
UPSTREAM_VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' "$UPSTREAM/package.json")"
[[ -n "$UPSTREAM_VERSION" ]] || die "could not read 'version' from upstream package.json"
UPSTREAM_BRANCH="$(cd "$UPSTREAM" && git branch --show-current)"
UPSTREAM_SHA="$(cd "$UPSTREAM" && git rev-parse HEAD)"
UPSTREAM_SHORT="$(cd "$UPSTREAM" && git rev-parse --short HEAD)"
confirm() {
[[ $YES -eq 1 ]] && return 0
read -rp "$1 [y/N] " ans
[[ "$ans" == "y" || "$ans" == "Y" ]]
}
if [[ "$UPSTREAM_BRANCH" != "main" ]]; then
echo "WARNING: upstream is on '$UPSTREAM_BRANCH', not 'main'"
confirm "Sync from '$UPSTREAM_BRANCH' anyway?" || exit 1
fi
UPSTREAM_STATUS="$(cd "$UPSTREAM" && git status --porcelain)"
if [[ -n "$UPSTREAM_STATUS" ]]; then
echo "WARNING: upstream has uncommitted changes:"
echo "$UPSTREAM_STATUS" | sed 's/^/ /'
echo "Sync will use working-tree state, not HEAD ($UPSTREAM_SHORT)."
confirm "Continue anyway?" || exit 1
fi
# =============================================================================
# Prepare destination (clone fork fresh, or use --local)
# =============================================================================
CLEANUP_DIR=""
cleanup() {
[[ -n "$CLEANUP_DIR" ]] && rm -rf "$CLEANUP_DIR"
}
trap cleanup EXIT
if [[ -n "$LOCAL_CHECKOUT" ]]; then
DEST_REPO="$(cd "$LOCAL_CHECKOUT" && pwd)"
[[ -d "$DEST_REPO/.git" ]] || die "--local path '$DEST_REPO' is not a git checkout"
else
echo "Cloning $FORK..."
CLEANUP_DIR="$(mktemp -d)"
DEST_REPO="$CLEANUP_DIR/openai-codex-plugins"
gh repo clone "$FORK" "$DEST_REPO" >/dev/null
fi
DEST="$DEST_REPO/$DEST_REL"
# Checkout base branch
cd "$DEST_REPO"
git checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
# Plugin-existence check depends on mode
if [[ $BOOTSTRAP -eq 1 ]]; then
[[ ! -d "$DEST" ]] || die "--bootstrap but base branch '$BASE' already has '$DEST_REL/' — use normal sync instead"
mkdir -p "$DEST"
else
[[ -d "$DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap + --assets-src, or pass --base <branch>"
fi
# =============================================================================
# Create sync branch
# =============================================================================
TIMESTAMP="$(date -u +%Y%m%d-%H%M%S)"
if [[ $BOOTSTRAP -eq 1 ]]; then
SYNC_BRANCH="bootstrap/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
else
SYNC_BRANCH="sync/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
fi
git checkout -q -b "$SYNC_BRANCH"
# =============================================================================
# Build rsync args
# =============================================================================
RSYNC_ARGS=(-av --delete)
for pat in "${EXCLUDES[@]}"; do RSYNC_ARGS+=(--exclude="$pat"); done
# =============================================================================
# Dry run preview (always shown)
# =============================================================================
echo ""
echo "Upstream: $UPSTREAM ($UPSTREAM_BRANCH @ $UPSTREAM_SHORT)"
echo "Version: $UPSTREAM_VERSION"
echo "Fork: $FORK"
echo "Base: $BASE"
echo "Branch: $SYNC_BRANCH"
if [[ $BOOTSTRAP -eq 1 ]]; then
echo "Mode: BOOTSTRAP (creating initial plugin from scratch)"
echo "Assets: $ASSETS_SRC"
fi
echo ""
echo "=== Preview (rsync --dry-run) ==="
rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$UPSTREAM/" "$DEST/"
echo "=== End preview ==="
echo ""
echo "Overlay file (.codex-plugin/plugin.json) will be regenerated with"
echo "version $UPSTREAM_VERSION regardless of rsync output."
if [[ $BOOTSTRAP -eq 1 ]]; then
echo "Assets (superpowers-small.svg, app-icon.png) will be seeded from:"
echo " $ASSETS_SRC"
fi
if [[ $DRY_RUN -eq 1 ]]; then
echo ""
echo "Dry run only. Nothing was changed or pushed."
exit 0
fi
# =============================================================================
# Apply
# =============================================================================
echo ""
confirm "Apply changes, push branch, and open PR?" || { echo "Aborted."; exit 1; }
echo ""
echo "Syncing upstream content..."
rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$DEST/"
if [[ $BOOTSTRAP -eq 1 ]]; then
echo "Seeding brand assets..."
mkdir -p "$DEST/assets"
cp "$ASSETS_SRC/PrimeRadiant_Favicon.svg" "$DEST/assets/superpowers-small.svg"
cp "$ASSETS_SRC/PrimeRadiant_Favicon.png" "$DEST/assets/app-icon.png"
fi
echo "Regenerating overlay file..."
generate_plugin_json "$DEST/.codex-plugin/plugin.json" "$UPSTREAM_VERSION"
# Bail early if nothing actually changed
cd "$DEST_REPO"
if [[ -z "$(git status --porcelain "$DEST_REL")" ]]; then
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
exit 0
fi
# =============================================================================
# Commit, push, open PR
# =============================================================================
git add "$DEST_REL"
if [[ $BOOTSTRAP -eq 1 ]]; then
COMMIT_TITLE="bootstrap superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
PR_BODY="Initial bootstrap of the superpowers plugin from upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
Creates \`plugins/superpowers/\` from scratch: upstream content via rsync, \`.codex-plugin/plugin.json\` regenerated inline, brand assets seeded from a local Brand Assets directory.
Run via: \`scripts/sync-to-codex-plugin.sh --bootstrap --assets-src <path>\`
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
This is a one-time bootstrap. Subsequent syncs will be normal (non-bootstrap) runs and will not touch the \`assets/\` directory."
else
COMMIT_TITLE="sync superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
PR_BODY="Automated sync from superpowers upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
Run via: \`scripts/sync-to-codex-plugin.sh\`
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
Running the sync tool again against the same upstream SHA should produce a PR with an identical diff — use that to verify the tool is behaving."
fi
git commit --quiet -m "$COMMIT_TITLE
Automated sync via scripts/sync-to-codex-plugin.sh
Upstream: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
Branch: $SYNC_BRANCH"
echo "Pushing $SYNC_BRANCH to $FORK..."
git push -u origin "$SYNC_BRANCH" --quiet
echo "Opening PR..."
PR_URL="$(gh pr create \
--repo "$FORK" \
--base "$BASE" \
--head "$SYNC_BRANCH" \
--title "$COMMIT_TITLE" \
--body "$PR_BODY")"
PR_NUM="${PR_URL##*/}"
DIFF_URL="https://github.com/$FORK/pull/$PR_NUM/files"
echo ""
echo "PR opened: $PR_URL"
echo "Diff view: $DIFF_URL"