Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
50a78f3
[simulator-launcher] Prepare Simulator services at guest startup
gwdp Oct 23, 2026
93fc358
[simulator-launcher] Claim warm sessions once serve-sim is ready
gwdp Oct 24, 2026
1fad3cf
[simulator-launcher] Disable apsd during warmup
gwdp Oct 24, 2026
0cba53c
[simulator-launcher] Stop installing ffmpeg during warmup
gwdp Oct 24, 2026
f9ee3cb
[simulator-launcher] Start replacement services without waiting for s…
gwdp Oct 25, 2026
6c38a43
[simulator-launcher] Report the preinstalled Expo Go in the claim record
gwdp Oct 25, 2026
5c600e3
[simulator-launcher] Handle a failed serve-sim exit while waiting for…
gwdp Oct 25, 2026
64cddb0
[simulator-launcher] Read serve-sim readiness from its configured state
gwdp Oct 25, 2026
f8f672b
[simulator-launcher] Settle every old stop before failing a replacement
gwdp Oct 25, 2026
7bd9f73
[simulator-launcher] Treat an already shut down Simulator as cleaned up
gwdp Oct 25, 2026
8fef6f5
[simulator-launcher] Simplify warm Simulator cleanup
gwdp Oct 25, 2026
c9196e1
[simulator-launcher] Update the README for warm claim and cleanup
gwdp Oct 25, 2026
2fce2ff
[simulator-launcher] Simplify apsd disabling and the claim result
gwdp Oct 25, 2026
96e169d
[simulator-launcher] Start Simulator tools after serve-sim is ready
gwdp Oct 25, 2026
81a3bec
[simulator-launcher] Treat exited processes awaiting reap as stopped
gwdp Oct 25, 2026
026dc78
[simulator-launcher] Probe readiness only at the local serve-sim address
gwdp Oct 25, 2026
2854146
[simulator-launcher] Split the warm session into simulator and tool m…
gwdp Oct 25, 2026
3b0db0c
[simulator-launcher] Use the shared warm Simulator terms in the chang…
gwdp Oct 26, 2026
6b6ff97
[simulator-launcher] Use the shared warm Simulator terms in the README
gwdp Oct 26, 2026
2d01d9b
[simulator-launcher] Name the warm session handle type
codex Oct 26, 2026
5455ea0
[simulator-launcher] Use the package version instead of a copied bundle
codex Oct 26, 2026
e4ae4c4
[simulator-launcher] Accept a list of warm Simulator devices
codex Oct 26, 2026
b0e40d9
[simulator-launcher] Warm more devices after the default is ready
codex Oct 26, 2026
0779aed
[simulator-launcher] Claim either warm device and release the others
codex Oct 26, 2026
cca8819
[simulator-launcher] Prime the launcher cache before ready
codex Oct 26, 2026
dc6977b
[simulator-launcher] Keep unused-device cleanup from stopping the job
codex Oct 26, 2026
fe7c627
[simulator-launcher] Keep default warmup after an additional device f…
codex Oct 26, 2026
29fd654
[simulator-launcher] Keep the default device for blank configuration
codex Oct 26, 2026
28f4e83
[simulator-launcher] Bound cache priming and retry once
codex Oct 26, 2026
c1aad59
[simulator-launcher] Shut owned devices down in parallel at terminal …
codex Oct 26, 2026
bf44a35
[simulator-launcher] Finish default warmup before sharing Expo Go wit…
codex Oct 26, 2026
6646061
[simulator-launcher] Start warm serve-sim with explicit orphan ownership
codex Oct 26, 2026
3326bbd
[simulator-launcher] Start the selected Simulator before returning it…
codex Oct 26, 2026
6e60a81
[simulator-launcher] Keep Expo Go failures scoped to their device
codex Oct 26, 2026
abf447d
[stack] Integrate current main while preserving existing commits
codex Oct 27, 2026
3d8868a
[simulator-launcher] Keep the base launcher focused on one device
gwdp Oct 27, 2026
1f214df
[simulator-launcher] Keep one selected device in session state
gwdp Oct 27, 2026
2b471ce
[simulator-launcher] Make session startup and cleanup explicit
gwdp Oct 27, 2026
682a387
[stack] Keep launcher commands above service helpers
gwdp Oct 27, 2026
29c2bd5
[stack] Keep existing changes above public launcher metadata
gwdp Oct 27, 2026
bae24fc
[stack] Retain the launcher foundation release entry
gwdp Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/simulator-launcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@expo/simulator-launcher': minor
---

