stim 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +37 -0
  2. package/dist/{android-CC5bUer7.mjs → android-BW8i_YxU.mjs} +1 -1
  3. package/dist/android-BqVIJoG7.mjs +1368 -0
  4. package/dist/{android-DnZlT3aU.mjs → android-CqcW1hrP.mjs} +205 -58
  5. package/dist/{android-cas-DGlTStWu.mjs → android-cas-BR5YJBYv.mjs} +6 -6
  6. package/dist/android-cas-compiler.mjs +1 -1
  7. package/dist/{app-install-oZIQRbdD.mjs → app-install-DIp9riNx.mjs} +29 -21
  8. package/dist/{build-slots-CgacA9zQ.mjs → build-slots-C3-R4XQr.mjs} +3 -3
  9. package/dist/{cache-manifest-oeH18ERr.mjs → cache-manifest-CXR-Y8pH.mjs} +1 -1
  10. package/dist/cache-manifest.mjs +1 -1
  11. package/dist/cli.mjs +13 -13
  12. package/dist/collector-run.d.mts +4 -1
  13. package/dist/collector-run.mjs +36 -11
  14. package/dist/{config-D7uu8Gbq.mjs → config-CcefMY2Q.mjs} +94 -13
  15. package/dist/{deps-64wVnpZc.mjs → deps-Spz8ozgo.mjs} +2 -2
  16. package/dist/{dev-client-Bvky1hya.mjs → dev-client-BjisHDB5.mjs} +250 -10
  17. package/dist/{device-DJKv5Qej.mjs → device-BkiW-gkk.mjs} +19 -11
  18. package/dist/{device-lease-D-G3SgVe.mjs → device-lease-BJYybF-2.mjs} +107 -83
  19. package/dist/{device-pool-BlHXnYYs.mjs → device-pool-CPbLGfrB.mjs} +19 -13
  20. package/dist/{device-remote-CCgkG82J.mjs → device-remote-AkYCKS8U.mjs} +8 -8
  21. package/dist/{doctor-DlVxTtMq.mjs → doctor-Bmv86UUW.mjs} +18 -26
  22. package/dist/{doctor-BRF9aAJ3.mjs → doctor-fAMXC4vl.mjs} +10 -10
  23. package/dist/{error-diagnostics-B5IJwv3-.mjs → error-diagnostics-DHC31rXA.mjs} +65 -55
  24. package/dist/{exec-bsN9MJXb.mjs → exec-CyylIdq9.mjs} +4 -2
  25. package/dist/{gc-DhXdgSdt.mjs → gc-GGu-8ULN.mjs} +90 -67
  26. package/dist/{guide-DrhrDBo5.mjs → guide-92CPA21s.mjs} +414 -47
  27. package/dist/{ios-CK1Vrk6Q.mjs → ios-BSXFeO5H.mjs} +200 -59
  28. package/dist/{ios-BZxKPuqP.mjs → ios-Deh5js5V.mjs} +147 -40
  29. package/dist/{ios-device-CdSm0GDw.mjs → ios-device-CWOM_S44.mjs} +2 -2
  30. package/dist/{ios-device-CYbuRNXR.mjs → ios-device-D3pzTKQE.mjs} +1 -1
  31. package/dist/{logs-Dxoy16Qv.mjs → logs-DPNF4C9s.mjs} +9 -6
  32. package/dist/{logs-query-oqn47Ffx.mjs → logs-query-R-Cqc6Qv.mjs} +22 -5
  33. package/dist/{metro-B01H3EuD.mjs → metro-CORqXyTL.mjs} +3 -3
  34. package/dist/{ndjson-DcAtEx_K.mjs → ndjson-BZwI1NBv.mjs} +5 -2
  35. package/dist/{ownership-D8HmSv2E.mjs → ownership-8O073GIC.mjs} +3 -3
  36. package/dist/{ownership-B9QIdQOw.mjs → ownership-BpCKiRlQ.mjs} +4 -4
  37. package/dist/{ownership-claim-CeJLEpjD.mjs → ownership-claim-Bf2CAfw3.mjs} +4 -3
  38. package/dist/{project-COj6nzzh.mjs → project-fKmuIaMI.mjs} +2 -2
  39. package/dist/{reclaim-BPvN2HlP.mjs → reclaim-iW9Cad7k.mjs} +80 -73
  40. package/dist/{reload-DYZEBbZy.mjs → reload-DazHDSFA.mjs} +32 -24
  41. package/dist/{server-bare-BYHqEeyw.mjs → server-bare-DEzPZLvf.mjs} +7 -2
  42. package/dist/server-expo-44em5Pmg.mjs +2 -0
  43. package/dist/{server-expo-BEMr_m6p.mjs → server-expo-DizT4OMk.mjs} +5 -5
  44. package/dist/{settings-BSwrY4FZ.mjs → settings-DEJf6_kJ.mjs} +26 -5
  45. package/dist/slot-launch-cci0xvmC.mjs +19 -0
  46. package/dist/{start-ByCylYtB.mjs → start-mObjQH2W.mjs} +12 -12
  47. package/dist/{state-IYEY-zi8.mjs → state-B3XA2wp2.mjs} +9 -9
  48. package/dist/{stats-wqxPm7Tv.mjs → stats-BR-kwj0B.mjs} +1 -1
  49. package/dist/{stats-DZ4Q5J-7.mjs → stats-CaaQr4yN.mjs} +3 -3
  50. package/dist/{status-Dia0XTqG.mjs → status-BxQNqu9t.mjs} +86 -25
  51. package/dist/{stop-D6o5zAdm.mjs → stop-CrHGcjrV.mjs} +2 -2
  52. package/dist/{stop-BApyaF21.mjs → stop-DimGXEKY.mjs} +93 -42
  53. package/dist/supervisor-run.d.mts +1 -2
  54. package/dist/supervisor-run.mjs +5 -5
  55. package/dist/{remote-cache-DOi5-zLj.mjs → teardown-ClFp1Aax.mjs} +889 -830
  56. package/dist/{workspace-process-lock-CxOO9-pf.mjs → workspace-process-lock-3NcQnZ0X.mjs} +1 -1
  57. package/dist/{worktree-DxEmUI_n.mjs → worktree-DxTgN1CJ.mjs} +16 -16
  58. package/dist/{worktree-Dx3ZC5lS.mjs → worktree-Eq6TLH8N.mjs} +7 -3
  59. package/dist/{xcode-CDB6fytw.mjs → xcode-D7sAp-Zy.mjs} +256 -103
  60. package/package.json +5 -5
  61. package/shim/bundle-response.cjs +5 -0
  62. package/dist/android-xmyGBNy5.mjs +0 -665
  63. package/dist/build-lock-vE45ZzJZ.mjs +0 -645
  64. package/dist/server-expo-rb0k-0w7.mjs +0 -2
