Skip to content

fix(npm-globals): re-run postinstall after native binary repair - #2046

Merged
shunkakinoki merged 1 commit into
mainfrom
fix/amp-native-binary-postinstall
Jul 11, 2026
Merged

fix(npm-globals): re-run postinstall after native binary repair#2046
shunkakinoki merged 1 commit into
mainfrom
fix/amp-native-binary-postinstall

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • After repair_native_optional_dep installs a missing native binary (e.g. @ampcode/cli-darwin-arm64), the wrapper's postinstall wasn't re-run, leaving the error-stub shim (~/.bun/bin/amp) in place
  • Packages like @ampcode/cli use a postinstall script (install.cjs) to hard-link the native binary into bin/amp.exe - this must run after the native package is present
  • Added run_postinstall_if_needed call after successful repair_native_optional_dep in both code paths: the "already installed but native missing" path and the "fresh install with native repair" path

Root cause

~/.bun/bin/amp is a symlink to @ampcode/cli/bin/amp.exe. When bun installs @ampcode/cli without its @ampcode/cli-darwin-arm64 optional dep, the postinstall writes a fallback error stub to bin/amp.exe. The script then installs the native binary via repair_native_optional_dep but never re-ran postinstall, so the stub persisted and amp kept printing "Amp native binary not installed."

Test plan

  • Run make switch - amp should work after activation without manual intervention
  • Verify amp --version outputs a version string rather than the error message

Summary by cubic

Re-runs postinstall for npm global wrappers after a native optional dependency is repaired, replacing the error-stub shim with the real binary. Fixes @ampcode/cli so ~/.bun/bin/amp works right after activation.

  • Bug Fixes
    • Call run_postinstall_if_needed "$dep" after successful repair_native_optional_dep in both paths (existing wrapper with missing native, and fresh install with immediate repair).
    • Ensures @ampcode/cli links its native package (e.g., @ampcode/cli-darwin-arm64) into bin/amp.exe, removing the "Amp native binary not installed" stub.

Written for commit f0526de. Summary will update on new commits.

Review in cubic

@indent-zero

indent-zero Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor
PR Summary

Ensures the CLI wrapper's postinstall script re-runs after install-npm-globals.sh repairs a bun-dropped platform-native optionalDependency, so wrappers like @ampcode/cli end up with a working bin/ entry in the same activation rather than requiring another run.

  • In the "already installed but native binary missing" branch, call run_postinstall_if_needed "$dep" after a successful repair_native_optional_dep.
  • In the "install missing packages" branch, restructure repair_native_optional_dep || echo failed into an explicit if/else so the success path can also invoke run_postinstall_if_needed "$dep"; failure path preserves the original stderr message.

Issues

1 potential issue found:

  • Postinstall may run twice per package in the MISSING flow: after bun add at line 307, and again after a successful native repair at line 312. For wrappers whose postinstall unconditionally fetches a platform binary over the network, this doubles the download on fresh installs. → Autofix

CI Checks

Waiting for CI checks...


⚡ Autofix All Issues

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2cc9406b-10ae-4351-98b6-18a6cad2479f

📥 Commits

Reviewing files that changed from the base of the PR and between b14d903 and f0526de.

📒 Files selected for processing (1)
  • home-manager/modules/npm-globals/install-npm-globals.sh

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Ensured package post-install steps run after successfully repairing missing native dependencies.
    • Prevented post-install steps from running when native dependency repair fails.
    • Improved error handling during package installation and updates.

Walkthrough

The npm globals installer now runs per-package postinstall hooks after successful native optional dependency repairs in both existing-version and fresh-install paths.

Changes

NPM native dependency repair

Layer / File(s) Summary
Run postinstall after successful repair
home-manager/modules/npm-globals/install-npm-globals.sh
Both native repair paths call run_postinstall_if_needed only after successful repair; failures print an error and skip postinstall.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: bug

Poem

A rabbit found a broken native sprout,
Repaired it neatly, without a doubt.
Then postinstall hopped into place,
With failures skipped at a careful pace.
“Fresh packages bloom!” the bunny sings.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: re-running postinstall after native binary repair.
Description check ✅ Passed The description directly explains the same fix, root cause, and test plan for the native repair flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/amp-native-binary-postinstall

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates install-npm-globals.sh to trigger run_postinstall_if_needed immediately after a native optional dependency is successfully repaired. The reviewer noted that run_postinstall_if_needed might incorrectly skip running the postinstall script if the package uses extensionless shell script wrappers or fallback stubs in its bin/ directory. They suggested adding a force parameter to bypass the native check when a repair has just occurred.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

