From bece102900a9b0855c5a5323aa80b20a9f027a80 Mon Sep 17 00:00:00 2001 From: Dongni Yang Date: Thu, 9 Apr 2026 10:42:59 +0800 Subject: [PATCH] fix(install): detect and remove broken npm placeholder package (#506) Signed-off-by: Dongni Yang Co-Authored-By: Claude Opus 4.6 (1M context) --- .../references/commands.md | 3 +- docs/reference/commands.md | 3 +- scripts/install.sh | 63 +++++++++++++------ test/install-preflight.test.js | 43 +++++++++---- test/runner.test.js | 2 +- 5 files changed, 80 insertions(+), 34 deletions(-) diff --git a/.agents/skills/nemoclaw-user-reference/references/commands.md b/.agents/skills/nemoclaw-user-reference/references/commands.md index 814cd8326..c3cd99ef0 100644 --- a/.agents/skills/nemoclaw-user-reference/references/commands.md +++ b/.agents/skills/nemoclaw-user-reference/references/commands.md @@ -1,6 +1,7 @@ # Commands -The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. It is installed when you run `npm install -g nemoclaw`. +The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. +It is installed automatically by the installer (`curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash`). ## `/nemoclaw` Slash Command diff --git a/docs/reference/commands.md b/docs/reference/commands.md index aafde7699..e4442d9fb 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -22,7 +22,8 @@ status: published # Commands -The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. It is installed when you run `npm install -g nemoclaw`. +The `nemoclaw` CLI is the primary interface for managing NemoClaw sandboxes. +It is installed automatically by the installer (`curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash`). ## `/nemoclaw` Slash Command diff --git a/scripts/install.sh b/scripts/install.sh index 9bba08793..16d2737c8 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -898,39 +898,62 @@ install_nemoclaw() { # --------------------------------------------------------------------------- # 4. Verify # --------------------------------------------------------------------------- + +# Verify that a nemoclaw binary is the real NemoClaw CLI and not the broken +# placeholder npm package (npmjs.org/nemoclaw 0.1.0 — 249 bytes, no build +# artifacts). The real CLI prints "nemoclaw v" on --version. +# Mirrors the isOpenshellCLI() pattern from resolve-openshell.js (PR #970). +is_real_nemoclaw_cli() { + local bin_path="${1:-nemoclaw}" + local version_output + version_output="$("$bin_path" --version 2>/dev/null)" || return 1 + # Real CLI outputs: "nemoclaw v0.1.0" (or any semver, with optional pre-release) + [[ "$version_output" =~ ^nemoclaw[[:space:]]+v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] +} + verify_nemoclaw() { if command_exists nemoclaw; then - NEMOCLAW_READY_NOW=true - ensure_nemoclaw_shim || true - info "Verified: nemoclaw is available at $(command -v nemoclaw)" - return 0 + if is_real_nemoclaw_cli "$(command -v nemoclaw)"; then + NEMOCLAW_READY_NOW=true + ensure_nemoclaw_shim || true + info "Verified: nemoclaw is available at $(command -v nemoclaw)" + return 0 + else + warn "Found nemoclaw at $(command -v nemoclaw) but it is not the real NemoClaw CLI." + warn "This is likely the broken placeholder npm package." + npm uninstall -g nemoclaw 2>/dev/null || true + fi fi local npm_bin npm_bin="$(npm config get prefix 2>/dev/null)/bin" || true if [[ -n "$npm_bin" && -x "$npm_bin/nemoclaw" ]]; then - ensure_nemoclaw_shim || true - if command_exists nemoclaw; then - NEMOCLAW_READY_NOW=true - info "Verified: nemoclaw is available at $(command -v nemoclaw)" - return 0 - fi + if is_real_nemoclaw_cli "$npm_bin/nemoclaw"; then + ensure_nemoclaw_shim || true + if command_exists nemoclaw; then + NEMOCLAW_READY_NOW=true + info "Verified: nemoclaw is available at $(command -v nemoclaw)" + return 0 + fi - NEMOCLAW_RECOVERY_PROFILE="$(detect_shell_profile)" - if [[ -x "$NEMOCLAW_SHIM_DIR/nemoclaw" ]]; then - NEMOCLAW_RECOVERY_EXPORT_DIR="$NEMOCLAW_SHIM_DIR" + NEMOCLAW_RECOVERY_PROFILE="$(detect_shell_profile)" + if [[ -x "$NEMOCLAW_SHIM_DIR/nemoclaw" ]]; then + NEMOCLAW_RECOVERY_EXPORT_DIR="$NEMOCLAW_SHIM_DIR" + else + NEMOCLAW_RECOVERY_EXPORT_DIR="$npm_bin" + fi + warn "Found nemoclaw at $npm_bin/nemoclaw but this shell still cannot resolve it." + warn "Onboarding will be skipped until PATH is updated." + return 0 else - NEMOCLAW_RECOVERY_EXPORT_DIR="$npm_bin" + warn "Found nemoclaw at $npm_bin/nemoclaw but it is not the real NemoClaw CLI." + npm uninstall -g nemoclaw 2>/dev/null || true fi - warn "Found nemoclaw at $npm_bin/nemoclaw but this shell still cannot resolve it." - warn "Onboarding will be skipped until PATH is updated." - return 0 - else - warn "Could not locate the nemoclaw executable." - warn "Try running: npm install -g git+https://github.com/NVIDIA/NemoClaw.git" fi + warn "Could not locate the nemoclaw executable." + warn "Try re-running: curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash" error "Installation failed: nemoclaw binary not found." } diff --git a/test/install-preflight.test.js b/test/install-preflight.test.js index 14f1b4cb1..b6cc575fe 100644 --- a/test/install-preflight.test.js +++ b/test/install-preflight.test.js @@ -177,6 +177,9 @@ fi if [ "$1" = "run" ]; then exit 0 fi +if [ "$1" = "uninstall" ]; then + exit 0 +fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash @@ -184,7 +187,7 @@ if [ "$1" = "onboard" ]; then exit 0 fi if [ "$1" = "--version" ]; then - echo "v0.1.0-test" + echo "nemoclaw v0.1.0-test" exit 0 fi exit 0 @@ -277,6 +280,9 @@ fi if [ "$1" = "run" ]; then exit 0 fi +if [ "$1" = "uninstall" ]; then + exit 0 +fi if [ "$1" = "link" ]; then exit 0 fi @@ -300,7 +306,7 @@ exit 98 const output = `${result.stdout}${result.stderr}`; expect(result.status).not.toBe(0); - expect(output).toMatch(new RegExp(GITHUB_INSTALL_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))); + expect(output).toMatch(/curl -fsSL https:\/\/www\.nvidia\.com\/nemoclaw\.sh \| bash/); expect(output).not.toMatch(/npm install -g nemoclaw/); }); @@ -427,7 +433,8 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "onboard" ] || [ "$1" = "--version" ]; then exit 0; fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi +if [ "$1" = "onboard" ]; then exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" @@ -518,6 +525,7 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi printf '%s\\n' "$*" >> "$NEMOCLAW_ONBOARD_LOG" exit 0 EOS @@ -612,6 +620,7 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi printf '%s\\n' "$*" >> "$NEMOCLAW_ONBOARD_LOG" exit 0 EOS @@ -674,6 +683,7 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi printf '%s\\n' "$*" >> "$NEMOCLAW_ONBOARD_LOG" exit 0 EOS @@ -760,6 +770,7 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi printf '%s\\n' "$*" >> "$NEMOCLAW_ONBOARD_LOG" exit 0 EOS @@ -830,6 +841,7 @@ if [ "$1" = "run" ] && { [ "$2" = "build" ] || [ "$2" = "build:cli" ] || [ "$2" if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi printf '%s\\n' "$*" >> "$NEMOCLAW_ONBOARD_LOG" exit 0 EOS @@ -976,6 +988,9 @@ fi if [ "$1" = "run" ]; then exit 0 fi +if [ "$1" = "uninstall" ]; then + exit 0 +fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash @@ -983,7 +998,7 @@ if [ "$1" = "onboard" ]; then exit 0 fi if [ "$1" = "--version" ]; then - echo "v0.1.0-test" + echo "nemoclaw v0.1.0-test" exit 0 fi exit 0 @@ -1103,12 +1118,14 @@ fi if [ "$1" = "run" ]; then exit 0 fi +if [ "$1" = "uninstall" ]; then + exit 0 +fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "onboard" ] || [ "$1" = "--version" ]; then - exit 0 -fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi +if [ "$1" = "onboard" ]; then exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" @@ -1200,7 +1217,8 @@ if [ "$1" = "install" ] || [ "$1" = "run" ]; then exit 0; fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "onboard" ] || [ "$1" = "--version" ]; then exit 0; fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi +if [ "$1" = "onboard" ]; then exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" @@ -1317,7 +1335,8 @@ if [ "$1" = "install" ] || [ "$1" = "run" ]; then exit 0; fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "onboard" ] || [ "$1" = "--version" ]; then exit 0; fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi +if [ "$1" = "onboard" ]; then exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" @@ -1422,7 +1441,8 @@ if [ "$1" = "install" ] || [ "$1" = "run" ]; then exit 0; fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "onboard" ] || [ "$1" = "--version" ]; then exit 0; fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.1.0-test"; exit 0; fi +if [ "$1" = "onboard" ]; then exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" @@ -1892,10 +1912,11 @@ if [ "$1" = "config" ] && [ "$2" = "get" ] && [ "$3" = "prefix" ]; then echo "$N if [ "$1" = "pack" ]; then exit 1; fi if [ "$1" = "install" ] && [[ "$*" == *"--ignore-scripts"* ]]; then exit 0; fi if [ "$1" = "run" ]; then exit 0; fi +if [ "$1" = "uninstall" ]; then exit 0; fi if [ "$1" = "link" ]; then cat > "$NPM_PREFIX/bin/nemoclaw" <<'EOS' #!/usr/bin/env bash -if [ "$1" = "--version" ]; then echo "v0.5.0-test"; exit 0; fi +if [ "$1" = "--version" ]; then echo "nemoclaw v0.5.0-test"; exit 0; fi exit 0 EOS chmod +x "$NPM_PREFIX/bin/nemoclaw" diff --git a/test/runner.test.js b/test/runner.test.js index eb9519fd5..42a758a5b 100644 --- a/test/runner.test.js +++ b/test/runner.test.js @@ -604,7 +604,7 @@ describe("regression guards", () => { const normalized = normalize(src, "#"); return normalized.split("\n").filter((line) => { const t = line.trim(); - if (t.startsWith("printf") || t.startsWith("echo")) return false; + if (t.startsWith("printf") || t.startsWith("echo") || t.startsWith("warn")) return false; return shellViolationRe.test(t); }); };