mirror of
https://github.com/Yeachan-Heo/oh-my-claudecode.git
synced 2026-09-03 06:25:33 +08:00
Node.js hooks fail silently for nvm/fnm users because claude Code invokes
hook commands in a non-interactive shell that does not source ~/.bashrc or
~/.zshrc, so bare `node` is not on PATH.
Changes:
- Add src/utils/resolve-node.ts with resolveNodeBinary() that probes
process.execPath → which node → nvm paths → fnm paths → system paths
and returns an absolute path (never bare 'node' when avoidable).
- Add scripts/find-node.sh, a POSIX shell wrapper that reads the stored
nodeBinary from ~/.claude/.omc-config.json then falls back through the
same priority chain; exits 0 on failure so hooks never block Claude Code.
- Update hooks/hooks.json to invoke all hook scripts via find-node.sh
instead of bare `node`, using sh "${CLAUDE_PLUGIN_ROOT}/scripts/find-node.sh".
- Update installer/index.ts to use resolveNodeBinary() for the HUD
statusLine command and to persist the detected path as nodeBinary in
~/.claude/.omc-config.json for use by find-node.sh at runtime.
- Update scripts/plugin-setup.mjs to use process.execPath for the HUD
statusLine and to persist nodeBinary to .omc-config.json.
- Add nodeBinary?: string field to OMCConfig interface in auto-update.ts.
- Add src/__tests__/resolve-node.test.ts with 10 tests covering
pickLatestVersion() and resolveNodeBinary() (all passing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91 lines
3.4 KiB
Bash
Executable File
91 lines
3.4 KiB
Bash
Executable File
#!/bin/sh
|
|
# OMC Node.js Finder (find-node.sh)
|
|
#
|
|
# Locates the Node.js binary and executes it with the provided arguments.
|
|
# Designed for nvm/fnm users where `node` is not on PATH in non-interactive
|
|
# shells (e.g. Claude Code hook invocations). Fixes issue #892.
|
|
#
|
|
# Priority:
|
|
# 1. nodeBinary stored in ~/.claude/.omc-config.json (set at setup time)
|
|
# 2. `which node` (node is on PATH)
|
|
# 3. nvm versioned paths (~/.nvm/versions/node/*/bin/node)
|
|
# 4. fnm versioned paths (~/.fnm/node-versions/*/installation/bin/node)
|
|
# 5. Homebrew / system paths (/opt/homebrew/bin/node, /usr/local/bin/node)
|
|
#
|
|
# Exits 0 on failure so it never blocks Claude Code hook processing.
|
|
|
|
NODE_BIN=""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Read stored node path from OMC config
|
|
# ---------------------------------------------------------------------------
|
|
CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
CONFIG_FILE="$CLAUDE_DIR/.omc-config.json"
|
|
if [ -f "$CONFIG_FILE" ]; then
|
|
# POSIX-safe extraction without requiring jq
|
|
_stored=$(grep -o '"nodeBinary" *: *"[^"]*"' "$CONFIG_FILE" 2>/dev/null \
|
|
| head -1 \
|
|
| sed 's/.*"nodeBinary" *: *"//;s/".*//')
|
|
if [ -n "$_stored" ] && [ -x "$_stored" ]; then
|
|
NODE_BIN="$_stored"
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. which node
|
|
# ---------------------------------------------------------------------------
|
|
if [ -z "$NODE_BIN" ] && command -v node >/dev/null 2>&1; then
|
|
NODE_BIN="node"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. nvm versioned paths: iterate to find the latest installed version
|
|
# ---------------------------------------------------------------------------
|
|
if [ -z "$NODE_BIN" ] && [ -d "$HOME/.nvm/versions/node" ]; then
|
|
# shellcheck disable=SC2231
|
|
for _path in "$HOME/.nvm/versions/node/"*/bin/node; do
|
|
[ -x "$_path" ] && NODE_BIN="$_path"
|
|
# Keep iterating — later entries tend to be newer (lexicographic order)
|
|
done
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. fnm versioned paths (Linux and macOS default locations)
|
|
# ---------------------------------------------------------------------------
|
|
if [ -z "$NODE_BIN" ]; then
|
|
for _fnm_base in \
|
|
"$HOME/.fnm/node-versions" \
|
|
"$HOME/Library/Application Support/fnm/node-versions" \
|
|
"$HOME/.local/share/fnm/node-versions"; do
|
|
if [ -d "$_fnm_base" ]; then
|
|
# shellcheck disable=SC2231
|
|
for _path in "$_fnm_base/"*/installation/bin/node; do
|
|
[ -x "$_path" ] && NODE_BIN="$_path"
|
|
done
|
|
[ -n "$NODE_BIN" ] && break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Common Homebrew / system paths
|
|
# ---------------------------------------------------------------------------
|
|
if [ -z "$NODE_BIN" ]; then
|
|
for _path in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
|
|
if [ -x "$_path" ]; then
|
|
NODE_BIN="$_path"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Invoke node with all provided arguments
|
|
# ---------------------------------------------------------------------------
|
|
if [ -z "$NODE_BIN" ]; then
|
|
printf '[OMC] Error: Could not find node binary. Run /oh-my-claudecode:omc-setup to fix.\n' >&2
|
|
exit 0 # exit 0 so this hook does not block Claude Code
|
|
fi
|
|
|
|
exec "$NODE_BIN" "$@"
|