Skip to content

fix: resolve Node outside minimal hook PATH - #737

Open
fscfede-beep wants to merge 13 commits into
openai:mainfrom
fscfede-beep:fix/portable-node-launcher-105
Open

fscfede-beep wants to merge 13 commits into
openai:mainfrom
fscfede-beep:fix/portable-node-launcher-105

Conversation

@fscfede-beep

@fscfede-beep fscfede-beep commented Sep 5, 2026

Copy link
Copy Markdown

Summary

Fixes #105.

Claude Code hooks and deterministic !-pattern commands can run with a minimal shell PATH that does not expose a normally installed Node or Codex executable. This PR adds a portable POSIX launcher and routes the affected plugin surfaces through it.

The current branch covers the compatibility issues found during review:

  • validates every candidate against Node >=18.18;
  • preserves the selected toolchain directory on PATH;
  • routes /codex:transfer through the same portable launcher as the other deterministic commands;
  • discovers standard Windows / Git Bash installs via Program Files, NVM_SYMLINK, VOLTA_HOME, and LOCALAPPDATA;
  • restores custom npm global locations through NPM_CONFIG_PREFIX or npm prefix -g;
  • honors and normalizes custom NVM_DIR, FNM_DIR, ASDF_DATA_DIR, and MISE_DATA_DIR roots for both Node discovery and PATH enrichment;
  • honors normalized HOMEBREW_PREFIX and the standard Linuxbrew /home/linuxbrew/.linuxbrew prefix, in addition to macOS/Homebrew fallback locations;
  • prefers a supported managed Node whose directory contains the Codex shim when the incoming PATH would otherwise split Node and Codex across different toolchains;
  • normalizes an explicit native-Windows CODEX_COMPANION_NODE before returning it, so downstream directory derivation exposes the selected toolchain's adjacent npm/Codex executables instead of falling back to .;
  • isolates launcher tests from inherited version-manager / Windows installation-root variables case-insensitively.

Validation

Fresh validation on Windows 11 / Git Bash at head e116d57b1d5fa61a3bfa02ab6aa9595335b84416:

  • commands / launcher / process / state: 28 passed, 0 failed;
  • SessionStart / SessionEnd focal lifecycle tests: 2 passed, 0 failed;
  • custom ASDF_DATA_DIR / MISE_DATA_DIR regression: RED before fix, GREEN after;
  • native-Windows configured-Node PATH propagation regression: RED before fix (PATH fell back to .), GREEN after;
  • HOMEBREW_PREFIX regression: RED before fix with exit 127, GREEN after;
  • bash -n plugins/codex/scripts/run-node.sh: PASS;
  • hooks JSON parse: PASS;
  • git diff --check: PASS.

Upstream Pull Request CI is checked per head. If GitHub reports action_required with zero jobs, that is treated as an external workflow-approval/action gate, not a CI test failure.

Current scope

The implementation remains limited to launcher/routing compatibility and regression coverage; it does not alter Codex task/review semantics.

@fscfede-beep
fscfede-beep requested a review from a team September 5, 2026 01:26

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f09814f4b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh
Comment thread plugins/codex/scripts/run-node.sh

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a17c3dafe4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cc0ffadc0e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

There is a version-manager edge here when node is absent from PATH and several nvm/fnm/asdf/mise installations exist. The glob loop selects the first supported executable in lexical path order, not the version manager's active/default runtime. That selected directory is then prepended to PATH, so a codex shim found later in another installation can still resolve #!/usr/bin/env node to the earlier, unrelated Node version. A machine with nvm v20 and v24 installed can therefore run the companion and Codex under a different runtime than the user's configured default. Resolving the manager's default/current alias first, or selecting the highest supported semantic version, would avoid that mismatch. A regression with two supported nvm installs and codex present only in the newer one would make the behavior explicit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef58bf1597

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/commands.test.mjs Outdated
Comment thread plugins/codex/scripts/run-node.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1338edef04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6855f3992

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/node-launcher.test.mjs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64dcef9272

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a420fc0dfb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated

Copy link
Copy Markdown
Author

