From e87f2821298db18e33ea6cea04c705c99716ed05 Mon Sep 17 00:00:00 2001 From: Charan Jagwani Date: Tue, 21 Apr 2026 11:11:21 -0700 Subject: [PATCH 1/2] Revert "fix(ci): move sudo npm link into launchable to unblock non-full Brev E2E (#2186)" This reverts commit ab7f36834c13a1b675905dc97b6f3fa571f51945. --- scripts/brev-launchable-ci-cpu.sh | 11 ----------- test/e2e/brev-e2e.test.ts | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/scripts/brev-launchable-ci-cpu.sh b/scripts/brev-launchable-ci-cpu.sh index 8da9e73936..b8b1340e00 100755 --- a/scripts/brev-launchable-ci-cpu.sh +++ b/scripts/brev-launchable-ci-cpu.sh @@ -249,17 +249,6 @@ npm run build 2>&1 | tail -3 cd "$NEMOCLAW_CLONE_DIR" info "Plugin built" -# Create the global nemoclaw symlink once during setup. This runs here -# (before any test) so the cold-path npm link cost is absorbed by the -# launchable's own readiness window rather than a later test's tight -# execSync timeout. When the test suite rsyncs PR branch code over this -# clone, a subsequent `npm link` is a fast no-op against the existing -# symlink. See PR #1888 regression commentary. -info "Linking nemoclaw CLI globally..." -sudo npm link 2>&1 | tail -3 -sudo chown -R "$TARGET_USER":"$TARGET_USER" "$NEMOCLAW_CLONE_DIR" -info "nemoclaw CLI linked" - # ══════════════════════════════════════════════════════════════════════ # 6. Pre-pull Docker images # ══════════════════════════════════════════════════════════════════════ diff --git a/test/e2e/brev-e2e.test.ts b/test/e2e/brev-e2e.test.ts index f9700e751c..8349aefefb 100644 --- a/test/e2e/brev-e2e.test.ts +++ b/test/e2e/brev-e2e.test.ts @@ -426,9 +426,7 @@ function bootstrapLaunchable(elapsed) { // Install nemoclaw CLI. // Use `sudo npm link` because Node.js is installed system-wide via // nodesource (global prefix is /usr), so creating the global symlink - // requires elevated permissions. The launchable setup script already - // runs this once during its readiness window, so this invocation is a - // fast idempotent no-op against the existing symlink on Brev CPU runs. + // requires elevated permissions. console.log(`[${elapsed()}] Installing nemoclaw CLI (npm link)...`); ssh( `source ~/.nvm/nvm.sh 2>/dev/null || true && cd ${resolvedRemoteDir} && sudo npm link && sudo chown -R $(whoami):$(whoami) ${resolvedRemoteDir}`, From 2eb527430ea76605c55f5990d2b7c16d3bdfa3e8 Mon Sep 17 00:00:00 2001 From: Charan Jagwani Date: Tue, 21 Apr 2026 11:13:42 -0700 Subject: [PATCH 2/2] fix(ci): replace sudo npm link with direct symlink on Brev CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #2186 tried to unblock non-full Brev E2E suites by moving the slow `sudo npm link` step from the test (120s cap) into the launchable setup (20min outer cap). That hit a worse pathology: on cold CPU Brev, `sudo npm link` + `sudo chown -R` on a ~50k-file node_modules tree doesn't complete within 20 minutes at all. Every run now hangs at "Linking nemoclaw CLI globally..." until the outer cap trips — 10× longer to fail and 10× more Brev credit per failed run. The previous commit reverts #2186. This commit replaces `sudo npm link` with what npm link actually produces: two symlinks. We can do them directly with `sudo ln -sf` and skip npm's global-prefix housekeeping entirely. O(1), no chown traversal, no hang. Changes: - scripts/brev-launchable-ci-cpu.sh: after plugin build, create /usr/local/bin/nemoclaw → $NEMOCLAW_CLONE_DIR/bin/nemoclaw.js with a direct `sudo ln -sf`. Drop the `sudo chown -R node_modules` that used to pair with npm link (no longer needed — only one file is owned by root now). - test/e2e/brev-e2e.test.ts: replace the in-test `sudo npm link` with the same direct-symlink approach. Launchable already pre-links on the same path; this is idempotent re-link so local dev runs that skip the launchable still work. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Charan Jagwani --- scripts/brev-launchable-ci-cpu.sh | 10 ++++++++++ test/e2e/brev-e2e.test.ts | 16 +++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/scripts/brev-launchable-ci-cpu.sh b/scripts/brev-launchable-ci-cpu.sh index b8b1340e00..a218657948 100755 --- a/scripts/brev-launchable-ci-cpu.sh +++ b/scripts/brev-launchable-ci-cpu.sh @@ -249,6 +249,16 @@ npm run build 2>&1 | tail -3 cd "$NEMOCLAW_CLONE_DIR" info "Plugin built" +# Expose the nemoclaw CLI on PATH. Earlier this was `sudo npm link`, but +# on cold CPU Brev that routinely hangs inside npm's global-prefix +# housekeeping and `sudo chown -R node_modules` traversal (≥20 min in +# CI). npm link just creates two symlinks in the end; do them directly +# so setup stays deterministic and fast. +info "Linking nemoclaw CLI (direct symlink)..." +sudo ln -sf "$NEMOCLAW_CLONE_DIR/bin/nemoclaw.js" /usr/local/bin/nemoclaw +sudo chmod +x "$NEMOCLAW_CLONE_DIR/bin/nemoclaw.js" +info "nemoclaw CLI linked at /usr/local/bin/nemoclaw" + # ══════════════════════════════════════════════════════════════════════ # 6. Pre-pull Docker images # ══════════════════════════════════════════════════════════════════════ diff --git a/test/e2e/brev-e2e.test.ts b/test/e2e/brev-e2e.test.ts index 8349aefefb..7e57359345 100644 --- a/test/e2e/brev-e2e.test.ts +++ b/test/e2e/brev-e2e.test.ts @@ -423,15 +423,17 @@ function bootstrapLaunchable(elapsed) { ); console.log(`[${elapsed()}] Plugin built`); - // Install nemoclaw CLI. - // Use `sudo npm link` because Node.js is installed system-wide via - // nodesource (global prefix is /usr), so creating the global symlink - // requires elevated permissions. - console.log(`[${elapsed()}] Installing nemoclaw CLI (npm link)...`); + // Expose the nemoclaw CLI on PATH. The launchable setup script already + // creates /usr/local/bin/nemoclaw → $NEMOCLAW_CLONE_DIR/bin/nemoclaw.js + // as a direct symlink, and rsync above preserves that path, so this is + // an idempotent re-link to make local dev runs (that skip the launchable) + // still work. Avoid `sudo npm link` on cold CPU Brev — it routinely + // hangs inside npm's global-prefix housekeeping. + console.log(`[${elapsed()}] Linking nemoclaw CLI (direct symlink)...`); ssh( - `source ~/.nvm/nvm.sh 2>/dev/null || true && cd ${resolvedRemoteDir} && sudo npm link && sudo chown -R $(whoami):$(whoami) ${resolvedRemoteDir}`, + `sudo ln -sf ${resolvedRemoteDir}/bin/nemoclaw.js /usr/local/bin/nemoclaw && sudo chmod +x ${resolvedRemoteDir}/bin/nemoclaw.js`, { - timeout: 120_000, + timeout: 30_000, stream: true, }, );