# re-triggers the same bun transitive-optional drop.
if repair_native_optional_dep "$dep"; then
echo "$dep native binary repaired in place"
run_postinstall_if_needed "$dep"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If a package uses an extensionless shell script wrapper or fallback stub in its bin/ directory (which is very common), run_postinstall_if_needed will incorrectly identify it as a native binary (since it doesn't match .js, .cjs, .mjs, or .exe) and skip running the postinstall script.

Since we just successfully repaired the native optional dependency, we should force the postinstall script to run to ensure any stubs are correctly replaced and the native binary is properly linked.

We can add a force parameter to run_postinstall_if_needed to bypass the has_native check when we know a repair has just occurred:

run_postinstall_if_needed() {
  local dep="$1"
  local force="${2:-false}"
  ...
  if [ "$force" != "true" ] && [ -d "$bin_dir" ]; then
    ...
Suggested change
run_postinstall_if_needed "$dep"
run_postinstall_if_needed "$dep" true

if missing_native_optional_dep "$dep"; then
repair_native_optional_dep "$dep" || echo "Native binary repair failed: $dep" >&2
if repair_native_optional_dep "$dep"; then
run_postinstall_if_needed "$dep"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Similarly to the repair path above, we should force the postinstall script to run here to bypass the has_native check, ensuring that any extensionless fallback stubs or wrappers are correctly replaced by the postinstall script after the native binary is repaired.

Suggested change
run_postinstall_if_needed "$dep"
run_postinstall_if_needed "$dep" true

@mesa-dot-dev mesa-dot-dev 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.

Performed full review of b14d903...f0526de

Analysis

Error handling for postinstall failures is implicit and non-standardized: After repair_native_optional_dep succeeds, run_postinstall_if_needed is called but the consequences of its failure are unclear (silent inconsistency vs. flow abort). Error policy must be explicit with appropriate logging to prevent users from silently ending with repaired natives but broken shims.

Idempotency of postinstall is assumed but undocumented: The increased invocation frequency of run_postinstall_if_needed requires strict idempotency of wrapper postinstall scripts. This constraint should be documented and verified across all globally managed packages to prevent state corruption from repeated runs.

Repair+postinstall coupling risk for future drift: Having two separate call sites that must both pair repair_native_optional_dep with run_postinstall_if_needed creates maintenance burden and risk of omission in future code paths. Missing this coupling elsewhere in the codebase would silently reintroduce the lifecycle gap. Consider centralizing this into a single repair_and_reconcile_native_dep primitive.

Limited scope visibility: The fix covers both repair paths within this file, but other scripts or functions outside this file that call repair_native_optional_dep or mutate optional native deps may lack postinstall reconciliation, creating inconsistency across the broader codebase.

Tip

Help

Slash Commands:

  • /review - Request a full code review
  • /review latest - Review only changes since the last review
  • /describe - Generate PR description. This will update the PR body or issue comment depending on your configuration
  • /help - Get help with Mesa commands and configuration options

0 files reviewed | 2 comments | Edit Agent SettingsRead Docs

if missing_native_optional_dep "$dep"; then
repair_native_optional_dep "$dep" || echo "Native binary repair failed: $dep" >&2
if repair_native_optional_dep "$dep"; then
run_postinstall_if_needed "$dep"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Medium

Same concern as the other call site: postinstall rerun failure should be explicitly handled and logged. Without this, a silent failure in run_postinstall_if_needed could leave the wrapper in a stale state despite successful native binary repair. Consider: run_postinstall_if_needed "$dep" || echo "Warning: postinstall reconciliation failed for $dep" >&2

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#2046
File: home-manager/modules/npm-globals/install-npm-globals.sh#L312
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Same concern as the other call site: postinstall rerun failure should be explicitly handled and logged. Without this, a silent failure in `run_postinstall_if_needed` could leave the wrapper in a stale state despite successful native binary repair. Consider: `run_postinstall_if_needed "$dep" || echo "Warning: postinstall reconciliation failed for $dep" >&2`

# re-triggers the same bun transitive-optional drop.
if repair_native_optional_dep "$dep"; then
echo "$dep native binary repaired in place"
run_postinstall_if_needed "$dep"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Medium

Consider adding explicit error handling for run_postinstall_if_needed failure. If postinstall fails after successful native binary repair, the system could end up in an inconsistent state (native dep present but wrapper shim still broken) with no clear diagnostic signal. Recommendation: capture the exit status and log a warning if postinstall reconciliation fails, e.g., run_postinstall_if_needed "$dep" || echo "Warning: postinstall reconciliation failed for $dep" >&2

Agent: 🏛 Architecture • Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#2046
File: home-manager/modules/npm-globals/install-npm-globals.sh#L280
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Consider adding explicit error handling for `run_postinstall_if_needed` failure. If postinstall fails after successful native binary repair, the system could end up in an inconsistent state (native dep present but wrapper shim still broken) with no clear diagnostic signal. Recommendation: capture the exit status and log a warning if postinstall reconciliation fails, e.g., `run_postinstall_if_needed "$dep" || echo "Warning: postinstall reconciliation failed for $dep" >&2`

if missing_native_optional_dep "$dep"; then
repair_native_optional_dep "$dep" || echo "Native binary repair failed: $dep" >&2
if repair_native_optional_dep "$dep"; then
run_postinstall_if_needed "$dep"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Postinstall runs twice on fresh installs: run_postinstall_if_needed "$dep" was already invoked at line 307 immediately after bun add. When bun drops the transitive optional dep and we then repair_native_optional_dep, we call it a second time here. For postinstalls that unconditionally hit the network to fetch a platform binary, that's a duplicate download per fresh install.

Consider skipping the earlier call when a native repair is likely to fire, or short-circuit the second call if the first one already populated the wrapper's bin/.

@shunkakinoki
shunkakinoki merged commit f563916 into main Jul 11, 2026
35 checks passed
@shunkakinoki
shunkakinoki deleted the fix/amp-native-binary-postinstall branch July 11, 2026 14:58
@mesa-dot-dev

mesa-dot-dev Bot commented Jul 11, 2026

Copy link
Copy Markdown

Mesa Description

TL;DR

Re-runs the wrapper package's postinstall script after successful repair of missing native optional dependencies, ensuring that binaries are correctly linked rather than leaving error-stub shims in place.

What changed?

  • home-manager/modules/npm-globals/install-npm-globals.sh: Added run_postinstall_if_needed calls immediately after repair_native_optional_dep in both the "already installed but native missing" verification path and the fresh install self-healing path.

Description generated by Mesa. Update settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant