fix(npm): install to a user cache when the package is read-only; signal-safe first run

- When the package's bin/ is not writable (a root-owned `sudo npm i -g`
  whose postinstall npm 12 skipped), install the binary to a per-user
  cache ($XDG_CACHE_HOME, ~/.cache, ~/Library/Caches on macOS, under
  <package>/<version>/); the launcher looks in both. Previously the first
  run failed with EACCES and advice to rerun npm install.
- Run the first-run installer asynchronously with SIGTERM/SIGHUP
  forwarded, so a supervisor stopping the launcher stops the download;
  the installer removes its partial file and the launcher exits by the
  same signal.
- Verify an IDX_BINARY_URL local file's checksum on the copy, not the
  source, so the installed bytes are the checked ones.
- npm smoke covers the read-only fallback.

The last three come from a Codex review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
hermes 2026-10-16 08:07:41 +00:00
commit 907223a838
4 changed files with 156 additions and 51 deletions

View file

@ -95,4 +95,19 @@ if ! head -n 1 "${smoke_dir}/no-scripts-help.txt" | grep -q "MCP server"; then
cat "${smoke_dir}/no-scripts-help.txt" >&2
exit 1
fi
echo "npm smoke: PASS (idx-cli and idx-mcp: pack, install, --help; idx-mcp without postinstall)"
# A read-only package (root-owned global install) falls back to the user cache.
echo "npm smoke: idx-mcp without postinstall, read-only package directory"
read_only_dir="${smoke_dir}/idx-mcp-read-only"
npm_config_cache="$npm_cache" npm install --prefix "$read_only_dir" "${smoke_dir}"/idx-mcp/idx-mcp-*.tgz \
--no-save --no-package-lock --no-audit --no-fund --ignore-scripts
chmod -R a-w "${read_only_dir}/node_modules/idx-mcp"
XDG_CACHE_HOME="${smoke_dir}/user-cache" IDX_BINARY_URL="${repo_root}/target/release/idx-mcp" \
"${read_only_dir}/node_modules/.bin/idx-mcp" --help > "${smoke_dir}/read-only-help.txt"
chmod -R u+w "${read_only_dir}/node_modules/idx-mcp"
cached=("${smoke_dir}"/user-cache/idx-mcp/*/idx-mcp)
if ! head -n 1 "${smoke_dir}/read-only-help.txt" | grep -q "MCP server" || [[ ! -x "${cached[0]}" ]]; then
echo "npm smoke: idx-mcp with a read-only package did not install to the user cache:" >&2
cat "${smoke_dir}/read-only-help.txt" >&2
exit 1
fi
echo "npm smoke: PASS (idx-cli and idx-mcp: pack, install, --help; idx-mcp without postinstall, also read-only)"