@@ -1,4 +1,4 @@
1
- import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-BSwrY4FZ.mjs";
1
+ import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-DEJf6_kJ.mjs";
2
2
  import chalk from "chalk";
3
3
  //#endregion
4
4
  //#region src/guide/index.ts
@@ -31,6 +31,15 @@ branch that is not the default one -- only once the repository has at least
31
31
  one linked worktree, so read it from inside the worktree. A single-checkout
32
32
  session is never told that its own branch is a problem.
33
33
 
34
+ MULTIPLE DEVICES
35
+
36
+ Use ios/android --slot <name> to retain multiple devices in one workspace,
37
+ including several of the same model. Reuse the same slot name on subsequent
38
+ runs. Read guide lifecycle options for the complete slot workflow. Use the
39
+ reported device ID for UI interaction. All slots share Metro; reload can reach
40
+ multiple devices, and a shared bundle request does not prove a slot launched.
41
+ Use stop --slot <name> for one slot, or plain stop for the whole workspace.
42
+
34
43
  NORMAL WORKFLOW
35
44
 
36
45
  Work in the current checkout by default. When the task needs another branch or
@@ -64,6 +73,13 @@ Doctor reports cross-volume staging and build-cache copies; read guide settings
64
73
  for placement overrides and guide lifecycle options for warm behavior.
65
74
  For iOS Debug architecture findings, review the project's overrides and imported
66
75
  Podfile helpers using guide lifecycle options. Doctor --fix does not change them.
76
+ For parallel iOS work, review the recommended optional SimSlim setup in
77
+ stim guide lifecycle simslim. If simulator process startup times out, check
78
+ host memory pressure and free memory before retrying. Boot progress reports
79
+ current and highest observed pressure; a timeout does not establish OOM.
80
+ Avoid repeated reboots under unchanged pressure; do not restart other
81
+ workspaces' devices or close their apps without asking. That guide covers
82
+ the recovery steps and profile tradeoffs.
67
83
  For a linked native library carrying Git metadata, add the printed .git entries to
68
84
  .fingerprintignore only when the native build does not read Git state.
69
85
 
@@ -83,6 +99,21 @@ them. It preserves source, custom launcher settings, and the shared ccache.
83
99
  stim start
84
100
  stim ios # or: stim android
85
101
 
102
+ For a project using EAS development builds, read stim guide lifecycle eas to
103
+ select a profile from eas.json for the requested target, then run
104
+ stim ios --eas-profile <name> or stim android --eas-profile <name>.
105
+ Ask the user if the profile choice is ambiguous. A miss stops with
106
+ STIM_EAS_BUILD_MISSING and an EAS build command. Run that command only when the
107
+ session authorizes the potentially billable build, then retry Stim. The
108
+ presence of eas.json does not select EAS or authorize building.
109
+ Physical --device targets are supported. Follow EAS device-registration and
110
+ rebuild remedies only when the session authorizes those account changes.
111
+
112
+ Read stim guide lifecycle concurrency when a build waits on another workspace
113
+ or a build call times out. A native build can outlive a shell timeout; if the
114
+ tool call timed out, retry the same command and follow its printed remedy if
115
+ waiting times out.
116
+
86
117
  # Reproduce the affected behavior and capture the baseline errors.
87
118
  stim logs --errors
88
119
 
@@ -132,8 +163,6 @@ RULES DURING THE LOOP
132
163
  the error screen remains, follow the printed reload remedy instead of
133
164
  running ios or android again. If launch says FATAL because the app process exited,
134
165
  fix the crash and run the platform command again; Metro cannot restart it.
135
- - A native build can outlive a shell timeout. Retry the same command and
136
- follow its printed remedy if waiting times out. See guide lifecycle concurrency.
137
166
  - ios and android install the app, launch it, and check readiness. Trust the
138
167
  exact device, app, Metro, and launch facts in the final summary. Use the full
139
168
  reported device ID. Never assume a simulator named booted belongs to this
@@ -156,7 +185,9 @@ RULES DURING THE LOOP
156
185
  - Use stim status when resuming a workspace or recovering missing device,
157
186
  port, server, or build facts. A normal start and platform run already print
158
187
  them. Use stim doctor when a build is unexpectedly slow or the environment
159
- looks incomplete.
188
+ looks incomplete. If status reports a changed Android serial, rerun stim
189
+ android with the same build options to restore forwarding, then reopen your automation
190
+ session on the reported serial (guide lifecycle).
160
191
 
161
192
  OWNERSHIP AND DELETION
162
193
 
@@ -215,6 +246,34 @@ requirements.
215
246
 
216
247
  LOAD ADVANCED GUIDANCE WHEN NEEDED
217
248
 
249
+ Read the matching guide before acting in these situations:
250
+
251
+ | Situation | Read |
252
+ | ----------------------------------------------------- | -------------------------------- |
253
+ | Build waiting on another workspace or tool timeout | stim guide lifecycle concurrency |
254
+ | --variant, scheme, or several APKs from assembleDebug | stim guide lifecycle options |
255
+ | Refusal with a CODE | stim guide errors <CODE> |
256
+ | Running under a sandbox | stim guide errors sandbox |
257
+ | Release configuration or ...Release variant | stim guide lifecycle release |
258
+ | Remote device, custom Metro, or tunnel | stim guide metro |
259
+ | Cache miss, bypass, or fingerprint exclusions | stim guide lifecycle builds |
260
+ | Capacity limits | stim guide lifecycle concurrency |
261
+ | Cache statistics from stim stats | stim guide facts stats |
262
+ | Worktree carry-over | stim guide lifecycle options |
263
+ | gc or orphaned resources | stim guide cleanup gc |
264
+ | worktree remove refusal or --force | stim guide errors remove |
265
+ | Cleanup failure or unverified cleanup ownership | stim guide errors teardown |
266
+ | Unfamiliar state or JSON field | stim guide facts payloads |
267
+ | Refusal without a code | stim guide errors |
268
+
269
+ Use the CODE exactly as printed; codes sharing a header resolve to the same
270
+ section. For a refusal without a code, find its quoted message in the errors
271
+ index. Ordinary stim stop and an authorized clean stim worktree remove do not
272
+ need the cleanup guide. A sectioned topic called without a section prints its
273
+ index; choose the narrowest section.
274
+
275
+ FULL TOPIC LIST
276
+
218
277
  stim guide # list topics
