Skip to content

Fix Bun installs getting npm self-update hints (#1621) - #1622

Merged
Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-bun-self-update-hint
Oct 20, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-bun-self-update-hint

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1621

Summary

socket-patch --update (and the passive update notice) told Bun users that the binary was "managed by npm" and gave them an npm command. For a bun add -g install, npm update -g is a no-op. In a Bun project, npm install …@latest writes a stray package-lock.json, leaves bun.lock stale, and breaks the next bun install --frozen-lockfile. Bun installs are now labelled bun and get Bun's own command:

Install shape Detected by Hint
bun add -g …/install/global/node_modules/… ($BUN_INSTALL, default ~/.bun) bun add -g @socketsecurity/socket-patch@latest (bun update -g keeps the exact pinned version)
bun add in a project node_modules/.bun/ isolated store in the path, or bun.lock / bun.lockb beside the outermost node_modules bun add @socketsecurity/socket-patch@latest
bunx the holder (or, for a scoped spec, its parent) is named bunx-<numeric uid>-… bunx @socketsecurity/socket-patch@latest …

Root cause

update/channel.rs's node_manager knew only npm, pnpm and vlt ("Anything else is npm, which also covers yarn and Bun (no dedicated hint yet)"). The fix adds Bun / Bunx managers at that boundary. commands/update.rs (the refusal) and update_notifier.rs (the passive notice) both go through upgrade_hint_for / channel_label_for, so they're both fixed. A path's own store component (.pnpm, .bun) now outranks a lockfile left beside the project, and pnpm's lockfile still outranks Bun's when no store names the manager. CLI_CONTRACT.md's managed-install row is updated to match. The npm/PyPI/gem wrappers have no update hints of their own, so they need no change.

Tests

  • Unit (crates/socket-patch-core/src/update/channel.rs): bun_global_installs_get_bun_add_g, bun_project_installs_get_bun_add, bunx_cache_gets_bunx_latest. All 3 failed on main 657fce2 (cargo test -p socket-patch-core --lib update::channel: 18 passed, 3 failed) and pass with the fix (21 passed).
  • E2E (crates/socket-patch-cli/tests/update/self_update_channels_e2e.rs): bun_project_refuses_with_bun_hint and bun_global_refuses_with_bun_hint spawn the real binary from a staged Bun layout and check the managed by bun refusal and its hint. cargo test -p socket-patch-cli --all-features --test update: 65 passed.
  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --all-features --lib: 6537 passed. 4 failed, all permission-injection tests (copy_tree, vlt_heal, pypi_poetry, pypi_requirements) that chmod a dir to 0o555 and expect a write to fail. The agent container runs as root, which ignores that. They're unrelated to this diff, and CI runs as non-root.
  • The full cargo test --workspace run didn't fit this container's disk allowance (the target dir passed 20 GB). CI covers it.

Per-issue checklist:

/code-review high

I fixed two findings in 26461c3. (1) A bunx cache dir without a package.json was read as a global prefix. (2) A leftover pnpm-lock.yaml beat Bun's own .bun store. I tightened the bunx name match to a numeric uid in the same commit. Not fixed, as follow-ups outside this PR's scope:

  • A hoisted Bun workspace member's own node_modules copy: the lockfile is only looked for beside the outermost node_modules. pnpm and vlt have the same limit today.
  • A Bun workspace root where a member declares the dependency: pnpm gets pnpm update --recursive --latest. I couldn't verify Bun's equivalent here, so Bun keeps bun add …@latest.
  • A global dir set with BUN_INSTALL_GLOBAL_DIR / bunfig install.globalDir isn't recognized as global.
  • --backend=symlink installs that canonicalize into ~/.bun/install/cache have no node_modules component and read as Standalone. This predates the PR and applies to every channel heuristic.
  • Probing each refusal twice (once for the label, once for the hint): this predates the PR.

https://claude.ai/code/session_016akFSbKa8ztJC4jji31cAn


Note

Low Risk
Heuristic-only changes to refusal messaging and upgrade hints for managed installs; no self-update download or binary replacement behavior changes beyond correct manager detection.

Overview
Self-update managed-install detection now recognizes Bun installs (global store, project with bun.lock/bun.lockb or node_modules/.bun, and bunx cache dirs) instead of labeling them npm and suggesting npm commands that don't work or corrupt lockfiles.

node_manager in update/channel.rs gains Bun / Bunx with path heuristics (store components beat stale lockfiles; pnpm lock still wins when no store names the manager). Refusal messages use managed by bun and hints like bun add -g …, bun add …, or bunx …@latest. CLI_CONTRACT.md documents the Bun row; unit and e2e tests cover global, project, and bunx cases.

Reviewed by Cursor Bugbot for commit 26461c3. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
`socket-patch --update` on a copy installed with Bun said it was
"managed by npm" and suggested an npm command. For a `bun add -g`
install that command is a no-op, and in a Bun project `npm install`
writes a stray package-lock.json and breaks the next
`bun install --frozen-lockfile`. The passive update notice showed the
same wrong hint.

Bun installs are now labelled "bun" and told to run:
- `bun add -g @socketsecurity/socket-patch@latest` for Bun's global
  store (`$BUN_INSTALL/install/global`),
- `bun add @socketsecurity/socket-patch@latest` in a project with
  bun.lock / bun.lockb or Bun's isolated `node_modules/.bun` store,
- `bunx @socketsecurity/socket-patch@latest …` for bunx's cache dir.

Fixes #1621

Assisted-by: Claude Code:claude-opus-5-5
A bunx cache dir is now recognized by its name even when it holds no
package.json (which would otherwise read as a global prefix and get
`bun add -g`). A project-only `bunx-...` name no longer matches: the
uid part must be numeric, as bunx writes it.

A `.bun` or `.pnpm` store in the binary's path now outranks a
lockfile left beside the project, so a project that moved from pnpm
to Bun and still has pnpm-lock.yaml is told to use Bun.

Refs #1621

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 17, 2026 04:57
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 26461c3. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 17, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent).

  • Head: 26461c3b
  • CI: 86/86 green (36 passed, 50 skipped), no main-wide failures
  • Bugbot: reviewed 26461c3b, no findings
  • Mergeable, no CHANGELOG.md change
  • Reviewer note: the Bun/bunx detection in crates/socket-patch-core/src/update/channel.rs is path-heuristic; store-path components intentionally win over stale lockfiles.

