stim 1.1.0 → 1.2.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 (59) hide show
  1. package/README.md +7 -0
  2. package/dist/{android-CC5bUer7.mjs → android-BW8i_YxU.mjs} +1 -1
  3. package/dist/{android-DnZlT3aU.mjs → android-Bcmev2s2.mjs} +86 -31
  4. package/dist/{android-xmyGBNy5.mjs → android-K63_0UfF.mjs} +77 -15
  5. package/dist/{android-cas-DGlTStWu.mjs → android-cas-D6HPZ6UQ.mjs} +6 -6
  6. package/dist/android-cas-compiler.mjs +1 -1
  7. package/dist/{app-install-oZIQRbdD.mjs → app-install-NFxUahnH.mjs} +25 -17
  8. package/dist/{build-lock-vE45ZzJZ.mjs → build-lock-BsVoLDaq.mjs} +6 -6
  9. package/dist/{build-slots-CgacA9zQ.mjs → build-slots-D0b6sJyo.mjs} +3 -3
  10. package/dist/{cache-manifest-oeH18ERr.mjs → cache-manifest-Cu4_Znw9.mjs} +1 -1
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +13 -13
  13. package/dist/collector-run.d.mts +1 -0
  14. package/dist/collector-run.mjs +6 -6
  15. package/dist/{config-D7uu8Gbq.mjs → config-CMtIaTk9.mjs} +1 -1
  16. package/dist/{deps-64wVnpZc.mjs → deps-BLBsTNDS.mjs} +2 -2
  17. package/dist/{dev-client-Bvky1hya.mjs → dev-client-RpvXxCXV.mjs} +72 -9
  18. package/dist/{device-DJKv5Qej.mjs → device-CoCPmazS.mjs} +5 -5
  19. package/dist/{device-lease-D-G3SgVe.mjs → device-lease-Dpik41RY.mjs} +3 -3
  20. package/dist/{device-pool-BlHXnYYs.mjs → device-pool-B5pEVa3t.mjs} +3 -3
  21. package/dist/{device-remote-CCgkG82J.mjs → device-remote-E81KAdXf.mjs} +8 -8
  22. package/dist/{doctor-DlVxTtMq.mjs → doctor-CqPeMsSm.mjs} +19 -26
  23. package/dist/{doctor-BRF9aAJ3.mjs → doctor-D_CX7ib5.mjs} +10 -10
  24. package/dist/{error-diagnostics-B5IJwv3-.mjs → error-diagnostics-Dw8Gn3yw.mjs} +8 -8
  25. package/dist/{exec-bsN9MJXb.mjs → exec-CyylIdq9.mjs} +4 -2
  26. package/dist/{gc-DhXdgSdt.mjs → gc-B7KkDinF.mjs} +39 -25
  27. package/dist/{guide-DrhrDBo5.mjs → guide-BS2Xc24o.mjs} +220 -36
  28. package/dist/{ios-CK1Vrk6Q.mjs → ios-B7KLgIp5.mjs} +38 -26
  29. package/dist/{ios-BZxKPuqP.mjs → ios-D1h1Di39.mjs} +79 -10
  30. package/dist/{ios-device-CYbuRNXR.mjs → ios-device-D3pzTKQE.mjs} +1 -1
  31. package/dist/{ios-device-CdSm0GDw.mjs → ios-device-xNt0Lg6v.mjs} +2 -2
  32. package/dist/{logs-Dxoy16Qv.mjs → logs-DcX9AvRF.mjs} +3 -3
  33. package/dist/{metro-B01H3EuD.mjs → metro-COslRK_F.mjs} +3 -3
  34. package/dist/{ownership-D8HmSv2E.mjs → ownership-CGPart6T.mjs} +3 -3
  35. package/dist/{ownership-B9QIdQOw.mjs → ownership-CYOyqxUo.mjs} +4 -4
  36. package/dist/{ownership-claim-CeJLEpjD.mjs → ownership-claim-7zRxxTfZ.mjs} +1 -1
  37. package/dist/{project-COj6nzzh.mjs → project-BBTVABUz.mjs} +2 -2
  38. package/dist/{reclaim-BPvN2HlP.mjs → reclaim-C5Jmuahx.mjs} +9 -8
  39. package/dist/{reload-DYZEBbZy.mjs → reload-Z8nKifAk.mjs} +7 -7
  40. package/dist/{remote-cache-DOi5-zLj.mjs → remote-cache-DDmJ1Roq.mjs} +73 -13
  41. package/dist/{server-bare-BYHqEeyw.mjs → server-bare-DEk37Mz2.mjs} +7 -2
  42. package/dist/{server-expo-BEMr_m6p.mjs → server-expo-C3ktAwUG.mjs} +4 -4
  43. package/dist/server-expo-Drd7ksHu.mjs +2 -0
  44. package/dist/{settings-BSwrY4FZ.mjs → settings-DwU1_U_q.mjs} +26 -5
  45. package/dist/{start-ByCylYtB.mjs → start-BrY4EuIg.mjs} +10 -10
  46. package/dist/{state-IYEY-zi8.mjs → state-CZ-ER-8d.mjs} +1 -1
  47. package/dist/{stats-wqxPm7Tv.mjs → stats-BCWEVLrM.mjs} +1 -1
  48. package/dist/{stats-DZ4Q5J-7.mjs → stats-BsF15Bti.mjs} +3 -3
  49. package/dist/{status-Dia0XTqG.mjs → status-DFI1Hfpg.mjs} +46 -16
  50. package/dist/{stop-D6o5zAdm.mjs → stop-B7DR4awK.mjs} +2 -2
  51. package/dist/{stop-BApyaF21.mjs → stop-Btg770vV.mjs} +9 -9
  52. package/dist/supervisor-run.mjs +4 -4
  53. package/dist/{workspace-process-lock-CxOO9-pf.mjs → workspace-process-lock-BKfdys1q.mjs} +1 -1
  54. package/dist/{worktree-DxEmUI_n.mjs → worktree-BPTbI-LN.mjs} +16 -16
  55. package/dist/{worktree-Dx3ZC5lS.mjs → worktree-C79xx_kM.mjs} +7 -3
  56. package/dist/{xcode-CDB6fytw.mjs → xcode-DeKCribl.mjs} +190 -63
  57. package/package.json +5 -5
  58. package/shim/bundle-response.cjs +5 -0
  59. 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-DwU1_U_q.mjs";
