Skip to content

docs: use node installer flow for Codex/OpenCode#410

Open
kundeng wants to merge 2 commits intoobra:mainfrom
kundeng:pr/installer-docs
Open

docs: use node installer flow for Codex/OpenCode#410
kundeng wants to merge 2 commits intoobra:mainfrom
kundeng:pr/installer-docs

Conversation

@kundeng
Copy link

@kundeng kundeng commented Feb 4, 2026

Updates the Codex/OpenCode INSTALL.md docs to use the new node-based installer commands introduced in #409.

  • Codex: first install via a temp clone + node ... install, updates via node ... upgrade
  • OpenCode: same (including the Updating section)

This keeps defaults upstream-friendly (obra/superpowers@main) and avoids fork-specific flags.

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

The pull request introduces a centralized installer framework replacing direct git clone operations. A new installer-core.js module provides install, upgrade, and doctor commands with git-based workflows and symlink management. These utilities are integrated into existing CLI entry points for Codex and OpenCode, with updated installation documentation reflecting the new flow.

Changes

Cohort / File(s) Summary
Core Installer Framework
lib/installer-core.js
New 356-line module providing environment utilities, git operations, symlink management, config resolution, and workflows for install/upgrade/doctor commands supporting multiple IDEs (codex, kilocode, opencode).
Codex Integration
\.codex/superpowers-codex, \.codex/INSTALL.md
Added imports for installer functions and early command dispatch for install/upgrade/doctor. Updated installation documentation to use a temporary clone workflow and installer-based upgrade path instead of direct git operations.
OpenCode Integration
\.opencode/superpowers-opencode, \.opencode/INSTALL.md
New CLI entry point script (43 lines) wiring installer utilities with help text and command dispatch. Updated installation guide to reflect centralized installer flow, symlink creation via installer, and node-based upgrade commands.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as CLI Entry Point
    participant Installer as installer-core
    participant Git as Git Operations
    participant FS as File System
    participant Symlink as Symlink Manager

    User->>CLI: run install command
    CLI->>Installer: parseArgs(argv)
    Installer-->>CLI: parsed config
    CLI->>Installer: runInstall(config)
    
    Installer->>Git: gitEnsureCloned(repo, path)
    Git->>FS: clone repo to /tmp
    Git-->>Installer: repo cloned
    
    Installer->>Git: gitCheckoutRef(ref)
    Git-->>Installer: ref checked out
    
    Installer->>FS: resolveInstallConfig(paths)
    FS-->>Installer: config resolved
    
    Installer->>Symlink: ensureSymlink(source, target)
    Symlink->>FS: create symlink ~/.codex/superpowers
    Symlink-->>Installer: symlink created
    
    Installer-->>CLI: installation complete
    CLI-->>User: success message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A new framework hops into place,
Installers running at lightning pace,
No more tangled symlinks to chase—
The superpowers now centralize with grace! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: updating installation documentation to use a new node-based installer flow for both Codex and OpenCode.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.opencode/INSTALL.md (1)

3-7: ⚠️ Potential issue | 🟠 Major

Add Node.js to prerequisites.

The installer now relies on node commands, but the prerequisites omit Node.js.