219
278
  stim guide errors # index of every refusal code and message
220
279
  stim guide errors <CODE> # one refusal, e.g. stim guide errors STIM_NO_METRO
@@ -235,23 +294,17 @@ LOAD ADVANCED GUIDANCE WHEN NEEDED
235
294
  stim guide logs # filters, record shape, and capture limits
236
295
  stim guide cleanup # what reclaims a device, and what deletes
237
296
  stim guide cleanup collector # an unproven collector pid; why the app on a phone closed
238
- stim guide settings # configuration files and supported keys
239
-
240
- A refusal prints a CODE such as STIM_NO_METRO. Run stim guide errors <CODE>
241
- with the code exactly as printed and read only that section; every code in a
242
- shared header (STIM_BAD_ARG / STIM_NO_PROJECT) resolves to the same section. A
243
- refusal with no code is quoted by message in stim guide errors. A topic with
244
- sections called bare prints its section index, so read the narrowest section
245
- before release configurations or Android variants; remote devices; custom
246
- Metro processes or tunnels; cache misses, bypasses, or concurrent builds;
247
- capacity limits; cache statistics from stim stats; worktree carry-over;
248
- fingerprint exclusions; gc; --force; cleanup failures; or unfamiliar states
249
- and error codes. Ordinary stim stop and an authorized clean
250
- stim worktree remove do not need the cleanup guide.`
297
+ stim guide settings # configuration files and supported keys`
251
298
  },
252
299
  facts: {
253
300
  summary: "The --json payloads: `start`, `ios`, `android`, `reload`, `stop`, `status`, `doctor`, `device lock`/`unlock`, and the error contract",
254
- preamble: () => `FACTS CONTRACT
301
+ preamble: () => `SLOTS
302
+ Named ios/android runs add slot to their JSON facts. Default-run fields remain
303
+ compatible. status adds a slots array per environment with each named slot's
304
+ ios/android device facts; top-level ios/android still describe default.
305
+ Named collector, lease-holder, and launch keys use platform:slot internally.
306
+
307
+ FACTS CONTRACT
255
308
 
256
309
  \`start\`, \`ios\`, \`android\`, \`reload\`, \`stop\`, \`status\`, \`stats\`, \`doctor\`,
257
310
  and \`device lock\`/\`device unlock\` each print exactly ONE line of JSON on
@@ -315,6 +368,11 @@ line by design (see \`guide logs\`), not this single-payload contract.`,
315
368
  absent for automatic selection; not the app URL scheme
316
369
  cacheKey the shared-build-cache key derived from it (the
317
370
  configuration is part of it: -release-sim vs -debug-sim)
371
+ With --eas-profile, fingerprint is computed by EAS CLI using the selected
372
+ profile/environment, and cacheKey identifies the EAS project and build ID
373
+ separately from local native builds. cacheHit is "remote" for the EAS
374
+ source, including when EAS CLI reuses its own downloaded artifact cache.
375
+
318
376
  cacheHit WHICH LEVEL answered, not a boolean:
319
377
  "local" this machine's shared cache (free, instant)
320
378
  "remote" the project's own Expo buildCacheProvider (a
@@ -705,6 +763,30 @@ Plain \`stim start\` is local and does not create a public tunnel. Remote intent
705
763
  comes from \`start --remote\`, \`ios.remote\`, or \`android.remote\`. The
706
764
  \`metro.tunnel\` setting selects the provider after remote intent exists.
707
765
 
766
+ BUNDLE WARMUP
767
+ After verifying Metro, \`stim ios\` and \`stim android\` prefetch the
768
+ platform's development bundle while native work continues. Expo supplies the
769
+ entry point and bundle options through its manifest; bare React Native uses
770
+ the standard index entry and development bundle options, including lazy loading.
771
+ Warmup is enabled by default. Set optimizations.metroWarmup=false to disable
772
+ it on the next ios/android command, using the machine or project settings.
773
+ For custom entry points or bundle options, set metro.warmupUrl.ios and/or
774
+ metro.warmupUrl.android to the app's complete bundle URL or /path?query.
775
+ Stim keeps the path and query and uses the verified local Metro port.
776
+ Overrides replace discovery and receive no additional query defaults.
777
+ doctor validates configured URLs, including their platform; it does not
778
+ infer or auto-fix runtime native entry points or dev-menu bundle options.
779
+ See \`guide settings\` for configuration examples.
780
+ Each request times out after 60 seconds and does not keep the command alive.
781
+ Warmup failures do not fail the native build.
782
+ Release builds and \`--no-metro-check\` skip warmup. Servers without Stim's
783
+ prefetch-aware response observer also skip it; restart an older supervisor
784
+ with the current CLI to enable warmup.
785
+
786
+ Prefetch completion is not launch proof. Development launch verification
787
+ waits for the app's own bundle response. With a bundler started outside Stim,
788
+ device logs may prove a request, but bundle completion may stay unverified.
789
+
708
790
  REMOTE DEVICE BACKENDS
709
791
  Metro exposure and device selection are separate:
710
792
 
@@ -824,7 +906,13 @@ one dim note on STDERR reading \`No matching log records in <logs dir>\`
824
906
  (human mode only -- \`--json\` prints nothing at all, on either stream).
825
907
  The only exit-1 paths are a malformed query and no project.
826
908
 
909
+ Device collectors and build records carry their named slot. Use --slot phone
910
+ for that slot's timeline; its launch marker cannot hide a sibling's errors.
911
+ Untagged legacy records belong to default. Metro/client records are shared and
912
+ usually untagged: use an unfiltered workspace query to inspect those errors.
913
+
827
914
  FLAGS
915
+ --slot <name> only this slot's records (default includes untagged records)
828
916
  --source <s...> metro, client, device, build (one or more), or all. An
829
917
  unknown value is REJECTED rather than quietly matching
830
918
  nothing.
@@ -1088,6 +1176,24 @@ WHAT WRITES WHAT
1088
1176
  Every refusal from \`ios\` / \`android\` carries a stable CODE. Branch on the
1089
1177
  code, never on the message.`,
1090
1178
  sections: {
1179
+ STIM_EAS_BUILD_MISSING: {
1180
+ summary: "no completed EAS development build matches; build only with session authorization",
1181
+ body: () => `STIM_EAS_BUILD_MISSING
1182
+ No compatible build matches the selected EAS project, profile, platform and
1183
+ native fingerprint. No device was acquired and no local or cloud build was
1184
+ started. The remedy prints the exact npx eas-cli build command. Check session
1185
+ authorization for its potential cost before running it, then retry Stim.
1186
+ See stim guide lifecycle eas.`
1187
+ },
1188
+ STIM_EAS_UNAVAILABLE: {
1189
+ summary: "EAS lookup/download failed, or another run holds the artifact claim",
1190
+ body: () => `STIM_EAS_UNAVAILABLE
1191
+ EAS CLI is unavailable, a profile/fingerprint/list/download operation failed,
1192
+ the response could not be validated, or another run holds the artifact claim.
1193
+ Follow the printed remedy: inspect the named EAS command or retry once the
1194
+ holder finishes. This is not proof that a build is missing. No native build
1195
+ is started. See stim guide lifecycle eas.`
1196
+ },
1091
1197
  STIM_WORKSPACE_STATE: {
1092
1198
  summary: "$STIM_HOME/workspaces could not be prepared, or the digest directory belongs to another project",
1093
1199
  aliases: ["STIM_WORKSPACE_COLLISION"],
@@ -1355,6 +1461,11 @@ code, never on the message.`,
1355
1461
  body: () => `STIM_LAUNCH_FAILED
1356
1462
  Installed, but the app would not start. On Android this usually means no
1357
1463
  launchable activity resolved.
1464
+ On a local iOS simulator, a timed-out launch can mean the simulator cannot
1465
+ spawn processes, even while it reports Booted. Check the reported memory
1466
+ pressure and free host memory before retrying; a timeout alone is not an OOM
1467
+ diagnosis. See \`stim guide lifecycle simslim\` for recovery and the optional
1468
+ SimSlim recommendation.
1358
1469
  On a PHONE it means the app never appeared in the device's own process list
1359
1470
  after \`devicectl device process launch\`, and the devicectl lines that
1360
1471
  explain it are quoted under the message. The refusal a first launch usually
@@ -1409,7 +1520,10 @@ spending a build or a bundle, that the check can succeed.`,
1409
1520
  profile;
1410
1521
  - it is a development or ad hoc profile whose device list does not name
1411
1522
  this UDID. Register the UDID at developer.apple.com, regenerate the
1412
- profile, and build once from Xcode.`
1523
+ profile, and build once from Xcode.
1524
+ With --eas-profile, follow the EAS device:create and build commands in the
1525
+ refusal instead. Registration, signing changes and cloud builds need session
1526
+ authorization. See stim guide lifecycle eas.`
1413
1527
  },
1414
1528
  STIM_NO_SIGNING_IDENTITY: {
1415
1529
  summary: "no single keychain identity resolves; ios.signingIdentitySha1 for two certificates",
@@ -1578,9 +1692,21 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
1578
1692
  reach a booted state. \`stim doctor\` checks the toolchain; \`stim status\` says what
1579
1693
  Stim thinks it owns. Re-running the command creates a fresh owned device
1580
1694
  when the recorded one is gone.
1695
+ If Android creation says an AVD already exists on disk but is not listed,
1696
+ run \`npx stim gc\` to inspect orphaned owned AVDs, then \`npx stim gc --delete\`
1697
+ to reclaim those safe to delete before retrying. Keep anything GC cannot
1698
+ verify; do not delete AVD directories by hand. A registered unrecorded owned
1699
+ AVD is recovered, reusing its existing emulator when its identity is verified.
1700
+ If recovery cannot verify registration or process state, inspect \`npx stim status\`
1701
+ and \`adb devices\`, then retry after any other run finishes. Keep the AVD and
1702
+ its process locks while its state is unverified.
1581
1703
  On iOS a slow first boot is waited out for up to ten minutes while the
1582
- simulator still reports Booting -- a long silent wait on a loaded machine
1583
- is patience, not a hang. The failure names the udid and the wait.
1704
+ simulator reports Booting or Booted but bootstatus has not completed.
1705
+ Booted alone does not end that wait. The failure names the udid and the wait.
1706
+ After boot, a process-spawn probe must finish within 30 seconds before
1707
+ installation. If it fails, the refusal includes observed host memory pressure
1708
+ when available. Free memory before retrying under pressure; see
1709
+ \`stim guide lifecycle simslim\`. Booted alone does not prove readiness.
1584
1710
  On Android the emulator's own stdio is captured to
1585
1711
  the global workspace logs/emulator.log (truncated per boot), and when it printed a
1586
1712
  \`FATAL |\` / \`ERROR |\` / \`PANIC:\` line THAT is the message and the remedy
@@ -2116,9 +2242,11 @@ changes nothing (worktree warm --refresh)
2116
2242
  blocks network egress by default, which breaks a cache lookup and a fetch.
2117
2243
 
2118
2244
  \`stim doctor\` names this when a write to STIM_HOME actually fails, not
2119
- merely when a harness that can sandbox is present, and
2120
- \`stim doctor --fix\` writes the three keys into .claude/settings.local.json,
2121
- the per-user file, merging with what is there. It refuses under Codex, which
2245
+ merely when a harness that can sandbox is present. \`stim doctor --fix\`
2246
+ writes only when the report shows that finding, and only what the finding
2247
+ names: the three keys, into .claude/settings.local.json, the per-user file,
2248
+ merging with what is there. A report without the finding, with or without
2249
+ --platform, leaves that file alone. It refuses under Codex, which
2122
2250
  has no per-path allowance to add, and refuses any settings file it cannot
2123
2251
  parse rather than replace it: comments make one unparseable here even though
2124
2252
  Claude Code accepts them. Claude Code reads project settings from the
@@ -2293,6 +2421,21 @@ If the app is stuck before loading its first bundle, restart its process with
2293
2421
  the printed force-stop and launcher commands. Foregrounding the same process
2294
2422
  does not restart initialization. Confirm the bundle request and expected UI.
2295
2423
 
2424
+ Debug Android launches on an owned emulator created in the same run get up to
2425
+ 60 seconds for bundle loading; the verify phase names that budget. Existing
2426
+ emulators, remote targets, and physical devices keep the 20-second budget.
2427
+ Bundle delivery still requires the usual stability or app readiness check;
2428
+ an observed fatal error ends verification without waiting for the deadline.
2429
+
2430
+ ANDROID EMULATOR RESTARTS
2431
+ \`stim status\` resolves owned AVDs to their currently detected adb serial.
2432
+ Its Android JSON adds serial and state (detected, not-detected, missing,
2433
+ or unknown). Detection confirms device identity, not app health. Status
2434
+ reports a serial change without changing forwarding or restarting anything.
2435
+ Rerun \`stim android\` with the same build options in that workspace to restore Metro
2436
+ forwarding, then reopen agent-device on the serial that run reports.
2437
+ Other workspaces' simulators and automation sessions remain theirs.
2438
+
2296
2439
  DESTRUCTIVE COMMANDS -- ask the user first
2297
2440
  gc --delete deletes orphaned stim-* devices, tens of GB
2298
2441
  gc --delete --cache all empties the shared build caches every project uses
@@ -2319,6 +2462,82 @@ TWO REPORTS, TWO QUESTIONS
2319
2462
  the machine, with a hit rate and an estimate of the time saved (see
2320
2463
  \`guide facts stats\`).`,
2321
2464
  sections: {
2465
+ eas: {
2466
+ summary: "download a matching EAS development build; explicit profile, costs, cache and miss remedies",
2467
+ body: () => `EAS DEVELOPMENT BUILDS
2468
+
2469
+ stim ios --eas-profile ios-simulator
2470
+ stim android --eas-profile development
2471
+ stim ios --eas-profile development-device --device <udid>
2472
+ stim android --eas-profile development --device <serial>
2473
+
2474
+ An eas.json file does not select EAS automatically. The flag names the profile
2475
+ and selects EAS Build as the artifact source. The profile must resolve to
2476
+ "developmentClient": true and "distribution": "internal". For iOS, set
2477
+ "ios.simulator": true for a simulator, or false (or omit it) for --device.
2478
+ An explicit ios.buildConfiguration must be Debug;
2479
+ android.gradleCommand must be a single :app:assemble<Variant>Debug task producing
2480
+ an APK. Install eas-cli and authenticate with eas login
2481
+ or EXPO_TOKEN. The Expo app must already be linked to the intended EAS project.
2482
+
2483
+ Use the profile the user names. Otherwise inspect eas.json, including extends
2484
+ and platform overrides, for the requested platform, simulator or physical
2485
+ device, and app variant or environment. Choose a profile only when those
2486
+ requirements identify one compatible development profile. If there is no
2487
+ compatible profile or the choice is ambiguous, ask the user. Profile names
2488
+ alone do not establish compatibility. Confirm the resolved settings with
2489
+ npx eas-cli config --platform <ios|android> --profile <name> --json --non-interactive.
2490
+ Pass the selected name to --eas-profile; the CLI does not infer it.
2491
+
2492
+ Stim delegates profile inheritance, environment resolution and fingerprinting
2493
+ to EAS CLI. fingerprint:generate uploads fingerprint metadata to EAS. It does
2494
+ not start a native build. EAS access is needed even when the artifact is
2495
+ already cached, because the current profile and fingerprint must be resolved.
2496
+
2497
+ Stim matches the EAS project, profile, native fingerprint, platform and
2498
+ simulator/internal distribution target against a completed build. It downloads
2499
+ an iOS .app or Android .apk with EAS CLI, then uses its existing installation,
2500
+ Metro connection, log capture and launch verification on the selected device.
2501
+ The flag also works with --remote; remote EAS Simulator sessions have their
2502
+ own costs, independent of this download path. Local --scheme, --configuration,
2503
+ --variant and --no-build-cache selectors
2504
+ cannot be combined with --eas-profile. Local configuration/variant defaults
2505
+ are ignored for this development-build run.
2506
+
2507
+ Physical devices use Stim's usual selection and lease rules. An iOS app must
2508
+ have a development-client URL scheme and a valid embedded provisioning profile
2509
+ that includes the target UDID. Stim installs the signed app without re-signing
2510
+ it. If the profile does not admit the device, the remedy points to
2511
+ npx eas-cli device:create and npx eas-cli build --platform ios --profile <name>.
2512
+ Registration, signing changes and cloud builds need session authorization.
2513
+ Run the EAS build interactively when its provisioning profile needs refreshing,
2514
+ then retry the same Stim command.
2515
+
2516
+ Start Metro with stim start as usual. Metro uses the local workspace's
2517
+ environment; arrange the appropriate local variables before starting it.
2518
+ EAS environment resolution for native fingerprinting does not configure Metro.
2519
+
2520
+ EAS CLI caches extracted artifacts by project and build ID in its own temporary
2521
+ cache. Stim calls build:download and uses the returned artifact without making
2522
+ another cache copy. Every run queries the latest matching build, so a rebuild
2523
+ with a refreshed provisioning profile is selected even if its native fingerprint
2524
+ is unchanged. Stim coordinates concurrent downloads by project and build ID.
2525
+ cacheHit: "remote" identifies the EAS source, including when EAS CLI reuses its
2526
+ disk cache. The fingerprint fact is the EAS native fingerprint. Stim's local
2527
+ buildCache and remoteBuildCache settings do not control EAS CLI's cache.
2528
+ EAS cache files are managed by EAS CLI and are outside Stim gc.
2529
+
2530
+ On STIM_EAS_BUILD_MISSING, Stim stops before acquiring a device and prints:
2531
+
2532
+ npx eas-cli build --platform ios --profile ios-simulator
2533
+
2534
+ Run that command only when the session authorizes the potentially billable
2535
+ cloud build. Once it completes, retry the same Stim command. No build-on-miss
2536
+ flag exists, and Stim never starts a cloud build or falls back to local
2537
+ compilation in this mode. Authentication, network, invalid output or download
2538
+ failures produce STIM_EAS_UNAVAILABLE, with the failed EAS command to inspect.
2539
+ If another run holds the artifact claim, wait for it to finish and retry.`
2540
+ },
2322
2541
  readiness: {
2323
2542
  summary: "implement optional pending/ready app logs, deadlines, errors, and platform isolation",
2324
2543
  body: () => `OPTIONAL APP READINESS
@@ -2474,7 +2693,7 @@ result as proof instead of requiring an unrelated screenshot.`
2474
2693
  build still compiling (4m00s, usually ~3m10s)
2475
2694
  build still compiling (1m00s)
2476
2695
  pods still installing (1m30s of ~1m40s)
2477
- build waiting on /w/app-411 (pid 41233, 1m30s elapsed)
2696
+ build waiting on /w/app-411 (pid 41233, 1m30s elapsed) -- stim guide lifecycle concurrency
2478
2697
 
2479
2698
  The \`~\` value is an estimate, never a countdown; the third line is a
2480
2699
  project with no record to estimate from yet. \`guide facts stats\` says where
@@ -2490,7 +2709,7 @@ result as proof instead of requiring an unrelated screenshot.`
2490
2709
  step, before those. A plain warm prints the \`lock\` line only when its copy
2491
2710
  actually waited for another warm:
2492
2711
 
2493
- lock acquired (waited 12s for stim worktree warm --refresh pid 41233)
2712
+ lock acquired (waited 12s for stim worktree warm --refresh pid 41233) -- stim guide lifecycle options
2494
2713
  checkout janic/wip 2 commits behind origin/janic/wip -> fast-forwarded to 4b81e0c
2495
2714
  not the default branch (main); worktrees seeded from this copy
2496
2715
  carry janic/wip's dependencies
@@ -2498,7 +2717,7 @@ result as proof instead of requiring an unrelated screenshot.`
2498
2717
  pods source /w/main/apps/mobile: ios/Podfile.lock changed -> pod install (1m12s)
2499
2718
 
2500
2719
  A wait reports how long this caller has waited and names the holder:
2501
- \`lock waiting 40s for stim worktree warm --refresh (pid 41233)\`.
2720
+ \`lock waiting 40s for stim worktree warm --refresh (pid 41233) -- stim guide lifecycle options\`.
2502
2721
 
2503
2722
  \`start\` names the port, the supervisor mode and its pid on one line
2504
2723
  (\`metro starting on port 8083 (expo-child, supervisor pid 13724)\`),
@@ -2744,7 +2963,7 @@ changing modes selects another profile. See \`guide settings\` for cleanup.
2744
2963
 
2745
2964
  Each reports its cache setup. \`stim doctor\` checks missing or stale setup
2746
2965
  when a build is blocked or slow. It reports what Stim cannot handle itself
2747
- (a missing dev client, ccache absent from PATH or a .cxx that predates the
2966
+ (ccache absent from PATH or a .cxx that predates the
2748
2967
  launcher, a fingerprint no fresh worktree reproduces, a provider on a key this
2749
2968
  SDK ignores) and settings for builds outside Stim.
2750
2969
 
@@ -2926,9 +3145,9 @@ WHAT MAKES THE CACHE ACTUALLY HIT: .FINGERPRINTIGNORE
2926
3145
  <fingerprint, platform> (a directory under ~/.stim/build-locks). Exactly
2927
3146
  one workspace compiles; the others print
2928
3147
 
2929
- build /w/app-412 is already building a3f9b1.. (pid 41233) -- tail ...
2930
- build waiting on /w/app-412 (pid 41233, 4m elapsed) -- tail ...
2931
- build waited 12m41s for /w/app-412's build -> installed from cache
3148
+ build /w/app-412 is already building a3f9b1.. (pid 41233) -- tail ... -- stim guide lifecycle concurrency
3149
+ build waiting on /w/app-412 (pid 41233, 4m elapsed) -- tail ... -- stim guide lifecycle concurrency
3150
+ build waited 12m41s for /w/app-412's build -> installed from cache -- stim guide lifecycle concurrency
2932
3151
 
2933
3152
  and install the artifact the builder stored. They report cacheHit: "local"
2934
3153
  plus waitedForBuild: { pid, ms }.
@@ -2997,13 +3216,13 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
2997
3216
  summary: "every flag per command, Android variants and flavors, the per-run simulator model, runtime and system image",
2998
3217
  body: () => `THE OPTION SURFACE, IN FULL
2999
3218
  start --json --wait <seconds> --remote --reset-cache
3000
- ios --json --no-metro-check --no-build-cache --scheme <name> --configuration <name> --device-type <name> --runtime <version> --device [udid] --wait <seconds> --no-wait --remote <proxy|eas>
3001
- android --json --no-metro-check --no-build-cache --variant <name> --system-image <id> --device [serial] --wait <seconds> --no-wait --remote <proxy|eas>
3219
+ ios --slot <name> --json --no-metro-check --no-build-cache --scheme <name> --configuration <name> --device-type <name> --runtime <version> --device [udid] --wait <seconds> --no-wait --remote <proxy|eas>
3220
+ android --slot <name> --json --no-metro-check --no-build-cache --variant <name> --system-image <id> --device [serial] --wait <seconds> --no-wait --remote <proxy|eas>
3002
3221
  reload [ios|android] --json
3003
- device lock <ios|android> [id] --for <duration> --wait <seconds> --json;
3004
- unlock [ios|android] --json
3005
- logs --source --level --since --grep --tail --follow --errors --json
3006
- stop --json
3222
+ device lock <ios|android> [id] --slot <name> --for <duration> --wait <seconds> --json;
3223
+ unlock [ios|android] --slot <name> --json
3224
+ logs --slot <name> --source --level --since --grep --tail --follow --errors --json
3225
+ stop --slot <name> --json
3007
3226
  status --json (already machine-wide)
3008
3227
  stats --json (this project and machine-wide)
3009
3228
  doctor --json --fix --platform <ios|android>
@@ -3011,6 +3230,38 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3011
3230
  gc --delete --older-than <days> --cache <name|all>
3012
3231
  worktree warm --refresh; remove [path] --force
3013
3232
 
3233
+ DEVICE SLOTS
3234
+ Use --slot <name> on ios or android to keep any number of simulators,
3235
+ emulators, or physical devices in the same workspace. Names are reusable
3236
+ identities, not models: two slots can request identical models. A slot has
3237
+ one target per platform. Omitting the flag selects default and preserves
3238
+ the workspace's existing assignment.
3239
+
3240
+ stim ios --slot phone
3241
+ stim ios --slot tablet --device-type "iPad Pro 13-inch (M4)"
3242
+ stim ios --slot hardware --device <udid>
3243
+ stim android --slot second-phone
3244
+ stim logs --slot tablet --source device
3245
+ stim stop --slot tablet
3246
+
3247
+ All slots share this workspace's Metro server and build cache. Native CLI
3248
+ runs serialize workspace mutations; a waiting run can wait up to 30 minutes.
3249
+ Named slots support local devices; remote sessions use the default slot.
3250
+ Names use 1-64 letters, digits, underscores or hyphens, starting with a letter
3251
+ or digit. Reserved object-property names are refused.
3252
+
3253
+ stop --slot shuts down that slot's owned devices and releases its leases,
3254
+ retaining Metro and sibling slots. Plain stop handles the whole workspace.
3255
+ status reports named devices under slots and counts their memory. Device
3256
+ caps count every slot. Recycling uses the same model/runtime-matched pool
3257
+ for every slot, with one shared cap per platform and oldest-first eviction.
3258
+
3259
+ Metro cannot reliably identify a particular simulator's bundle request.
3260
+ When slots coexist, a shared bundle event is not proof that a particular
3261
+ slot launched: Debug launch can report unverified. Check the reported device
3262
+ directly. Release verification still checks its process. reload ios/android
3263
+ addresses matching Metro peers across slots; it is not a single-slot reload.
3264
+
3014
3265
  That is the whole surface today, and it is deliberately small. It can grow
3015
3266
  when a flag is genuinely the best answer -- but project-specific knowledge
3016
3267
  (release builds, variants, device targets) belongs in a script the repo owns,
@@ -3096,10 +3347,27 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3096
3347
  paths eligible under the source checkout's Git ignore rules, including .env
3097
3348
  and local configuration. The source's nonempty
3098
3349
  .worktreeexclude replaces its resolved worktree.exclude setting. Nested
3099
- registered worktrees, .DerivedData, and android/build/generated/autolinking
3100
- caches are excluded, including in nested apps. Gradle regenerates autolinking
3350
+ registered worktrees, .DS_Store, .DerivedData, .idea, and
3351
+ android/build/generated/autolinking caches are excluded, including inside
3352
+ newly copied directories. Gradle regenerates autolinking
3101
3353
  for the destination checkout on its next build. Warm also skips paths
3102
3354
  overlapping a nested destination worktree or below a symlink ancestor.
3355
+ Tracked .idea settings come from Git and stay untouched by warm.
3356
+
3357
+ Other generated state stays eligible: .gradle, .cxx, *.tsbuildinfo, build
3358
+ directories, and embedded JavaScript need project-specific decisions about
3359
+ regeneration. Native intermediates can record the source checkout's paths;
3360
+ warm does not relocate them. Excluding the whole .expo directory can drop
3361
+ generated TypeScript inputs.
3362
+
3363
+ To choose exclusions, run this in the source checkout's repository root:
3364
+
3365
+ git ls-files --others --ignored --exclude-standard --directory --no-empty-directory
3366
+
3367
+ Patterns match those entries with the trailing / removed. They do not prune
3368
+ children of a whole ignored directory: if Git lists android/app/src/main/assets/,
3369
+ excluding its bundle.jsbundle child has no effect. Exclude the assets entry
3370
+ only when the project regenerates everything inside it.
3103
3371
 
3104
3372
  Warm copies directly into the destination, without intermediate staging.
3105
3373
  Keep the source checkout and the linked worktree on the same volume to
@@ -3451,28 +3719,85 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
3451
3719
  \`.ipa\` export, store signing and distribution stay out of scope.`
3452
3720
  },
3453
3721
  simslim: {
3454
- summary: "installing SimSlim and what ios.simslimProfile does to an owned simulator",
3455
- body: () => `OPTIONAL SIMSLIM PROFILE
3722
+ summary: "recommended SimSlim profiles and recovery from host memory pressure",
3723
+ body: () => `SIMSLIM FOR PARALLEL IOS WORK
3724
+ SimSlim is recommended as an optional way to reduce simulator background
3725
+ services and memory use, especially with several workspaces. Review which
3726
+ services your app and tests need; a slim profile can disable those features.
3727
+ It does not guarantee that a memory stall or crash will be fixed.
3728
+
3456
3729
  Install SimSlim once on each Mac:
3457
3730
 
3458
3731
  brew install mobai-app/tap/simslim
3459
3732
 
3460
- Then commit a profile and select it in .stim.json:
3733
+ Review the categories and create a profile in an interactive terminal:
3734
+
3735
+ simslim profiles
3736
+ mkdir -p .simslim
3737
+ simslim profile .simslim/dev.json
3738
+
3739
+ Selected categories in the wizard stay enabled. The wizard writes the
3740
+ profile without applying it. Review and commit it, then select it in .stim.json:
3461
3741
 
3462
3742
  { "ios": { "simslimProfile": ".simslim/dev.json" } }
3463
3743
 
3464
- SimSlim requires an iOS 18 or newer simulator. On each local \`stim ios\`,
3744
+ SimSlim 0.8 requires iOS 18.5 or newer. On each local \`stim ios\`,
3465
3745
  Stim reconciles that profile on the owned simulator before the app build.
3466
3746
  The first change can update services and reboot the simulator. A matching
3467
3747
  profile is a fast no-op on later launches. The settings persist across normal
3468
3748
  shutdowns and reboots. Removing the setting restores stock services when
3469
- Stim applied the profile. Stim never changes an unowned or remote simulator.`
3749
+ Stim applied the profile. Stim never changes an unowned or remote simulator.
3750
+ Each SimSlim operation has a 12-minute outer deadline, including discovery.
3751
+ This cap also applies when SimSlim's own timeout is increased. On timeout,
3752
+ Ctrl-C, or SIGTERM, Stim attempts to stop only its verified process group, then waits up to
3753
+ 10 seconds to confirm termination before returning or exiting.
3754
+ An unconfirmed process group keeps its claim and blocks another reconciliation;
3755
+ inspect the named processes before removing the exact claim in the error.
3756
+ The simulator's managed settings record is retained, so retrying reconciles an
3757
+ interrupted apply or restore. Stim does not assume partial changes rolled back.
3758
+ Doctor recommends this setup but never installs SimSlim or applies a profile.
3759
+ Profile schema and service tradeoffs: https://github.com/MobAI-App/simslim
3760
+
3761
+ HOST MEMORY PRESSURE AND STALLED SIMULATORS
3762
+ Booted and a working screenshot do not prove that simulator processes can
3763
+ start. Stim checks a bounded process spawn before install and bounds local
3764
+ simulator launch operations. Simulator discovery waits up to 30 seconds,
3765
+ boot (including the initial boot request) up to 10 minutes, and app installation
3766
+ up to 5 minutes. Process termination confirmation can take another 10 seconds;
3767
+ a final boot-state query can take 30 seconds. Opening the Simulator app after
3768
+ boot is best-effort and takes at most 5 seconds. A timeout is not proof of an
3769
+ app crash or OOM.
3770
+ During boot, Stim reports elapsed time, the simulator name, last boot output,
3771
+ current pressure and the highest observed pressure roughly every 15 seconds.
3772
+ Failure diagnostics retain the highest pressure and unavailable sample count;
3773
+ they do not infer the cause of a timeout. Monitoring stops when boot ends.
3774
+ Monitoring and timeout handling are best-effort: synchronous CLI work can
3775
+ delay them. Diagnostics report observation gaps over 30 seconds; pressure
3776
+ during a gap is unobserved, even when the surrounding readings are normal.
3777
+ Doctor and failure diagnostics report macOS memory pressure when available;
3778
+ a failed query remains unknown. Existing swap or low free RAM alone is not
3779
+ enough to diagnose pressure.
3780
+
3781
+ If pressure is elevated, free host memory before retrying. Use \`stim stop\`
3782
+ only in workspaces you own and have finished using; ask before closing other
3783
+ agents' simulators or heavy apps. Rebooting a simulator under the same pressure
3784
+ can repeat the stall. Consider fewer concurrent builds/devices (guide lifecycle
3785
+ concurrency) and a reviewed SimSlim profile for future runs.`
3470
3786
  }
3471
3787
  }
3472
3788
  },
3473
3789
  cleanup: {
3474
3790
  summary: "Where simulators come from, and how they get reclaimed",
3475
- preamble: () => `CLEANUP AND DISK
3791
+ preamble: () => `DEVICE SLOTS
3792
+
3793
+ Cleanup enumerates every slot. stop --slot <name> keeps the shared server and
3794
+ other slots; plain stop and worktree remove handle the whole workspace.
3795
+ An upgrade retains existing device assignments as the default slot. Do not
3796
+ wipe state to upgrade: it records ownership needed for safe teardown. Use the
3797
+ same slot-aware CLI for all commands while named assignments exist; older
3798
+ versions cannot reliably manage their assignments.
3799
+
3800
+ CLEANUP AND DISK
3476
3801
 
3477
3802
  WHAT RECLAIMS AN OWNED DEVICE
3478
3803
  stim worktree remove parks eligible owned simulators and emulators
@@ -3527,6 +3852,18 @@ If a delete fails, the device's config record is KEPT and the command reports
3527
3852
  it. A record is what makes the device findable again, so it outlives a failed
3528
3853
  teardown rather than turning it into an orphan.
3529
3854
 
3855
+ ANDROID DATA WITHOUT A REGISTRATION
3856
+ \`gc\` also reports stim-*.avd directories whose .ini registration is
3857
+ gone. \`gc --delete\` rechecks the directory, emulator process locks, and
3858
+ current workspace and pool references before removing that data. A registration
3859
+ under any name that points at the directory protects it. User AVDs, symlinks
3860
+ and unverifiable storage stay. The no-config and scoped-STIM_HOME
3861
+ sweep guards apply to these directories too.
3862
+ A partial avdmanager deletion is a failure even if the tool exits successfully.
3863
+ The owning workspace or pool record stays for a retry. If removing orphan
3864
+ data fails, its remaining directory is reported as stim-gc-<id>.avd on the
3865
+ next sweep.
3866
+
3530
3867
  BUILD LOCKS
3531
3868
  \`gc\` also reports the single-flight build locks (above): the ones whose
3532
3869
  builder is no longer running are debris a reboot or a kill left behind, and
@@ -3777,7 +4114,9 @@ KEYS STIM READS
3777
4114
  at most 64 KiB. Install the
3778
4115
  external tool once with
3779
4116
  \`brew install mobai-app/tap/simslim\`. SimSlim requires
3780
- an iOS 18 or newer simulator. Each local \`stim ios\`
4117
+ iOS 18.5 or newer in SimSlim 0.8. Recommended for parallel
4118
+ iOS work after reviewing service tradeoffs; see
4119
+ \`stim guide lifecycle simslim\`. Each local \`stim ios\`
3781
4120
  reconciles the profile on its Stim-owned simulator.
3782
4121
  The first change can reboot it; a matching profile is a
3783
4122
  fast no-op. Removing the setting restores stock services
@@ -3814,7 +4153,10 @@ KEYS STIM READS
3814
4153
  -- the sdkmanager package id the owned AVD is created
3815
4154
  from. The \`--system-image\` flag overrides this per
3816
4155
  invocation, and an id this SDK has not installed is
3817
- STIM_BAD_ARG with the installed ids printed
4156
+ STIM_BAD_ARG with the installed ids printed.
4157
+ New AVDs use the Pixel 6 hardware profile (1080x2400,
4158
+ 420 dpi). Existing AVDs keep their display settings;
4159
+ parked AVDs from the old generic profile are not adopted.
3818
4160
  android.dataPartitionSizeGb
3819
4161
  whole GiB for a newly created owned AVD's data
3820
4162
  partition. Defaults to 8; accepts 6 through 16384.
@@ -3894,6 +4236,25 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
3894
4236
  did not create it, so a Metro request through it is
3895
4237
  still gated the same way a managed tunnel's is. Set it
3896
4238
  before Expo start so the manifest advertises it.
4239
+ metro.warmupUrl optional object with per-platform bundle URLs:
4240
+ metro.warmupUrl.ios
4241
+ metro.warmupUrl.android
4242
+ an HTTP(S) URL or a /path ending in .bundle, with the
4243
+ full query the app uses, including a matching platform.
4244
+ Unset uses Expo's manifest or bare React Native defaults.
4245
+ Stim preserves the path and query but always requests
4246
+ this workspace's verified local Metro port; a supplied
4247
+ host and port are ignored. No defaults are added to an
4248
+ override. This only configures prefetch, not the app.
4249
+ For example, in .stim.json:
4250
+ { "metro": { "warmupUrl": {
4251
+ "ios": "/src/main.bundle?platform=ios&dev=true&lazy=true"
4252
+ } } }
4253
+ Use the app's complete request for custom options.
4254
+ URLs must encode spaces and omit fragments. doctor
4255
+ validates the shape and platform but cannot discover
4256
+ runtime entry-point or dev-menu overrides or auto-fix
4257
+ them. See \`guide metro\` for warmup behavior.
3897
4258
  worktree.exclude ignored-path skip list for worktree warm. Settings
3898
4259
  come from the source checkout's repository-root
3899
4260
  .stim.json. A nonempty .worktreeexclude in the source
@@ -4044,6 +4405,7 @@ key inherits the next layer. Changes apply on the next build or Metro restart.
4044
4405
  "remoteBuildCache": true,
4045
4406
  "releaseBundleSwap": true,
4046
4407
  "metroSharedCache": true,
4408
+ "metroWarmup": true,
4047
4409
  "ios": {
4048
4410
  "compilationCache": true,
4049
4411
  "swiftCompilationCache": false,
@@ -4075,6 +4437,11 @@ The example shows the defaults. Full setting names and behavior:
4075
4437
  false stops Stim appending its shared Metro store on both dev servers.
4076
4438
  Project-configured stores remain the project's choice. Replace the removed
4077
4439
  machine setting caches.injectMetroStore=false with this setting set false.
4440
+ optimizations.metroWarmup
4441
+ true by default. false skips background development bundle requests during
4442
+ ios/android, including any metro.warmupUrl override. Metro verification and
4443
+ native builds still run. Applies on the next ios/android command; no Metro
4444
+ restart is needed.
4078
4445
  optimizations.ios.compilationCache
4079
4446
  controls Xcode compilation caching (Xcode 26+).
4080
4447
  optimizations.ios.swiftCompilationCache