2
2
  import chalk from "chalk";
3
3
  //#endregion
4
4
  //#region src/guide/index.ts
@@ -64,6 +64,11 @@ Doctor reports cross-volume staging and build-cache copies; read guide settings
64
64
  for placement overrides and guide lifecycle options for warm behavior.
65
65
  For iOS Debug architecture findings, review the project's overrides and imported
66
66
  Podfile helpers using guide lifecycle options. Doctor --fix does not change them.
67
+ For parallel iOS work, review the recommended optional SimSlim setup in
68
+ stim guide lifecycle simslim. If simulator process startup times out, check
69
+ host memory pressure and free memory before retrying; do not restart other
70
+ workspaces' devices or close their apps without asking. That guide covers
71
+ the recovery steps and profile tradeoffs.
67
72
  For a linked native library carrying Git metadata, add the printed .git entries to
68
73
  .fingerprintignore only when the native build does not read Git state.
69
74
 
@@ -83,6 +88,11 @@ them. It preserves source, custom launcher settings, and the shared ccache.
83
88
  stim start
84
89
  stim ios # or: stim android
85
90
 
91
+ Read stim guide lifecycle concurrency when a build waits on another workspace
92
+ or a build call times out. A native build can outlive a shell timeout; if the
93
+ tool call timed out, retry the same command and follow its printed remedy if
94
+ waiting times out.
95
+
86
96
  # Reproduce the affected behavior and capture the baseline errors.
87
97
  stim logs --errors
88
98
 
@@ -132,8 +142,6 @@ RULES DURING THE LOOP
132
142
  the error screen remains, follow the printed reload remedy instead of
133
143
  running ios or android again. If launch says FATAL because the app process exited,
134
144
  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
145
  - ios and android install the app, launch it, and check readiness. Trust the
138
146
  exact device, app, Metro, and launch facts in the final summary. Use the full
139
147
  reported device ID. Never assume a simulator named booted belongs to this
@@ -156,7 +164,9 @@ RULES DURING THE LOOP
156
164
  - Use stim status when resuming a workspace or recovering missing device,
157
165
  port, server, or build facts. A normal start and platform run already print
158
166
  them. Use stim doctor when a build is unexpectedly slow or the environment
159
- looks incomplete.
167
+ looks incomplete. If status reports a changed Android serial, rerun stim
168
+ android with the same build options to restore forwarding, then reopen your automation
169
+ session on the reported serial (guide lifecycle).
160
170
 
161
171
  OWNERSHIP AND DELETION
162
172
 
@@ -215,6 +225,34 @@ requirements.
215
225
 
216
226
  LOAD ADVANCED GUIDANCE WHEN NEEDED
217
227
 
228
+ Read the matching guide before acting in these situations:
229
+
230
+ | Situation | Read |
231
+ | ----------------------------------------------------- | -------------------------------- |
232
+ | Build waiting on another workspace or tool timeout | stim guide lifecycle concurrency |
233
+ | --variant, scheme, or several APKs from assembleDebug | stim guide lifecycle options |
234
+ | Refusal with a CODE | stim guide errors <CODE> |
235
+ | Running under a sandbox | stim guide errors sandbox |
236
+ | Release configuration or ...Release variant | stim guide lifecycle release |
237
+ | Remote device, custom Metro, or tunnel | stim guide metro |
238
+ | Cache miss, bypass, or fingerprint exclusions | stim guide lifecycle builds |
239
+ | Capacity limits | stim guide lifecycle concurrency |
240
+ | Cache statistics from stim stats | stim guide facts stats |
241
+ | Worktree carry-over | stim guide lifecycle options |
242
+ | gc or orphaned resources | stim guide cleanup gc |
243
+ | worktree remove refusal or --force | stim guide errors remove |
244
+ | Cleanup failure or unverified cleanup ownership | stim guide errors teardown |
245
+ | Unfamiliar state or JSON field | stim guide facts payloads |
246
+ | Refusal without a code | stim guide errors |
247
+
248
+ Use the CODE exactly as printed; codes sharing a header resolve to the same
249
+ section. For a refusal without a code, find its quoted message in the errors
250
+ index. Ordinary stim stop and an authorized clean stim worktree remove do not
251
+ need the cleanup guide. A sectioned topic called without a section prints its
252
+ index; choose the narrowest section.
253
+
254
+ FULL TOPIC LIST
255
+
218
256
  stim guide # list topics
219
257
  stim guide errors # index of every refusal code and message
220
258
  stim guide errors <CODE> # one refusal, e.g. stim guide errors STIM_NO_METRO
@@ -235,19 +273,7 @@ LOAD ADVANCED GUIDANCE WHEN NEEDED
235
273
  stim guide logs # filters, record shape, and capture limits
236
274
  stim guide cleanup # what reclaims a device, and what deletes
237
275
  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.`
276
+ stim guide settings # configuration files and supported keys`
251
277
  },
