Files
oh-my-claudecode/scripts/find-node.sh
Pedro Rodrigues b8948f6d3c fix: respect CLAUDE_CONFIG_DIR across remaining code paths
Several code paths hardcoded ~/.claude instead of resolving the active config directory. Introduce
getClaudeConfigDir() as a shared helper (with ESM/CJS/shell mirrors in scripts/lib/) and update
all call sites:

- transcript validation: allow paths under the active config directory
- transcript fallback resolution: build projects/ lookups from the active config directory instead
  of inline env-var fallback
- rules discovery: use getClaudeConfigDir() instead of hardcoded path
- rules injector: remove dead homeDir parameter from findRuleFiles and USER_RULE_DIR export;
  breaking change to the public surface (no npm dependents)
- uninstall: preserve existing CLAUDE_CONFIG_DIR env var
- CLI: use getClaudeConfigDir() for runtime paths and config directory descriptions
  (default: ~/.claude/)
- orchestrator: allow absolute paths under the active config directory while preserving
  project-root and relative-path checks
- skills tools: reference the active config directory in runtime output and help text
- shared memory: read .omc-config.json from the active config directory
- session history search: resolve transcript roots from the active config directory
- auto-slash-command executor: replace hardcoded ~/.claude in error message output
- factcheck guard: add ${CLAUDE_CONFIG_DIR} token to forbidden_path_prefixes defaults and token
  expander, replacing the hardcoded ${HOME}/.claude prefix
- config-dir helper: implement full getClaudeConfigDir() in config-dir.ts with tilde expansion
  and trailing-slash normalization, replacing the trivial getConfigDir() wrapper and the re-export
  from paths.ts
- runtime Node scripts: use shared config-dir helpers (ESM and CJS) instead of repeating
  ~/.claude fallbacks
- standalone hook templates: add templates/hooks/lib/config-dir.mjs shared helper (mirrors
  scripts/lib/config-dir.mjs) so template scripts resolve the config directory consistently
- HUD wrapper: import the shared lib/config-dir helper instead of embedding duplicate
  config-directory resolution logic
- persistent-mode scripts: resolve native tasks/todos from [$CLAUDE_CONFIG_DIR|~/.claude]
- shell scripts: use a shared config-dir.sh helper with ~ expansion and trailing-slash
  normalization
- installer: copy config-dir helpers alongside standalone hooks and the HUD find-node.sh helper
- plugin setup: move nodeBin to module scope so both settings.json and hooks.json patching blocks
  can access it (pre-existing const scoping bug where hooks.json patch always failed silently)
- skill snippets: replace $HOME/.claude with ${CLAUDE_CONFIG_DIR:-$HOME/.claude} in executable
  shell snippets across 8 skill files
- skill prose instructions: replace hardcoded ~/.claude in LLM-actionable directives (Read/Write
  tool targets, bash code blocks, path references in step instructions) across 9 skill files so
  an LLM executing the skill resolves the active config directory
- HUD usage API: document and test that Keychain service names hash the exact CLAUDE_CONFIG_DIR
  string, preserving distinct service-name mapping for ~-prefixed vs expanded inputs
- test files: align mock paths from paths.js to config-dir.js; fix vi.mock hoisting in
  doctor-conflicts.test.ts; resolve macOS /var symlink mismatch in bridge-integration,
  team-status, and edge-cases tests; update string-pattern assertions in hud-windows.test.ts
  and mingw-escape.test.ts
- test script: source lib/config-dir.sh in scripts/test-pr25.sh for post-install path
  verification

Adds focused regression coverage in:

- src/__tests__/auto-update.test.ts
- src/__tests__/cli-config-stop-callback.test.ts
- src/__tests__/config-dir.test.ts
- src/__tests__/delegation-enforcement-levels.test.ts
- src/__tests__/doctor-conflicts.test.ts
- src/__tests__/hud-api-key-source.test.ts
- src/__tests__/hud-marketplace-resolution.test.ts
- src/__tests__/hud-windows.test.ts
- src/__tests__/hud/cli-diagnostic.test.ts
- src/__tests__/hud/usage-api-lock.test.ts
- src/__tests__/hud/usage-api-stale.test.ts
- src/__tests__/hud/usage-api.test.ts
- src/__tests__/installer.test.ts
- src/__tests__/purge-stale-cache.test.ts
- src/__tests__/session-history-search.test.ts
- src/__tests__/setup-claude-md-script.test.ts
- src/__tests__/shared-memory.test.ts
- src/hooks/factcheck/__tests__/factcheck.test.ts
- src/installer/__tests__/standalone-hook-reconcile.test.ts
- src/notifications/__tests__/config-merge.test.ts
- src/notifications/__tests__/profiles.test.ts
- src/openclaw/__tests__/config.test.ts
- src/skills/__tests__/mingw-escape.test.ts
- src/team/__tests__/bridge-integration.test.ts
- src/team/__tests__/edge-cases.test.ts
- src/team/__tests__/inbox-outbox.test.ts
- src/team/__tests__/message-router.test.ts
- src/team/__tests__/outbox-reader.test.ts
- src/team/__tests__/team-registration.test.ts
- src/team/__tests__/team-status.test.ts
2026-04-04 19:40:17 +01:00

103 lines
3.5 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=""
case "$0" in
*/*)
SCRIPT_DIR="${0%/*}"
;;
*)
SCRIPT_DIR='.'
;;
esac
SCRIPT_DIR="$(cd "$SCRIPT_DIR" && pwd)"
. "$SCRIPT_DIR/lib/config-dir.sh"
# ---------------------------------------------------------------------------
# 1. Read stored node path from OMC config
# ---------------------------------------------------------------------------
CLAUDE_DIR="$(resolve_claude_config_dir)"
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" "$@"