Review reconciliation update for the multi-version/toolchain concern: addressed in 64dcef9 and subsequently extended through 0ef6b73. The launcher now prefers a supported managed Node whose directory contains the Codex shim when the incoming PATH would otherwise split Node and Codex across toolchains. The two-supported-nvm regression (v20 + v24, Codex only beside v24) was RED before the fix and GREEN after it. Custom NVM_DIR and FNM_DIR are also normalized and used for discovery/PATH enrichment. Fresh validation on current head 0ef6b73: commands/launcher/process/state 26/26 PASS; lifecycle focal 2/2 PASS; shell/JSON/diff checks PASS. Upstream PR CI remains an external action_required gate with 0 jobs created.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ef6b735bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated
Comment thread plugins/codex/scripts/run-node.sh

Copy link
Copy Markdown
Author

@codex review

Please re-review current head 11007e405a86415407f208879324f5960868f2a2. The two findings from the prior 0ef6b73 review were addressed with RED→GREEN regressions: custom ASDF_DATA_DIR / MISE_DATA_DIR discovery+PATH enrichment, and normalization of explicit native-Windows CODEX_COMPANION_NODE before selected-directory derivation. Fresh exact-head validation: commands/launcher/process/state 27/27 PASS; SessionStart/SessionEnd 2/2 PASS; bash -n, hooks JSON parse, and git diff --check PASS. Upstream CI remains action_required with 0 jobs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11007e405a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/run-node.sh Outdated

Copy link
Copy Markdown
Author

@codex review

Current head e116d57 addresses the Linuxbrew/Homebrew prefix finding with a RED→GREEN HOMEBREW_PREFIX regression and standard /home/linuxbrew/.linuxbrew fallback. Fresh local validation: commands/launcher/process/state 28/28 PASS; SessionStart/SessionEnd 2/2 PASS; bash -n, hooks JSON parse, and git diff --check PASS. Please review the current head.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: e116d57b1d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

fscfede-beep commented Sep 6, 2026

Copy link
Copy Markdown
Author

@openai/developer-experience — contributor-side work on this PR is complete at exact head e116d57b1d5fa61a3bfa02ab6aa9595335b84416: the known review findings are resolved and current-head local validation is documented in the PR body. I verified that the active Main ruleset requires at least one formal approval from the Developer Experience team for *. The repository's classic required-status-check protection is currently off; Actions is still action_required with 0 jobs, so CI has not executed, but I am not representing that as a proven merge requirement here. When convenient, could someone from Developer Experience review the current head? No maintainer approval or CI result is being claimed yet.

Edo771977 pushed a commit to Edo771977/codex-plugin-cc that referenced this pull request Sep 17, 2026
Upstream PR openai#737 (fscfede-beep), one conflict resolved.

Hooks ran `node` directly, so a Node installed through nvm, fnm, asdf, mise,
Volta or Homebrew was invisible under the minimal PATH hooks get, and the
plugin looked broken for anyone who does not have a system-wide node. The
hooks and the node-invoking commands now go through scripts/run-node.sh,
which finds a supported (>=18.18) toolchain, prefers one that ships codex
next to it, and restores the npm global prefix.

Conflict: plugins/codex/hooks/hooks.json, SessionEnd. The launcher command
is taken from the PR; the timeout stays at this fork's 30s rather than
reverting to upstream's 5s, since the bounded teardown imported earlier needs
it.