252
278
  facts: {
253
279
  summary: "The --json payloads: `start`, `ios`, `android`, `reload`, `stop`, `status`, `doctor`, `device lock`/`unlock`, and the error contract",
@@ -705,6 +731,30 @@ Plain \`stim start\` is local and does not create a public tunnel. Remote intent
705
731
  comes from \`start --remote\`, \`ios.remote\`, or \`android.remote\`. The
706
732
  \`metro.tunnel\` setting selects the provider after remote intent exists.
707
733
 
734
+ BUNDLE WARMUP
735
+ After verifying Metro, \`stim ios\` and \`stim android\` prefetch the
736
+ platform's development bundle while native work continues. Expo supplies the
737
+ entry point and bundle options through its manifest; bare React Native uses
738
+ the standard index entry and development bundle options, including lazy loading.
739
+ Warmup is enabled by default. Set optimizations.metroWarmup=false to disable
740
+ it on the next ios/android command, using the machine or project settings.
741
+ For custom entry points or bundle options, set metro.warmupUrl.ios and/or
742
+ metro.warmupUrl.android to the app's complete bundle URL or /path?query.
743
+ Stim keeps the path and query and uses the verified local Metro port.
744
+ Overrides replace discovery and receive no additional query defaults.
745
+ doctor validates configured URLs, including their platform; it does not
746
+ infer or auto-fix runtime native entry points or dev-menu bundle options.
747
+ See \`guide settings\` for configuration examples.
748
+ Each request times out after 60 seconds and does not keep the command alive.
749
+ Warmup failures do not fail the native build.
750
+ Release builds and \`--no-metro-check\` skip warmup. Servers without Stim's
751
+ prefetch-aware response observer also skip it; restart an older supervisor
752
+ with the current CLI to enable warmup.
753
+
754
+ Prefetch completion is not launch proof. Development launch verification
755
+ waits for the app's own bundle response. With a bundler started outside Stim,
756
+ device logs may prove a request, but bundle completion may stay unverified.
757
+
708
758
  REMOTE DEVICE BACKENDS
709
759
  Metro exposure and device selection are separate:
710
760
 
@@ -1355,6 +1405,11 @@ code, never on the message.`,
1355
1405
  body: () => `STIM_LAUNCH_FAILED
1356
1406
  Installed, but the app would not start. On Android this usually means no
1357
1407
  launchable activity resolved.
1408
+ On a local iOS simulator, a timed-out launch can mean the simulator cannot
1409
+ spawn processes, even while it reports Booted. Check the reported memory
1410
+ pressure and free host memory before retrying; a timeout alone is not an OOM
1411
+ diagnosis. See \`stim guide lifecycle simslim\` for recovery and the optional
1412
+ SimSlim recommendation.
1358
1413
  On a PHONE it means the app never appeared in the device's own process list
1359
1414
  after \`devicectl device process launch\`, and the devicectl lines that
1360
1415
  explain it are quoted under the message. The refusal a first launch usually
@@ -1578,9 +1633,21 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
1578
1633
  reach a booted state. \`stim doctor\` checks the toolchain; \`stim status\` says what
1579
1634
  Stim thinks it owns. Re-running the command creates a fresh owned device
1580
1635
  when the recorded one is gone.
1636
+ If Android creation says an AVD already exists on disk but is not listed,
1637
+ run \`npx stim gc\` to inspect orphaned owned AVDs, then \`npx stim gc --delete\`
1638
+ to reclaim those safe to delete before retrying. Keep anything GC cannot
1639
+ verify; do not delete AVD directories by hand. A registered unrecorded owned
1640
+ AVD is recovered, reusing its existing emulator when its identity is verified.
1641
+ If recovery cannot verify registration or process state, inspect \`npx stim status\`
1642
+ and \`adb devices\`, then retry after any other run finishes. Keep the AVD and
1643
+ its process locks while its state is unverified.
1581
1644
  On iOS a slow first boot is waited out for up to ten minutes while the
1582
1645
  simulator still reports Booting -- a long silent wait on a loaded machine
1583
1646
  is patience, not a hang. The failure names the udid and the wait.
1647
+ After boot, a process-spawn probe must finish within 30 seconds before
1648
+ installation. If it fails, the refusal includes observed host memory pressure
1649
+ when available. Free memory before retrying under pressure; see
1650
+ \`stim guide lifecycle simslim\`. Booted alone does not prove readiness.
1584
1651
  On Android the emulator's own stdio is captured to
1585
1652
  the global workspace logs/emulator.log (truncated per boot), and when it printed a
1586
1653
  \`FATAL |\` / \`ERROR |\` / \`PANIC:\` line THAT is the message and the remedy
@@ -2116,9 +2183,11 @@ changes nothing (worktree warm --refresh)
2116
2183
  blocks network egress by default, which breaks a cache lookup and a fetch.
2117
2184
 
2118
2185
  \`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
2186
+ merely when a harness that can sandbox is present. \`stim doctor --fix\`
2187
+ writes only when the report shows that finding, and only what the finding
2188
+ names: the three keys, into .claude/settings.local.json, the per-user file,
2189
+ merging with what is there. A report without the finding, with or without
2190
+ --platform, leaves that file alone. It refuses under Codex, which
2122
2191
  has no per-path allowance to add, and refuses any settings file it cannot
2123
2192
  parse rather than replace it: comments make one unparseable here even though
2124
2193
  Claude Code accepts them. Claude Code reads project settings from the
@@ -2293,6 +2362,21 @@ If the app is stuck before loading its first bundle, restart its process with
2293
2362
  the printed force-stop and launcher commands. Foregrounding the same process
2294
2363
  does not restart initialization. Confirm the bundle request and expected UI.
2295
2364
 
2365
+ Debug Android launches on an owned emulator created in the same run get up to
2366
+ 60 seconds for bundle loading; the verify phase names that budget. Existing
2367
+ emulators, remote targets, and physical devices keep the 20-second budget.
2368
+ Bundle delivery still requires the usual stability or app readiness check;
2369
+ an observed fatal error ends verification without waiting for the deadline.
2370
+
2371
+ ANDROID EMULATOR RESTARTS
2372
+ \`stim status\` resolves owned AVDs to their currently detected adb serial.
2373
+ Its Android JSON adds serial and state (detected, not-detected, missing,
2374
+ or unknown). Detection confirms device identity, not app health. Status
2375
+ reports a serial change without changing forwarding or restarting anything.
2376
+ Rerun \`stim android\` with the same build options in that workspace to restore Metro
2377
+ forwarding, then reopen agent-device on the serial that run reports.
2378
+ Other workspaces' simulators and automation sessions remain theirs.
2379
+
2296
2380
  DESTRUCTIVE COMMANDS -- ask the user first
2297
2381
  gc --delete deletes orphaned stim-* devices, tens of GB
2298
2382
  gc --delete --cache all empties the shared build caches every project uses
@@ -2474,7 +2558,7 @@ result as proof instead of requiring an unrelated screenshot.`
2474
2558
  build still compiling (4m00s, usually ~3m10s)
2475
2559
  build still compiling (1m00s)
2476
2560
  pods still installing (1m30s of ~1m40s)
2477
- build waiting on /w/app-411 (pid 41233, 1m30s elapsed)
2561
+ build waiting on /w/app-411 (pid 41233, 1m30s elapsed) -- stim guide lifecycle concurrency
2478
2562
 
2479
2563
  The \`~\` value is an estimate, never a countdown; the third line is a
2480
2564
  project with no record to estimate from yet. \`guide facts stats\` says where
@@ -2490,7 +2574,7 @@ result as proof instead of requiring an unrelated screenshot.`
2490
2574
  step, before those. A plain warm prints the \`lock\` line only when its copy
2491
2575
  actually waited for another warm:
2492
2576
 
2493
- lock acquired (waited 12s for stim worktree warm --refresh pid 41233)
2577
+ lock acquired (waited 12s for stim worktree warm --refresh pid 41233) -- stim guide lifecycle options
2494
2578
  checkout janic/wip 2 commits behind origin/janic/wip -> fast-forwarded to 4b81e0c
2495
2579
  not the default branch (main); worktrees seeded from this copy
2496
2580
  carry janic/wip's dependencies
@@ -2498,7 +2582,7 @@ result as proof instead of requiring an unrelated screenshot.`
2498
2582
  pods source /w/main/apps/mobile: ios/Podfile.lock changed -> pod install (1m12s)
2499
2583
 
2500
2584
  A wait reports how long this caller has waited and names the holder:
2501
- \`lock waiting 40s for stim worktree warm --refresh (pid 41233)\`.
2585
+ \`lock waiting 40s for stim worktree warm --refresh (pid 41233) -- stim guide lifecycle options\`.
2502
2586
 
2503
2587
  \`start\` names the port, the supervisor mode and its pid on one line
2504
2588
  (\`metro starting on port 8083 (expo-child, supervisor pid 13724)\`),
@@ -2744,7 +2828,7 @@ changing modes selects another profile. See \`guide settings\` for cleanup.
2744
2828
 
2745
2829
  Each reports its cache setup. \`stim doctor\` checks missing or stale setup
2746
2830
  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
2831
+ (ccache absent from PATH or a .cxx that predates the
2748
2832
  launcher, a fingerprint no fresh worktree reproduces, a provider on a key this
2749
2833
  SDK ignores) and settings for builds outside Stim.
2750
2834
 
@@ -2926,9 +3010,9 @@ WHAT MAKES THE CACHE ACTUALLY HIT: .FINGERPRINTIGNORE
2926
3010
  <fingerprint, platform> (a directory under ~/.stim/build-locks). Exactly
2927
3011
  one workspace compiles; the others print
2928
3012
 
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
3013
+ build /w/app-412 is already building a3f9b1.. (pid 41233) -- tail ... -- stim guide lifecycle concurrency
3014
+ build waiting on /w/app-412 (pid 41233, 4m elapsed) -- tail ... -- stim guide lifecycle concurrency
3015
+ build waited 12m41s for /w/app-412's build -> installed from cache -- stim guide lifecycle concurrency
2932
3016
 
2933
3017
  and install the artifact the builder stored. They report cacheHit: "local"
2934
3018
  plus waitedForBuild: { pid, ms }.
@@ -3096,10 +3180,27 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3096
3180
  paths eligible under the source checkout's Git ignore rules, including .env
3097
3181
  and local configuration. The source's nonempty
3098
3182
  .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
3183
+ registered worktrees, .DS_Store, .DerivedData, .idea, and
3184
+ android/build/generated/autolinking caches are excluded, including inside
3185
+ newly copied directories. Gradle regenerates autolinking
3101
3186
  for the destination checkout on its next build. Warm also skips paths
3102
3187
  overlapping a nested destination worktree or below a symlink ancestor.
3188
+ Tracked .idea settings come from Git and stay untouched by warm.
3189
+
3190
+ Other generated state stays eligible: .gradle, .cxx, *.tsbuildinfo, build
3191
+ directories, and embedded JavaScript need project-specific decisions about
3192
+ regeneration. Native intermediates can record the source checkout's paths;
3193
+ warm does not relocate them. Excluding the whole .expo directory can drop
3194
+ generated TypeScript inputs.
3195
+
3196
+ To choose exclusions, run this in the source checkout's repository root:
3197
+
3198
+ git ls-files --others --ignored --exclude-standard --directory --no-empty-directory
3199
+
3200
+ Patterns match those entries with the trailing / removed. They do not prune
3201
+ children of a whole ignored directory: if Git lists android/app/src/main/assets/,
3202
+ excluding its bundle.jsbundle child has no effect. Exclude the assets entry
3203
+ only when the project regenerates everything inside it.
3103
3204
 
3104
3205
  Warm copies directly into the destination, without intermediate staging.
3105
3206
  Keep the source checkout and the linked worktree on the same volume to
@@ -3451,22 +3552,63 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
3451
3552
  \`.ipa\` export, store signing and distribution stay out of scope.`
3452
3553
  },
