Skip to content

fix(input-helper): self-heal missing +x on packaged Swift binary (#32)#33

Open
mrz1880 wants to merge 1 commit into
antbotlab:mainfrom
mrz1880:fix/self-heal-helper-exec-bit
Open

fix(input-helper): self-heal missing +x on packaged Swift binary (#32)#33
mrz1880 wants to merge 1 commit into
antbotlab:mainfrom
mrz1880:fix/self-heal-helper-exec-bit

Conversation

@mrz1880

@mrz1880 mrz1880 commented Jun 11, 2026

Copy link
Copy Markdown

Summary

Closes (partially) #32 — the runtime side of the fix discussed in that issue.

  • Distinguish binary missing from binary present but not executable in runInputHelper instead of collapsing both into BINARY_NOT_FOUND.
  • Attempt a one-shot chmod 0o755 self-heal when the file exists without +x. This recovers the vast majority of broken installs in the wild today (npx cache, --ignore-scripts consumers, anything laid down before a publish-time fix lands) with zero user action.
  • Rewrite the error messages so they point at the real problem: BINARY_NOT_EXECUTABLE includes the actual path so the user knows exactly which file to chmod; BINARY_NOT_FOUND no longer sends npx users to pnpm run build:swift (a dead end without a source tree) and instead splits guidance for npx vs. local-checkout consumers.

This is meant to complement, not replace, the publish-time prepublishOnly mode-assertion proposed in the issue thread — that's still the right primary fix. The two together would protect future releases (prepublishOnly) while rescuing every cached install that already exists on disk today (this PR).

What changed

  • src/helpers/input-helper.ts — new ensureBinaryExecutable() helper:
    • access(X_OK) first → fast path, unchanged behavior when everything is fine.
    • On failure, access(F_OK) to disambiguate. Missing → BINARY_NOT_FOUND with path in the message.
    • File exists → chmod(BINARY_PATH, 0o755) then re-check X_OK. Any failure in that sequence → BINARY_NOT_EXECUTABLE with the path and the original error preserved as cause.
  • src/constants.ts — added ERROR_MESSAGES.BINARY_NOT_EXECUTABLE; reworded BINARY_NOT_FOUND to be actionable for both install paths.
  • src/__tests__/helpers/input-helper.test.ts — added two new tests:
    • self-heals via chmod when binary exists but lacks +x (asserts chmod is called with 0o755 and execution proceeds).
    • throws BINARY_NOT_EXECUTABLE when binary exists but chmod fails (asserts execFile is never invoked).
      Existing test for the missing-file path still covers BINARY_NOT_FOUND via substring match on the message.
  • CHANGELOG.md — entry under [Unreleased] linking to dist/bin/input-helper is published without executable bit — every Swift-backed tool fails with misleading "build:swift" error #32.

Test plan

  • pnpm test — 184 tests pass (was 181; +3 for the new behavior).
  • pnpm lint — clean.
  • pnpm build — clean.
  • Manually reproduced the original failure on macOS arm64 with npx -y mac-use-mcp@1.1.1, then verified that on this branch the first tool call (screenshot) succeeds without any manual chmod.

Notes for reviewers

  • The new catch clause in ensureBinaryExecutable is bare (no error binding) because the X_OK error gets superseded by either the F_OK error (missing file path) or the heal-attempt error (chmod path) — preserving the originally-caught error there would mask the more informative downstream cause. The lint rule preserve-caught-error is happy with this shape.
  • BINARY_PATH is appended at the throw site rather than templated into the constant so the constants table stays a plain as const lookup (consistent with how TIMEOUT works).
  • No behavior change on the happy path: access(X_OK) returns immediately and we proceed to execFile exactly as before.

…botlab#32)

npm pack normalizes file modes from the registry index, so
dist/bin/input-helper ships as 0644 from npx installs even though
the source tarball has +x. Every Swift-backed tool then surfaces a
misleading "run pnpm run build:swift" error to end users who don't
have a source tree or Xcode toolchain.

Distinguish "binary missing" from "binary present but not executable"
in runInputHelper, chmod 0o755 as a one-shot self-heal for the latter,
and only fall back to a structured error if recovery fails. The new
BINARY_NOT_EXECUTABLE message names the path and the chmod command;
the reworded BINARY_NOT_FOUND points users at the right install step
for npx vs. local-checkout consumers instead of pnpm run build:swift.
@mrz1880 mrz1880 force-pushed the fix/self-heal-helper-exec-bit branch from 5436e88 to c917886 Compare June 11, 2026 15:37
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