From 033d5b21f875c9f8f71d331e31eb598369cdee36 Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Fri, 21 Aug 2026 12:31:34 -0400 Subject: [PATCH] Build the launcher's extension on a machine that has only nvm The search extension is compiled, and the stage that compiles it checked for npm and skipped quietly when it found none. On this machine it always found one -- but only because Claude Desktop depends on nodejs and dragged a system npm in. Nowhere else would. Node moved to nvm when the shell config turned out to have been assuming it for months, and nvm is a shell function in a file only an interactive shell sources; a stage is not one. So a fresh install would have set up the launcher, printed one line about extensions not being built, and left somebody wondering why typing in it suggested nothing. The stage sources nvm before looking, and the contract pins that it does -- checking for npm is not the same as being able to find it. Claude-Session: https://claude.ai/code/session_01Q84axqUE5inJhf5Jz9CFy1 --- setup/scripts/link-vicinae-scripts | 16 ++++++++++++++++ tests/setup/launcher-search-contract | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/setup/scripts/link-vicinae-scripts b/setup/scripts/link-vicinae-scripts index fc5a19b..da80fb3 100755 --- a/setup/scripts/link-vicinae-scripts +++ b/setup/scripts/link-vicinae-scripts @@ -60,6 +60,22 @@ ln -s "$source_dir" "$target_dir" # extension that did not build is a launcher missing one command, not a desktop # that failed to install. extensions_source="$panama_path/config/local/share/vicinae/extensions" + +# npm comes from nvm, and nvm is a shell function in a file that only an +# interactive shell sources. A stage is not one, so without this npm is simply +# absent and the build below is skipped -- silently, which is the whole problem. +# +# This machine hid the bug: /usr/sbin/npm existed, but only because Claude +# Desktop depends on nodejs and dragged it in. A machine without that would have +# installed the launcher and quietly not built its search extension. +if [[ -s /etc/profile.d/nvm.sh ]] && ! command -v npm >/dev/null 2>&1; then + # nvm's script reads unset variables, which `set -u` treats as fatal. + set +u + # shellcheck source=/dev/null + source /etc/profile.d/nvm.sh + set -u +fi + if [[ -d "$extensions_source" ]] && command -v npm >/dev/null 2>&1; then for extension in "$extensions_source"/*/; do [[ -f "$extension/package.json" ]] || continue diff --git a/tests/setup/launcher-search-contract b/tests/setup/launcher-search-contract index 0191719..f48c118 100755 --- a/tests/setup/launcher-search-contract +++ b/tests/setup/launcher-search-contract @@ -103,6 +103,14 @@ grep -q 'npm run build' "$stage" \ grep -q 'command -v npm' "$stage" \ || note 'the extension build does not check for npm, so a machine without it fails the stage' +# Checking for npm is not enough. Node comes from nvm, whose script only an +# interactive shell sources -- and a stage is not one, so npm is absent unless +# the stage goes and gets it. This machine hid that: a system npm existed only +# because Claude Desktop depends on nodejs. Without this line, a fresh install +# builds no extension and says so in one line nobody reads. +grep -q '/etc/profile.d/nvm.sh' "$stage" \ + || note 'the extension build never sources nvm, so npm is missing on any machine without a system node' + # node_modules is a dependency tree, not configuration. git -C "$repo_dir" check-ignore -q "$extension/node_modules" 2>/dev/null \ || note 'the extension node_modules is not gitignored'