3453
3554
  simslim: {
3454
- summary: "installing SimSlim and what ios.simslimProfile does to an owned simulator",
3455
- body: () => `OPTIONAL SIMSLIM PROFILE
3555
+ summary: "recommended SimSlim profiles and recovery from host memory pressure",
3556
+ body: () => `SIMSLIM FOR PARALLEL IOS WORK
3557
+ SimSlim is recommended as an optional way to reduce simulator background
3558
+ services and memory use, especially with several workspaces. Review which
3559
+ services your app and tests need; a slim profile can disable those features.
3560
+ It does not guarantee that a memory stall or crash will be fixed.
3561
+
3456
3562
  Install SimSlim once on each Mac:
3457
3563
 
3458
3564
  brew install mobai-app/tap/simslim
3459
3565
 
3460
- Then commit a profile and select it in .stim.json:
3566
+ Review the categories and create a profile in an interactive terminal:
3567
+
3568
+ simslim profiles
3569
+ mkdir -p .simslim
3570
+ simslim profile .simslim/dev.json
3571
+
3572
+ Selected categories in the wizard stay enabled. The wizard writes the
3573
+ profile without applying it. Review and commit it, then select it in .stim.json:
3461
3574
 
3462
3575
  { "ios": { "simslimProfile": ".simslim/dev.json" } }
3463
3576
 
3464
- SimSlim requires an iOS 18 or newer simulator. On each local \`stim ios\`,
3577
+ SimSlim 0.8 requires iOS 18.5 or newer. On each local \`stim ios\`,
3465
3578
  Stim reconciles that profile on the owned simulator before the app build.
3466
3579
  The first change can update services and reboot the simulator. A matching
3467
3580
  profile is a fast no-op on later launches. The settings persist across normal
3468
3581
  shutdowns and reboots. Removing the setting restores stock services when
3469
- Stim applied the profile. Stim never changes an unowned or remote simulator.`
3582
+ Stim applied the profile. Stim never changes an unowned or remote simulator.
3583
+ Each SimSlim operation has a 12-minute outer deadline, including discovery.
3584
+ This cap also applies when SimSlim's own timeout is increased. On timeout,
3585
+ Ctrl-C, or SIGTERM, Stim attempts to stop only its verified process group, then waits up to
3586
+ 10 seconds to confirm termination before returning or exiting.
3587
+ An unconfirmed process group keeps its claim and blocks another reconciliation;
3588
+ inspect the named processes before removing the exact claim in the error.
3589
+ The simulator's managed settings record is retained, so retrying reconciles an
3590
+ interrupted apply or restore. Stim does not assume partial changes rolled back.
3591
+ Doctor recommends this setup but never installs SimSlim or applies a profile.
3592
+ Profile schema and service tradeoffs: https://github.com/MobAI-App/simslim
3593
+
3594
+ HOST MEMORY PRESSURE AND STALLED SIMULATORS
3595
+ Booted and a working screenshot do not prove that simulator processes can
3596
+ start. Stim checks a bounded process spawn before install and bounds local
3597
+ simulator launch operations. Simulator discovery waits up to 30 seconds,
3598
+ boot (including the initial boot request) up to 10 minutes, and app installation
3599
+ up to 5 minutes. Process termination confirmation can take another 10 seconds;
3600
+ a final boot-state query can take 30 seconds. Opening the Simulator app after
3601
+ boot is best-effort and takes at most 5 seconds. A timeout is not proof of an
3602
+ app crash or OOM.
3603
+ Doctor and failure diagnostics report macOS memory pressure when available;
3604
+ a failed query remains unknown. Existing swap or low free RAM alone is not
3605
+ enough to diagnose pressure.
3606
+
3607
+ If pressure is elevated, free host memory before retrying. Use \`stim stop\`
3608
+ only in workspaces you own and have finished using; ask before closing other
3609
+ agents' simulators or heavy apps. Rebooting a simulator under the same pressure
3610
+ can repeat the stall. Consider fewer concurrent builds/devices (guide lifecycle
3611
+ concurrency) and a reviewed SimSlim profile for future runs.`
3470
3612
  }