Add `@expo/simulator-launcher` to warm an iOS Simulator at VM startup, hand it to one job with `claim`, and clean up with `stop`.
54 changes: 54 additions & 0 deletions packages/simulator-launcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# @expo/simulator-launcher

Warm an iOS Simulator before an EAS job arrives. Requires macOS.
The image installs vm-tools and writes its startup script at
`/usr/local/share/vm-tools/startup.sh`:

```sh
export EXPO_SIMULATOR_STARTUP=1
export EXPO_SIMULATOR_DEVICE="iPhone Duo"
exec bunx @expo/simulator-launcher@latest start
```

## Commands

- `start`: boot the device, attempt to disable apsd and start serve-sim. Agent-device and Argent
start alongside it; a claim waits only for its requested tool.
- `claim ENGINE [DEVICE]`: give the warm device to one job. Engines: `serve-sim`, `agent-device`,
`argent`. No DEVICE means the configured device. A different device boots while the old
server and tools stop; the old device shuts down in the background.
- `stop`: permanently end warmup for this boot and wait for all owned resources to be cleaned up.

```sh
# Build-tools reads LAUNCHER_VERSION from the version recorded by start.
bun x --no-install "@expo/simulator-launcher@$LAUNCHER_VERSION" claim serve-sim
bun x --no-install "@expo/simulator-launcher@$LAUNCHER_VERSION" stop
```

Start records its package version and primes Bun's exact-version cache before ready, with two
attempts of up to 30 seconds. Claim/stop use `--no-install`, retrying once with the registry only
when Bun cannot find the cached binary. Priming failures warn. Before start has run, stop uses
the normal package-manager path and still disables later warmup for this boot.

One durable state file, `/tmp/expo-simulator-startup.json`, holds the lifecycle, launcher version,
device/port, claim and native identity. It is independent of HOME/TMPDIR. A short boot-scoped lock
serializes updates; an abandoned lock fails closed. This private format requires a fresh VM.

## Environment

- `EXPO_SIMULATOR_STARTUP=1` enables warmup.
- `EXPO_SIMULATOR_DEVICE`: exact device name or UDID. Unset, empty or blank selects the shortest
available iPhone name. Missing or ambiguous devices fail clearly.
- `SERVE_SIM_VERSION`, `AGENT_DEVICE_VERSION`, `ARGENT_VERSION`: each defaults to `latest`.
- `AGENT_DEVICE_STATE_DIR`, `ARGENT_EVENT_LOG`: tool state/output locations.
- Agent-device idle timers default to off. Override with `AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS`
and `AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS` (milliseconds).

## Boundaries

- Ready means the device booted, its apsd disable attempt finished and serve-sim answers.
Job-time native, version and authentication checks plus private serve-sim adoption remain
authoritative. The VM image provides ffmpeg.
- One start attempt and one accepted claim per boot. Failed cleanup never permits another session.
Stop's caller timeout is not a global cleanup deadline or proof that teardown completed.
A build-tools claim timeout uses normal startup only after confirmed terminal cleanup.
2 changes: 2 additions & 0 deletions packages/simulator-launcher/bin/simulator-launcher
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('../dist/index').runCliAsync();
13 changes: 11 additions & 2 deletions packages/simulator-launcher/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@expo/simulator-launcher",
"version": "25.3.0",
"description": "Simulator state, process and service helpers",
"description": "Launch and claim Simulator sessions on EAS workers",
"bugs": "https://github.com/expo/eas-cli/issues",
"license": "BUSL-1.1",
"author": "Expo <support@expo.io>",
Expand All @@ -10,16 +10,25 @@
"url": "https://github.com/expo/eas-cli.git",
"directory": "packages/simulator-launcher"
},
"bin": "bin/simulator-launcher",
"files": [
"bin",
"dist/index.js"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"test": "jest --config jest.config.ts",
"typecheck": "tsc --noEmit"
"build": "ncc build src/main.ts -o dist --no-cache --no-source-map-register",
"typecheck": "tsc --noEmit",
"prepack": "yarn build",
"rebuild": "yarn build"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/node": "22.20.5",
"@vercel/ncc": "^0.38.1",
"jest": "^29.7.0",
"ts-jest": "^29.4.12",
"typescript": "^6.0.3",
Expand Down
Loading
Loading