One fix beyond the PR: find_managed_node() listed /home/linuxbrew,
/opt/homebrew, /usr/local/bin and /opt/local/bin BEFORE the version-manager
roots, so on any machine carrying /usr/local/bin/node (Debian and Ubuntu
packages, CI images, this repo's own container) the system install shadowed
every managed toolchain — the precise failure the PR set out to fix. Four of
its own tests caught it here and passed only where no system node exists.
The managed roots now come first; HOMEBREW_PREFIX keeps its place ahead of
them because it is configured rather than guessed.

Verified: bash -n on run-node.sh; the new tests/node-launcher.test.mjs 14/14;
full npm test 254/254; npm run check-version passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXfvnjSC72HsM6EEPVt2Tg
Edo771977 pushed a commit to Edo771977/codex-plugin-cc that referenced this pull request Sep 17, 2026
Adds openai#731, openai#737, openai#747 and openai#763 to "Differences From Upstream", and notes in
Requirements that Node no longer has to be on the system PATH now that the
hooks go through scripts/run-node.sh (including CODEX_COMPANION_NODE for
pinning one).

Verified: full npm test 254/254.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXfvnjSC72HsM6EEPVt2Tg
@Edo771977

Copy link
Copy Markdown

Tried this out on a fork and hit something the PR's own tests catch: find_managed_node() searches the hardcoded system locations before the version-manager roots, so on any machine that has /usr/local/bin/node the system install shadows every nvm/fnm/asdf/mise toolchain — which is the situation the launcher exists to fix.
The candidate list is:

for candidate in \
  "$homebrew_node" /home/linuxbrew/.linuxbrew/bin/node /opt/homebrew/bin/node /usr/local/bin/node /opt/local/bin/node \
  "$home/.volta/bin/node" \
  "$nvm_dir"/versions/node/*/bin/node \
  ...

/usr/local/bin/node exists on Debian/Ubuntu Node packages, on GitHub's ubuntu runner images, and in plenty of dev containers. Where it does, find_managed_node returns it before ever globbing $nvm_dir, $fnm_dir, $asdf_dir or $mise_dir.
Four of this PR's tests fail because of it, on a box where /usr/local/bin/node is a supported version:
portable launcher discovers Node from a custom NVM_DIR
portable launcher discovers Node from a custom FNM_DIR
portable launcher honors custom ASDF_DATA_DIR and MISE_DATA_DIR
portable launcher skips unsupported Node versions
They pass only where no system node is installed. The failure looks like this — the fake managed node is ignored and the real one runs instead:

Error: Cannot find module '<plugin>/scripts/companion.mjs'
Node.js v20.20.2          # /usr/local/bin/node, not the fake node under the temp HOME
1 !== 0

Worth noting why those four and not the rest: the first pass runs with require_codex=true, and the tests that install a codex next to their fake node pass because that pass rejects the system node. The four above install no codex, so they fall through to the second pass, where list order decides.
Reordering fixes all four, with no other test affected:

   for candidate in \
-    "$homebrew_node" /home/linuxbrew/.linuxbrew/bin/node /opt/homebrew/bin/node /usr/local/bin/node /opt/local/bin/node \
+    "$homebrew_node" \
     "$home/.volta/bin/node" \
     "$nvm_dir"/versions/node/*/bin/node \
     "$fnm_dir"/node-versions/*/installation/bin/node \
     "$asdf_dir"/installs/nodejs/*/bin/node \
-    "$mise_dir"/installs/node/*/bin/node; do
+    "$mise_dir"/installs/node/*/bin/node \
+    /home/linuxbrew/.linuxbrew/bin/node /opt/homebrew/bin/node /usr/local/bin/node /opt/local/bin/node; do

$homebrew_node stays first because it comes from HOMEBREW_PREFIX, i.e. something the user configured rather than a guess — portable launcher honors HOMEBREW_PREFIX under a minimal PATH still passes. With this, the launcher's 14 tests are green on a machine that has a system node.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rechecked current e116d57b. The fallback still selects managed Node installations in a fixed filesystem order rather than resolving the active version manager/runtime. With more than one manager installed and a minimal hook PATH, find_managed_node can choose Homebrew/Volta/nvm/asdf/mise based on this hard-coded order rather than the project/user-selected runtime, changing the Node version used by the hook. Please make the fallback honor the active manager/version (or an explicit configured Node) and add a multi-manager regression that proves the selected runtime is preserved.

Edo771977 pushed a commit to Edo771977/codex-plugin-cc that referenced this pull request Sep 17, 2026
The review on openai#737 asks for a multi-manager regression
alongside the ordering fix. Two tests, with every manager root populated at
once (nvm, fnm, asdf, mise):

- "prefers a managed toolchain over a system install with several managers
  present" is the regression for the precedence bug itself. It discriminates
  where a system node exists: putting /usr/local/bin and the Homebrew paths
  back ahead of the manager roots fails it, along with the four upstream tests
  that caught the bug originally. It deliberately does not pin *which* manager
  wins — the launcher cannot tell which one the project or user selected, since
  it reads no .nvmrc, .tool-versions or mise config, so asserting one would
  freeze an arbitrary order as if it were a guarantee.
- "lets CODEX_COMPANION_NODE override every installed manager" pins the one
  way a specific runtime can be selected today, which is the honest answer to
  the reviewer's "preserve the selected runtime" until the launcher learns to
  read the active manager.

Verified: the first test fails with the pre-fix ordering restored and passes
with it in place; full npm test 304/304; tsc clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXfvnjSC72HsM6EEPVt2Tg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex plugin commands fail with command not found: node on Mac App

3 participants