3471
3613
  }
3472
3614
  },
@@ -3527,6 +3669,18 @@ If a delete fails, the device's config record is KEPT and the command reports
3527
3669
  it. A record is what makes the device findable again, so it outlives a failed
3528
3670
  teardown rather than turning it into an orphan.
3529
3671
 
3672
+ ANDROID DATA WITHOUT A REGISTRATION
3673
+ \`gc\` also reports stim-*.avd directories whose .ini registration is
3674
+ gone. \`gc --delete\` rechecks the directory, emulator process locks, and
3675
+ current workspace and pool references before removing that data. A registration
3676
+ under any name that points at the directory protects it. User AVDs, symlinks
3677
+ and unverifiable storage stay. The no-config and scoped-STIM_HOME
3678
+ sweep guards apply to these directories too.
3679
+ A partial avdmanager deletion is a failure even if the tool exits successfully.
3680
+ The owning workspace or pool record stays for a retry. If removing orphan
3681
+ data fails, its remaining directory is reported as stim-gc-<id>.avd on the
3682
+ next sweep.
3683
+
3530
3684
  BUILD LOCKS
3531
3685
  \`gc\` also reports the single-flight build locks (above): the ones whose
3532
3686
  builder is no longer running are debris a reboot or a kill left behind, and
@@ -3777,7 +3931,9 @@ KEYS STIM READS
3777
3931
  at most 64 KiB. Install the
3778
3932
  external tool once with
3779
3933
  \`brew install mobai-app/tap/simslim\`. SimSlim requires
3780
- an iOS 18 or newer simulator. Each local \`stim ios\`
3934
+ iOS 18.5 or newer in SimSlim 0.8. Recommended for parallel
3935
+ iOS work after reviewing service tradeoffs; see
3936
+ \`stim guide lifecycle simslim\`. Each local \`stim ios\`
3781
3937
  reconciles the profile on its Stim-owned simulator.
3782
3938
  The first change can reboot it; a matching profile is a
3783
3939
  fast no-op. Removing the setting restores stock services
@@ -3814,7 +3970,10 @@ KEYS STIM READS
3814
3970
  -- the sdkmanager package id the owned AVD is created
3815
3971
  from. The \`--system-image\` flag overrides this per
3816
3972
  invocation, and an id this SDK has not installed is
3817
- STIM_BAD_ARG with the installed ids printed
3973
+ STIM_BAD_ARG with the installed ids printed.
3974
+ New AVDs use the Pixel 6 hardware profile (1080x2400,
3975
+ 420 dpi). Existing AVDs keep their display settings;
3976
+ parked AVDs from the old generic profile are not adopted.
3818
3977
  android.dataPartitionSizeGb
3819
3978
  whole GiB for a newly created owned AVD's data
3820
3979
  partition. Defaults to 8; accepts 6 through 16384.
@@ -3894,6 +4053,25 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
3894
4053
  did not create it, so a Metro request through it is
3895
4054
  still gated the same way a managed tunnel's is. Set it
3896
4055
  before Expo start so the manifest advertises it.
4056
+ metro.warmupUrl optional object with per-platform bundle URLs:
4057
+ metro.warmupUrl.ios
4058
+ metro.warmupUrl.android
4059
+ an HTTP(S) URL or a /path ending in .bundle, with the
4060
+ full query the app uses, including a matching platform.
4061
+ Unset uses Expo's manifest or bare React Native defaults.
4062
+ Stim preserves the path and query but always requests
4063
+ this workspace's verified local Metro port; a supplied
4064
+ host and port are ignored. No defaults are added to an
4065
+ override. This only configures prefetch, not the app.
4066
+ For example, in .stim.json:
4067
+ { "metro": { "warmupUrl": {
4068
+ "ios": "/src/main.bundle?platform=ios&dev=true&lazy=true"
4069
+ } } }
4070
+ Use the app's complete request for custom options.
4071
+ URLs must encode spaces and omit fragments. doctor
4072
+ validates the shape and platform but cannot discover
4073
+ runtime entry-point or dev-menu overrides or auto-fix
4074
+ them. See \`guide metro\` for warmup behavior.
3897
4075
  worktree.exclude ignored-path skip list for worktree warm. Settings
3898
4076
  come from the source checkout's repository-root
3899
4077
  .stim.json. A nonempty .worktreeexclude in the source
@@ -4044,6 +4222,7 @@ key inherits the next layer. Changes apply on the next build or Metro restart.
4044
4222
  "remoteBuildCache": true,
4045
4223
  "releaseBundleSwap": true,
4046
4224
  "metroSharedCache": true,
4225
+ "metroWarmup": true,
4047
4226
  "ios": {
4048
4227
  "compilationCache": true,
4049
4228
  "swiftCompilationCache": false,
@@ -4075,6 +4254,11 @@ The example shows the defaults. Full setting names and behavior:
4075
4254
  false stops Stim appending its shared Metro store on both dev servers.
4076
4255
  Project-configured stores remain the project's choice. Replace the removed
4077
4256
  machine setting caches.injectMetroStore=false with this setting set false.
4257
+ optimizations.metroWarmup
4258
+ true by default. false skips background development bundle requests during
4259
+ ios/android, including any metro.warmupUrl override. Metro verification and
4260
+ native builds still run. Applies on the next ios/android command; no Metro
4261
+ restart is needed.
4078
4262
  optimizations.ios.compilationCache
4079
4263
  controls Xcode compilation caching (Xcode 26+).
4080
4264
  optimizations.ios.swiftCompilationCache
@@ -1,28 +1,28 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { S as upsertProject, f as getProject, l as getConcurrencyLimits } from "./config-D7uu8Gbq.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { S as upsertProject, f as getProject, l as getConcurrencyLimits } from "./config-CMtIaTk9.mjs";
3
3
  import { r as createNdjsonWriter } from "./ndjson-DcAtEx_K.mjs";
4
- import { D as workspaceLogsDir, T as workspaceDir, _ as writeWorkspaceState, g as writeWorkspaceLaunch, n as MODE_EXPO, p as readWorkspaceState, t as MODE_BARE } from "./state-IYEY-zi8.mjs";
5
- import { C as removeTemporaryEntry, S as makeTemporaryDirectory, g as repoRoot, s as gitCommonDir } from "./worktree-Dx3ZC5lS.mjs";
6
- import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, r as detectBundleId, t as appProjectProblem } from "./project-COj6nzzh.mjs";
7
- import { i as resolveProjectMetro, r as pidExists } from "./metro-B01H3EuD.mjs";
8
- import { n as verifyCollectorOwnership } from "./ownership-D8HmSv2E.mjs";
9
- import { a as easAuthNote, c as loadProjectProvider, d as resolveEasCliBin, f as resolveRemote, i as checkEasAuth, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as uploadRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DOi5-zLj.mjs";
10
- import { D as remoteIosSetting, E as remoteDeviceSettingError, F as unknownSettingKeys, H as resolveOptimizations, L as detectProviders, M as settingShapeErrors, O as resolveCacheProviderConfig, P as tunnelModeSetting, V as optimizationBuildProfile, _ as iosSigningIdentitySha1SettingError, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as iosLanHostSetting, g as iosSigningIdentitySha1Setting, h as iosSigningIdentitySettingError, k as resolveSettings, m as iosSigningIdentitySetting, p as iosLanHostSettingError, r as REMOTE_DEVICE_BACKENDS, w as publicUrlSetting, z as artifactCachePolicy } from "./settings-BSwrY4FZ.mjs";
4
+ import { D as workspaceLogsDir, T as workspaceDir, _ as writeWorkspaceState, g as writeWorkspaceLaunch, n as MODE_EXPO, p as readWorkspaceState, t as MODE_BARE } from "./state-CZ-ER-8d.mjs";
5
+ import { C as removeTemporaryEntry, S as makeTemporaryDirectory, g as repoRoot, s as gitCommonDir } from "./worktree-C79xx_kM.mjs";
6
+ import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, r as detectBundleId, t as appProjectProblem } from "./project-BBTVABUz.mjs";
7
+ import { i as resolveProjectMetro, r as pidExists } from "./metro-COslRK_F.mjs";
8
+ import { n as verifyCollectorOwnership } from "./ownership-CGPart6T.mjs";
9
+ import { a as easAuthNote, c as loadProjectProvider, d as resolveEasCliBin, f as resolveRemote, i as checkEasAuth, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as uploadRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
10
+ import { A as resolveSettings, B as artifactCachePolicy, D as remoteDeviceSettingError, F as tunnelModeSetting, H as optimizationBuildProfile, I as unknownSettingKeys, N as settingShapeErrors, O as remoteIosSetting, R as detectProviders, T as publicUrlSetting, U as resolveOptimizations, _ as iosSigningIdentitySha1SettingError, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as iosLanHostSetting, g as iosSigningIdentitySha1Setting, h as iosSigningIdentitySettingError, k as resolveCacheProviderConfig, m as iosSigningIdentitySetting, p as iosLanHostSettingError, r as REMOTE_DEVICE_BACKENDS, x as metroWarmupUrlSetting } from "./settings-DwU1_U_q.mjs";
11
11
  import { _ as launchErrorPreview, c as launchErrorReport, g as stepTimer, h as stepClock, i as formatDuration, l as phaseLine, m as shortUdid, n as appReadinessMessage, p as shortHash } from "./command-output-8wHMEde0.mjs";
12
- import { C as launchIosApp, E as unverifiedLaunchLines, O as verifyLaunch, T as readMetroRecords, b as isBundleProof, c as RELEASE_VERIFY_WAIT_MS, f as clearOtherUserApps, i as LAUNCH_BUNDLING, k as verifyReleaseLaunch, m as devClientUrl, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, v as installIosApp, w as readCollectorRecords, y as iosAppProcess } from "./app-install-oZIQRbdD.mjs";
13
- import { d as listIosRuntimes } from "./ios-BZxKPuqP.mjs";
14
- import { C as untrackedNativeFiles, S as untrackedMissLine, _ as providerUploadOutcome, b as storeBuild, c as buildCacheKey, d as filesystemBuildCapability, f as fingerprintDiffRecord, g as providerDownloadPath, h as prepareProviderDownloadDir, i as releaseBuildLock, l as describeFingerprintMiss, m as fingerprintProject, n as acquireBuildLock, o as takeoverLine, p as fingerprintDiffSuffix, s as waitForBuild, t as WAIT_CEILING_MS, v as refingerprintAfterMutation, y as resolveBuild } from "./build-lock-vE45ZzJZ.mjs";
15
- import { r as claimFailure } from "./ownership-claim-CeJLEpjD.mjs";
16
- import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-BlHXnYYs.mjs";
17
- import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-CgacA9zQ.mjs";
18
- import { a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as noMetroMessage, f as noMetroRemedy, l as gateShouldRetry, m as sleep, n as pickDevClientScheme, o as needsPrebuild, p as resolveMetroWithRetry, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as launchOutcomeRecord } from "./dev-client-Bvky1hya.mjs";
19
- import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-wqxPm7Tv.mjs";
20
- import { C as unknownIosDeviceTypeRefusal, _ as checkDeviceCapacity, b as ensureOwnedDevice, c as discoverXcodeProject, d as resolveScheme, i as buildIos, l as readBundleExecutable, m as describeDiagnostic, n as COMPILATION_CACHE_UNAVAILABLE, o as compilationCacheActivityLine, t as COMPILATION_CACHE_NOT_RUN, u as readBundleId, v as clearIosAdoptionPending, w as unknownIosRuntimeRefusal, y as ensureBooted } from "./xcode-CDB6fytw.mjs";
21
- import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-CCgkG82J.mjs";
12
+ import { C as launchIosApp, E as unverifiedLaunchLines, O as verifyLaunch, T as readMetroRecords, b as isBundleProof, c as RELEASE_VERIFY_WAIT_MS, f as clearOtherUserApps, i as LAUNCH_BUNDLING, k as verifyReleaseLaunch, m as devClientUrl, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, v as installIosApp, w as readCollectorRecords, y as iosAppProcess } from "./app-install-NFxUahnH.mjs";
13
+ import { f as listIosRuntimes } from "./ios-D1h1Di39.mjs";
14
+ import { C as untrackedNativeFiles, S as untrackedMissLine, _ as providerUploadOutcome, b as storeBuild, c as buildCacheKey, d as filesystemBuildCapability, f as fingerprintDiffRecord, g as providerDownloadPath, h as prepareProviderDownloadDir, i as releaseBuildLock, l as describeFingerprintMiss, m as fingerprintProject, n as acquireBuildLock, o as takeoverLine, p as fingerprintDiffSuffix, s as waitForBuild, t as WAIT_CEILING_MS, v as refingerprintAfterMutation, y as resolveBuild } from "./build-lock-BsVoLDaq.mjs";
15
+ import { r as claimFailure } from "./ownership-claim-7zRxxTfZ.mjs";
16
+ import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-B5pEVa3t.mjs";
17
+ import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-D0b6sJyo.mjs";
18
+ import { a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as noMetroMessage, f as noMetroRemedy, h as warmMetro, l as gateShouldRetry, m as sleep, n as pickDevClientScheme, o as needsPrebuild, p as resolveMetroWithRetry, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as launchOutcomeRecord } from "./dev-client-RpvXxCXV.mjs";
19
+ import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BCWEVLrM.mjs";
20
+ import { T as unknownIosRuntimeRefusal, b as ensureBooted, c as discoverXcodeProject, d as resolveScheme, i as buildIos, l as readBundleExecutable, m as describeDiagnostic, n as COMPILATION_CACHE_UNAVAILABLE, o as compilationCacheActivityLine, t as COMPILATION_CACHE_NOT_RUN, u as readBundleId, v as checkDeviceCapacity, w as unknownIosDeviceTypeRefusal, x as ensureOwnedDevice, y as clearIosAdoptionPending } from "./xcode-DeKCribl.mjs";
21
+ import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-E81KAdXf.mjs";
22
22
  import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
23
- import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-B5IJwv3-.mjs";
24
- import { a as iosDeviceProcess, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as installIosDeviceApp, l as localNetworkPending, n as LAUNCH_PROBE_TIMEOUT_MS, o as iosPoolCandidates, r as awaitIosDeviceLaunch, s as iosPoolNoCandidatesRefusal, t as DEVICECTL_INSTALL_TIMEOUT_MS, u as resolveIosPhysicalDevice } from "./ios-device-CdSm0GDw.mjs";
25
- import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-64wVnpZc.mjs";
23
+ import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-Dw8Gn3yw.mjs";
24
+ import { a as iosDeviceProcess, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as installIosDeviceApp, l as localNetworkPending, n as LAUNCH_PROBE_TIMEOUT_MS, o as iosPoolCandidates, r as awaitIosDeviceLaunch, s as iosPoolNoCandidatesRefusal, t as DEVICECTL_INSTALL_TIMEOUT_MS, u as resolveIosPhysicalDevice } from "./ios-device-xNt0Lg6v.mjs";
25
+ import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-BLBsTNDS.mjs";
26
26
  import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
27
27
  import { InvalidArgumentError } from "commander";
28
28
  import { X509Certificate } from "node:crypto";
@@ -812,6 +812,7 @@ const DEFAULT_DEPS = {
812
812
  detectProviders,
813
813
  resolveProjectMetro,
814
814
  resolveMetroWithRetry,
815
+ warmMetro,
815
816
  readWorkspaceState,
816
817
  pidExists,
817
818
  getConcurrencyLimits,
@@ -1052,6 +1053,7 @@ async function verifyIosRun({ root, appPath, d, release, launched, configuration
1052
1053
  return { state: crashes.length || processCheck?.reason === "exited" ? LAUNCH_FATAL : LAUNCH_UNVERIFIED };
1053
1054
  }
1054
1055
  const verification = metroCheck ? await d.verifyLaunch({
1056
+ requireBundleResponse: true,
1055
1057
  onReadinessPending: () => phase("readiness", "waiting for app readiness (up to 30s after bundle load)"),
1056
1058
  logsDir,
1057
1059
  since: launchedAt,
@@ -1190,6 +1192,9 @@ function recordIosReloadTarget({ d, root, physical, remoteDevice, bundleId, udid
1190
1192
  note(chalk.yellow(phaseLine("state", `could not record iOS launch: ${error?.message || error}`)));
1191
1193
  }
1192
1194
  }
1195
+ function simulatorLaunchFailureRemedy(remote, udid, bundleId, logFile) {
1196
+ return `${remote ? "Run" : "If the simulator timed out, run `stim doctor --platform ios` and resolve any reported host memory pressure before retrying. Otherwise run"} \`xcrun simctl launch --console ${udid} ${bundleId}\` to see what the app reports, and check ${logFile}.`;
1197
+ }
1193
1198
  async function finishIosRun({ d, root, json, release, configuration, buildScheme, isExpo, metroCheck, metroPort, logsDir, logFile, device, udid, physical, lanAddress, lanOriginUrl, remoteDevice, bootPromise, bootDuration, appPath, bundleId: initialBundleId, swapDir, buildFailure, fail, phase, note, logWriter, uploadPending, providerUpload, providerName, remote, abandonedRemote: remoteWasAbandoned, elapsed, startedAt, storeHash, storeKey, cacheHit, compilationCache, useBuildCache, waitedForBuild, closeWriter, lease, releaseLease, recordRun }) {
1194
1199
  let bundleId = initialBundleId;
1195
1200
  let leaseWarned = false;
@@ -1428,7 +1433,7 @@ async function finishIosRun({ d, root, json, release, configuration, buildScheme
1428
1433
  return fail({
1429
1434
  code: launched.code || "STIM_LAUNCH_FAILED",
1430
1435
  message: launched.reason,
1431
- remedy: `Run \`xcrun simctl launch --console ${udid} ${bundleId}\` to see what the app reports, and check ${logFile}.`,
1436
+ remedy: simulatorLaunchFailureRemedy(Boolean(remoteDevice), udid, bundleId, logFile),
1432
1437
  build: {
1433
1438
  ...buildFailure,
1434
1439
  appPath,
@@ -2032,6 +2037,13 @@ async function runIos(opts = {}, overrides = {}) {
2032
2037
  return false;
2033
2038
  }
2034
2039
  }
2040
+ if (!release && metroCheck && optimizations.metroWarmup) d.warmMetro({
2041
+ port: metroPort,
2042
+ platform: "ios",
2043
+ isExpo,
2044
+ appId: proj?.bundleId,
2045
+ bundleUrl: metroWarmupUrlSetting(settings, "ios")
2046
+ });
2035
2047
  return true;
2036
2048
  }
2037
2049
  async function resolveLanOrigin() {
@@ -2267,7 +2279,7 @@ async function runIos(opts = {}, overrides = {}) {
2267
2279
  releasedWait = null;
2268
2280
  const held = attempt.held;
2269
2281
  const who = held.projectRoot || "another workspace";
2270
- phase("build", `${who} is already building ${shortHash(fingerprint)} (pid ${held.pid})${held.logFile ? ` -- tail ${held.logFile}` : ""}`);
2282
+ phase("build", `${who} is already building ${shortHash(fingerprint)} (pid ${held.pid})${held.logFile ? ` -- tail ${held.logFile}` : ""} -- stim guide lifecycle concurrency`);
2271
2283
  let waited = null;
2272
2284
  try {
2273
2285
  const ceilingMs = WAIT_CEILING_MS - (d.now() - waitStarted);
@@ -2319,7 +2331,7 @@ async function runIos(opts = {}, overrides = {}) {
2319
2331
  pid: held.pid,
2320
2332
  ms: waited.waitedMs
2321
2333
  };
2322
- phase("build", `waited ${formatDuration(waited.waitedMs)} for ${who}'s build -> installed from cache`);
2334
+ phase("build", `waited ${formatDuration(waited.waitedMs)} for ${who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
2323
2335
  } else if (waited?.lockReleased) {
2324
2336
  failedHolder = void 0;
2325
2337
  releasedWait = {
@@ -2540,7 +2552,7 @@ async function runIos(opts = {}, overrides = {}) {
2540
2552
  phase("cache", `hit ${shortHash(storeHash)} (post-${mutatingSteps.join("/")} key)`);
2541
2553
  if (releasedWait) {
2542
2554
  waitedForBuild = releasedWait.facts;
2543
- phase("build", `waited ${formatDuration(waitedForBuild.ms)} for ${releasedWait.who}'s build -> installed from cache`);
2555
+ phase("build", `waited ${formatDuration(waitedForBuild.ms)} for ${releasedWait.who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
2544
2556
  }
2545
2557
  }
2546
2558
  }