Slack announcement could not be sent this run (no Slack send tool available); the next run will retry.


Generated by Claude Code

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 20, 2026
The merge queue dropped this PR because
`pipenv::pipenv_pylock_projects_wire_what_pipenv_installs` failed in the
e2e_vex_build pipenv leg. uv 0.13.2+ refuses the `environments = []`
pylock that Pipenv 2026.8.0 writes ("The target environment is not
supported by the lockfile"), and setup-uv without `version:` installs
the newest uv. main's nightly is red for the same reason.

This is the same pin #1639 adds to ci.yml and pipenv-compatibility.yml.
It changes nothing once #1639 lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016akFSbKa8ztJC4jji31cAn
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

The merge queue dropped this PR (CI_FAILURE) because a check failed that has nothing to do with this PR's code.

  • Failing check: e2e (ubuntu-latest, e2e_vex_build, pipenv:: --ignored, 2026.8.0). The failing test is pipenv::pipenv_pylock_projects_wire_what_pipenv_installs: uv pip install -r pylock.toml fails with "The target environment is not supported by the lockfile". It failed the same way in both of this PR's queue groups (runs 39462230399 and 39463384690).
  • Why it isn't this PR's: CI's setup-uv installs the newest uv, now 0.13.4. Since 0.13.2, uv refuses the environments = [] pylock that Pipenv 2026.8.0 writes. main's nightly on 14eee88b is red for the same reason, and Fix Pipenv refusing split-version categories (#1616) #1617's queue run hit it too. This PR only changes Bun self-update detection.
  • Fix ported: 251cd21 adds Fix nightly Pipenv pylock legs broken by uv 0.13.2 #1639's pin (setup-uv version: "0.13.1" in ci.yml and pipenv-compatibility.yml). It changes nothing once Fix nightly Pipenv pylock legs broken by uv 0.13.2 #1639 lands. I tested it locally on a Pipenv-style environments = [] pylock: uv 0.13.1 installs six==1.16.0, and uv 0.13.4 gives the same error as CI.
  • Before the push: d73cd80 merges in current main. fmt, clippy (-D warnings), the channel unit tests (21) and the CLI update suite (65) all pass on the merged head.

The PR needs to be added back to the merge queue once CI is green on 251cd21.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Wenxin Jiang (@Wenxin-Jiang) this changed after your approval (on 26461c3b), so it needs another look before it goes through the merge queue.

Besides merges from main, the only new commit is 251cd21: the CI-only uv pin from #1639 (version: "0.13.1" on the setup-uv steps in ci.yml and pipenv-compatibility.yml, 12 added lines, byte-for-byte the same as #1639). No crate code changed. Without it the pipenv:: e2e leg fails in the merge queue on uv 0.13.2+. It no-ops once #1639 lands.

If that's fine with you, re-approving 251cd210 is all this needs.


Generated by Claude Code

Merged via the queue into main with commit 43a6038 Oct 20, 2026
54 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-bun-self-update-hint branch October 20, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants