Skip to content

Drop gtb turbo's Android escape hatch for the npm turbo - #349

Draft
gtbuchanan wants to merge 1 commit into
mainfrom
turbo-android-native
Draft

Drop gtb turbo's Android escape hatch for the npm turbo#349
gtbuchanan wants to merge 1 commit into
mainfrom
turbo-android-native

Conversation

@gtbuchanan

Copy link
Copy Markdown
Owner

Summary

vercel/turborepo#12735 shipped in turbo 2.10.8, publishing the linux-arm64 binary under os: ["android", "linux"]. node_modules/.bin/turbo now starts on Termux, so gtb turbo no longer resolves a pkg install turbo binary from $PREFIX/bin/turbo.

That fixes the launcher, but not how turbo spawns tasks. The npm binary is statically linked (no PT_INTERP), so Termux's libtermux-exec-ld-preload.so shebang rewriter never loads into it and execve on $PREFIX/bin/pnpm hits its literal #!/usr/bin/env node, which Android has no /usr/bin/env for. @gtbuchanan/pnpm-termux-shim remains the fix for that — it moves from a defensive dependency to the mechanism the npm turbo depends on, so this repo now dogfoods it as a workspace-root optionalDependency.

Why gtb turbo still exists

Installing the shim is what makes the wrapper load-bearing. turbo resolves the package manager against PATH from the directory it was invoked in, keeps the path that search produced, then runs each task with that package's directory as the cwd — so a match from a relative entry is re-interpreted against the child's directory and the spawn fails. pnpm always prepends a relative ./node_modules/.bin, which is exactly where the shim installs its pnpm.

gtb turbo now rewrites every PATH entry to an absolute path before invoking turbo. Isolated on-device:

PATH entry 1 pnpm at <root>/<entry> pnpm at <pkg>/<entry> Result
./packages no no falls through to the absolute entry ✅
./relbin (probe) yes yes ran the package-dir copy, not the one turbo picked ⚠️
./relbin (probe) yes no unable to spawn child process, absolute entry never tried ❌

Non-Android hosts are unaffected either way: the shim's os filter means nothing named pnpm occupies node_modules/.bin, so the relative entry never matches and the normalization is a no-op.

Verification

  • Full pnpm build --concurrency=1 on Termux/aarch64: 73/73 tasks, gtb verify clean
  • pnpm run gtb turbo run typecheck:ts exercises the real pnpm-injected PATH end to end
  • 8 unit tests for withAbsolutePathEntries, written before the implementation and confirmed failing first

Notes

  • Docs updated: gtb-build-pipeline skill (Android-Termux section, description, and two evals that encoded the removed behavior), both package READMEs, CONTRIBUTING.md, and AGENTS.md
  • AGENTS.md's "Why turbo isn't in mise.toml" reasoning is unchanged — #12735 widened the os field of the existing npm package rather than adding standalone release binaries, so mise still has no backend with per-platform integrity
  • The shim README's mechanism was corrected: the binary is statically linked, not glibc-built as previously documented

🤖 Generated with Claude Code

turbo 2.10.8 publishes its linux-arm64 binary under
os: ["android", "linux"] (vercel/turborepo#12735), so
node_modules/.bin/turbo starts on Termux and the pkg-install
resolution of $PREFIX/bin/turbo in `gtb turbo` is obsolete.

In its place `gtb turbo` rewrites every PATH entry to an absolute
path. turbo resolves the package manager against PATH from the
directory it was invoked in and keeps the path that search
produced, then runs each task with that package's directory as the
cwd -- so a match from a relative entry is re-interpreted against
the child's directory and the spawn fails with ENOENT. pnpm always
prepends a relative ./node_modules/.bin, which is exactly where
@gtbuchanan/pnpm-termux-shim installs its pnpm.

That makes the shim the mechanism the npm turbo depends on rather
than a defensive dependency, so this repo now dogfoods it as a
workspace-root optionalDependency.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4db9a4e3-a68a-4321-9edf-97bfac33d1a9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.87%. Comparing base (feae032) to head (d93b0da).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
packages/cli/src/commands/root/turbo.ts 77.77% 1 Missing and 1 partial ⚠️

❌ Your patch status has failed because the patch coverage (77.77%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants