--- name: expo-local-build description: Serve locally-built Expo IPAs/APKs from this Mac to a phone over the Cloudflare tunnel. The skill owns the install-page + tunnel ingress wiring; each project owns its own `eas build --local` invocation via package.json `:local` scripts. Triggers on "serve the build", "install page", "send build to phone", "deliver expo build", "expo install URL", "publish IPA", "ad-hoc install page". --- # expo-local-build This skill **does not build**. Each project owns its build via `pnpm :local` scripts that wrap `eas build --local`. This skill takes the output directory and publishes it as an install page over the Cloudflare tunnel, reachable from anywhere. The split: | | Lives in | Owns | |---|---|---| | **Build** | each project's `app/package.json` + `app/scripts/local-build.sh` | `eas build --local` invocation, macOS PATH preamble, slot naming | | **Serve** | this skill's `deliver.sh` + `install-server.mjs` | install page, tunnel ingress, port allocation, launchd persistence | ## Usage ```sh SKILL=~/.claude/plugins/marketplaces/johnkueh-skills/skills/expo-local-build/scripts bash $SKILL/deliver.sh ~/Projects/myapp/app/build-output # -> https://myapp-install.example.dev/ (open on phone, tap Install) ``` That's it. No flags needed for the common case. The install server reads `build-output/` directly and re-scans on every request, so rebuilding overwrites in place and the page reflects the new build immediately. ### Flags | Flag | What it does | |---|---| | `--label NAME` | Override the project label (default: grandparent dir name of the build-output path, e.g. `my.app` → `my-app`). | | `--persist` | Run the install server under launchd (`~/Library/LaunchAgents/dev.jkyf.expo-localbuild.