📌 Suggested doc update
 ## Prerequisites
 
 - [OpenCode.ai](https://opencode.ai) installed
 - Git installed
+- Node.js installed (for `node ... install/upgrade`)
🤖 Fix all issues with AI agents
In @.codex/INSTALL.md:
- Around line 5-20: Add a "Prerequisites" section at the top of
.codex/INSTALL.md that explicitly lists Node.js (specify a minimum version,
e.g., Node 14+ or current LTS) and Git as required before running the installer,
and include brief instructions for verifying them (e.g., run node --version and
git --version) plus links or pointers for installing them; update the
Installation text in the existing "Run installer" section to reference this new
Prerequisites section so first-time installs won't fail due to missing node/git.

In `@lib/installer-core.js`:
- Around line 196-200: The update flag is incorrectly computed because
rawArgs['no-update'] can be the string "false" (truthy); modify the logic that
sets update (where rawArgs and defaults are assembled, referencing rawArgs and
the update property) to normalize string booleans first (e.g., coerce
"true"/"false" to actual booleans or add a small helper like parseBoolean to
handle strings, undefined, and actual booleans) and then compute update as
!(normalizedNoUpdate || false) so that --no-update=false yields update=true.
- Around line 323-325: The code calls gitFastForwardUpdate unconditionally after
gitCheckoutRef which can fail if the checkout left a detached HEAD; modify the
flow in installer-core.js to detect whether the repo is on a detached HEAD
before attempting to fast-forward: after gitCheckoutRef({ repoDir: config.dir,
ref: config.ref }) and only if config.update is true, run a check (e.g., run git
rev-parse --abbrev-ref HEAD or use a new helper isDetachedHead(repoDir)) and
skip calling gitFastForwardUpdate({ repoDir: config.dir }) when detached;
alternatively, add an isDetached flag return from gitCheckoutRef and use it to
conditionally skip gitFastForwardUpdate.

Comment on lines 5 to 20
## Installation

1. **Clone superpowers repository**:
1. **Run installer**
This will clone/update the central repo at `~/.superpowers` and link it into Codex at `~/.codex/superpowers`.

If this is your first install (and `~/.superpowers` does not exist yet), run from a temporary clone:
```bash
mkdir -p ~/.codex/superpowers
cd ~/.codex/superpowers
git clone https://github.com/obra/superpowers.git .
git clone https://github.com/obra/superpowers.git /tmp/superpowers
node /tmp/superpowers/.codex/superpowers-codex install
```

2. **Create personal skills directory**:
If you already have `~/.superpowers` installed, you can run:
```bash
mkdir -p ~/.codex/skills
node ~/.superpowers/.codex/superpowers-codex upgrade
```

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add Node.js + Git prerequisites to avoid failed installs.

The new flow requires node and git, but the doc doesn’t state that. Without this, a first-time setup will fail.

📌 Suggested doc update
 ## Installation
+
+## Prerequisites
+
+- Node.js installed (for `node ... install/upgrade`)
+- Git installed
+
 1. **Run installer**
    This will clone/update the central repo at `~/.superpowers` and link it into Codex at `~/.codex/superpowers`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Installation
1. **Clone superpowers repository**:
1. **Run installer**
This will clone/update the central repo at `~/.superpowers` and link it into Codex at `~/.codex/superpowers`.
If this is your first install (and `~/.superpowers` does not exist yet), run from a temporary clone:
```bash
mkdir -p ~/.codex/superpowers
cd ~/.codex/superpowers
git clone https://github.com/obra/superpowers.git .
git clone https://github.com/obra/superpowers.git /tmp/superpowers
node /tmp/superpowers/.codex/superpowers-codex install
```
2. **Create personal skills directory**:
If you already have `~/.superpowers` installed, you can run:
```bash
mkdir -p ~/.codex/skills
node ~/.superpowers/.codex/superpowers-codex upgrade
```
## Installation
## Prerequisites
- Node.js installed (for `node ... install/upgrade`)
- Git installed
1. **Run installer**
This will clone/update the central repo at `~/.superpowers` and link it into Codex at `~/.codex/superpowers`.
If this is your first install (and `~/.superpowers` does not exist yet), run from a temporary clone:
🤖 Prompt for AI Agents
In @.codex/INSTALL.md around lines 5 - 20, Add a "Prerequisites" section at the
top of .codex/INSTALL.md that explicitly lists Node.js (specify a minimum
version, e.g., Node 14+ or current LTS) and Git as required before running the
installer, and include brief instructions for verifying them (e.g., run node
--version and git --version) plus links or pointers for installing them; update
the Installation text in the existing "Run installer" section to reference this
new Prerequisites section so first-time installs won't fail due to missing
node/git.

Comment on lines +196 to +200
ref: rawArgs.ref || defaults.ref,
dir: path.resolve(expandHome(rawArgs.dir || defaults.dir)),
force: Boolean(rawArgs.force || false),
update: !(rawArgs['no-update'] || false),
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Normalize --no-update string values.

--no-update=false currently disables updates because the string "false" is truthy. Consider normalizing string booleans.

🧹 Suggested fix: normalize boolean args
 function resolveInstallConfig(rawArgs) {
   const defaults = getDefaults();
@@
   return {
@@
-    update: !(rawArgs['no-update'] || false),
+    update: !(
+      rawArgs['no-update'] === true ||
+      rawArgs['no-update'] === 'true'
+    ),
   };
 }
🤖 Prompt for AI Agents
In `@lib/installer-core.js` around lines 196 - 200, The update flag is incorrectly
computed because rawArgs['no-update'] can be the string "false" (truthy); modify
the logic that sets update (where rawArgs and defaults are assembled,
referencing rawArgs and the update property) to normalize string booleans first
(e.g., coerce "true"/"false" to actual booleans or add a small helper like
parseBoolean to handle strings, undefined, and actual booleans) and then compute
update as !(normalizedNoUpdate || false) so that --no-update=false yields
update=true.

Comment on lines +323 to +325
gitCheckoutRef({ repoDir: config.dir, ref: config.ref });
if (config.update) gitFastForwardUpdate({ repoDir: config.dir });

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Check file exists and get basic info
if [ -f "lib/installer-core.js" ]; then
  wc -l lib/installer-core.js
  echo "---"
  # Read lines around 323-325
  sed -n '310,340p' lib/installer-core.js | cat -n
fi

Repository: obra/superpowers

Length of output: 1297


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Search for gitFastForwardUpdate function
rg -n "function gitFastForwardUpdate|const gitFastForwardUpdate" lib/installer-core.js
echo "---"
# Search for resolveInstallConfig function
rg -n "function resolveInstallConfig|const resolveInstallConfig" lib/installer-core.js
echo "---"
# Search for gitCheckoutRef function
rg -n "function gitCheckoutRef|const gitCheckoutRef" lib/installer-core.js

Repository: obra/superpowers

Length of output: 209


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Read gitCheckoutRef and gitFastForwardUpdate implementations
sed -n '128,145p' lib/installer-core.js | cat -n
echo "---"
# Read resolveInstallConfig implementation
sed -n '187,210p' lib/installer-core.js | cat -n

Repository: obra/superpowers

Length of output: 1563


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Look for the run() function and how it works
rg -n "function run\(" lib/installer-core.js -A 10 | head -30
echo "---"
# Check how args are parsed/normalized
rg -n "process.argv\|parseArg\|rawArgs" lib/installer-core.js | head -20

Repository: obra/superpowers

Length of output: 304


🌐 Web query:

git pull --ff-only detached HEAD error

💡 Result:

When you’re in a detached HEAD state (git status shows HEAD detached at ...), git pull often fails because there’s no current branch for Git to update/merge into, so it may say:

  • You are not currently on a branch. Please specify which branch you want to merge withgit pull <remote> <branch>” [2][3]

And if you (or your config) use --ff-only, it can also fail with:

  • fatal: Not possible to fast-forward, aborting” when your local history can’t be fast-forwarded to the remote (diverged / would require a merge commit) [1][4].

Fix (most common)

  1. Switch back to the branch you meant to update, then pull:
git switch main        # or your branch name
git pull --ff-only

Detached-HEAD pull failures are resolved by re-attaching HEAD to a branch first. [2][3]

If you need to keep work you did while detached

Create a branch at the detached commit, then proceed normally:

git switch -c my-work
git pull --ff-only

(or later merge/cherry-pick into your target branch). [2]

If --ff-only is what’s blocking you

Your branches have diverged; choose one:

  • Rebase your local commits onto the pulled changes:
    git pull --rebase
    [5]
  • Or allow a merge (not fast-forward-only):
    git pull --no-ff
    [4]

If you paste the exact error text and git status output, I can tell you which of the above applies.

Sources: [1] [2] [3] [4] [5]


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Find where rawArgs comes from and how it's constructed
rg -n "runInstallOrUpgrade\(" lib/installer-core.js -B 5 -A 2 | head -40
echo "---"
# Search for main function or entry point
rg -n "function main\|process\.argv" lib/installer-core.js | head -20

Repository: obra/superpowers

Length of output: 505


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Look at the full file to understand arg flow
head -50 lib/installer-core.js | cat -n
echo "---"
# Search for where runInstall/runUpgrade is called
rg -n "runInstall\(|runUpgrade\(" lib/installer-core.js

Repository: obra/superpowers

Length of output: 1549


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Search for exports and main entry point
tail -30 lib/installer-core.js | cat -n

Repository: obra/superpowers

Length of output: 939


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Find parseArgs function
rg -n "function parseArgs" lib/installer-core.js -A 20

Repository: obra/superpowers

Length of output: 619


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Get the rest of parseArgs function
rg -n "function parseArgs" lib/installer-core.js -A 35

Repository: obra/superpowers

Length of output: 934


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Look for any tests related to install/upgrade
find . -name "*.test.js" -o -name "*.spec.js" -o -name "*test*" -type f 2>/dev/null | grep -E "(test|spec)" | head -10
echo "---"
# Check if there's documentation
find . -name "README*" -o -name "*.md" -type f 2>/dev/null | head -10

Repository: obra/superpowers

Length of output: 767


🏁 Script executed:

cd "$REPO_ROOT" 2>/dev/null || true
# Verify the git command syntax in the suggestion
# Check what git rev-parse --abbrev-ref HEAD returns in different states
echo "Testing git rev-parse behavior documentation..."
# Just confirm the file structure looks good for the fix
sed -n '128,145p' lib/installer-core.js

Repository: obra/superpowers

Length of output: 705


Skip git pull when checkout is detached.

If --ref is a tag, commit hash, or remote branch (e.g., origin/main), git checkout leaves you on a detached HEAD, and git pull --ff-only fails with "You are not currently on a branch". This causes install/upgrade to error even though the repo is clean.

🔧 Suggested fix: detect detached HEAD before pulling
+function gitCurrentBranch(repoDir) {
+  const r = run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: repoDir });
+  if (r.status !== 0) {
+    throw new Error(r.stderr.trim() || 'git rev-parse failed');
+  }
+  return r.stdout.trim();
+}
+
 function runInstallOrUpgrade(ide, args, mode) {
   const config = resolveInstallConfig(args);
@@
   gitCheckoutRef({ repoDir: config.dir, ref: config.ref });
-  if (config.update) gitFastForwardUpdate({ repoDir: config.dir });
+  if (config.update) {
+    const branch = gitCurrentBranch(config.dir);
+    if (branch !== 'HEAD') {
+      gitFastForwardUpdate({ repoDir: config.dir });
+    } else {
+      run('git', ['fetch', '--all', '--prune'], { cwd: config.dir });
+    }
+  }
🤖 Prompt for AI Agents
In `@lib/installer-core.js` around lines 323 - 325, The code calls
gitFastForwardUpdate unconditionally after gitCheckoutRef which can fail if the
checkout left a detached HEAD; modify the flow in installer-core.js to detect
whether the repo is on a detached HEAD before attempting to fast-forward: after
gitCheckoutRef({ repoDir: config.dir, ref: config.ref }) and only if
config.update is true, run a check (e.g., run git rev-parse --abbrev-ref HEAD or
use a new helper isDetachedHead(repoDir)) and skip calling
gitFastForwardUpdate({ repoDir: config.dir }) when detached; alternatively, add
an isDetached flag return from gitCheckoutRef and use it to conditionally skip
gitFastForwardUpdate.

@obra obra added codex Issues related to OpenAI Codex support opencode enhancement New feature or request documentation Improvements or additions to documentation labels Feb 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex Issues related to OpenAI Codex support documentation Improvements or additions to documentation enhancement New feature or request opencode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants