stim 1.31.0 → 1.33.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 (169) hide show
  1. package/dist/{acquire-artifact-P84h3ssa.mjs → acquire-artifact-DTh_LxrE.mjs} +2 -2
  2. package/dist/{act-lcOIEy32.mjs → act-Cur4YKtK.mjs} +74 -25
  3. package/dist/{activity-Dw4N_RFe.mjs → activity-C8kBq9w0.mjs} +6 -6
  4. package/dist/{agent-device-usage-output-Boie2yB-.mjs → agent-device-usage-output-BTRaK_up.mjs} +5 -5
  5. package/dist/{android-BeeC15Ve.mjs → android-B2DSKg-A.mjs} +2 -2
  6. package/dist/{android-DhiWSOFU.mjs → android-BL-QqHjc.mjs} +87 -53
  7. package/dist/{android-aIuJZoDu.mjs → android-D5mCdVl2.mjs} +5 -5
  8. package/dist/{android-DsEj2CCs.mjs → android-Iq0M2t2d.mjs} +27 -15
  9. package/dist/{android-cas-CbumHXIq.mjs → android-cas-Dhcjkys1.mjs} +4 -4
  10. package/dist/android-cas-compiler.mjs +1 -1
  11. package/dist/android-image-DFk26aY6.mjs +254 -0
  12. package/dist/{android-project-CCEQyYJK.d.mts → android-project-BDlPnfmL.d.mts} +1 -1
  13. package/dist/api.d.mts +2 -1
  14. package/dist/api.mjs +28 -28
  15. package/dist/{apk-signed-tail-B9Usseps.mjs → apk-signed-tail-CPpA-3vu.mjs} +2 -2
  16. package/dist/{artifact-ta3xA0c4.mjs → artifact-BMjubIP2.mjs} +13 -13
  17. package/dist/{artifact-Cr34-Yyy.mjs → artifact-BufzdGbT.mjs} +34 -21
  18. package/dist/{artifact-platform-BO2Uvk_A.mjs → artifact-platform-DqCWUieN.mjs} +1 -1
  19. package/dist/{auto-placement-DtTRG0rk.mjs → auto-placement-D7P98glJ.mjs} +11 -9
  20. package/dist/{browser-web-DuULNZrS.mjs → browser-web-C74et-Nv.mjs} +15 -15
  21. package/dist/{build-BpFFbdXD.mjs → build-DFBGWOTc.mjs} +23 -23
  22. package/dist/{build-cache-BsKim4V7.mjs → build-cache-Cqj4FGnX.mjs} +20 -8
  23. package/dist/{build-plan-DH1rT11x.mjs → build-plan-T3Hi24ax.mjs} +7 -7
  24. package/dist/{cache-manifest-CfiEny4T.mjs → cache-manifest-8JX9S1QJ.mjs} +1 -1
  25. package/dist/cache-manifest.mjs +1 -1
  26. package/dist/{ccache-DVDO2ocE.mjs → ccache-BXtzEL6M.mjs} +34 -24
  27. package/dist/{cdp-C3svvXiE.mjs → cdp-C216kOAn.mjs} +1 -1
  28. package/dist/{chrome-DyDWurWG.mjs → chrome-C8sC5tdl.mjs} +1 -1
  29. package/dist/{cli-C0jjwTuM.mjs → cli-B2YSjc9s.mjs} +20 -20
  30. package/dist/cli.mjs +1 -1
  31. package/dist/{client-DhJOvSvh.mjs → client-0_Mnfz0a.mjs} +29 -9
  32. package/dist/collector-run.mjs +7 -7
  33. package/dist/{command-output-VrXd6qPX.mjs → command-output-DWI9tGPU.mjs} +1 -1
  34. package/dist/{config-D5qNWJEP.mjs → config-BW0fAtoK.mjs} +256 -246
  35. package/dist/{dependencies-DIU-5rnG.mjs → dependencies-CgvBZbXD.mjs} +39 -39
  36. package/dist/{dependency-state-DZVln1P9.mjs → dependency-state-mL5g4H6K.mjs} +2 -2
  37. package/dist/{detached-entry-BPlSaCwC.mjs → detached-entry-tfrgGVWb.mjs} +1 -1
  38. package/dist/{dev-client-DeAg0fso.mjs → dev-client-ChsHwgrn.mjs} +2 -2
  39. package/dist/{device-C2WsPgFt.mjs → device-B0htCt2u.mjs} +13 -13
  40. package/dist/{device-DuNLOlR6.mjs → device-DOehZpyx.mjs} +11 -11
  41. package/dist/{device-android-BjhH0Ru3.mjs → device-android-B8TQP5AX.mjs} +10 -10
  42. package/dist/{device-capacity-Du5wBTNJ.mjs → device-capacity-BAkETfIl.mjs} +9 -9
  43. package/dist/device-host-worker.mjs +58 -17
  44. package/dist/{device-ios-CUYUhSYO.mjs → device-ios-DFaYFdar.mjs} +9 -9
  45. package/dist/{device-lease-run-CHXQEn-7.mjs → device-lease-run-DpiCnRbZ.mjs} +5 -5
  46. package/dist/{device-pool-kUHO7MHO.mjs → device-pool-DP4sCeCC.mjs} +3 -3
  47. package/dist/{device-provision-e7bKS7lx.mjs → device-provision-CnNOIxCF.mjs} +10 -10
  48. package/dist/{doctor-BGcsAgAV.mjs → doctor-9GrW5YSP.mjs} +30 -17
  49. package/dist/{doctor-B6kIVgU9.mjs → doctor-C6Xn96RS.mjs} +1 -1
  50. package/dist/{doctor-fingerprint-o7ZI9YLn.mjs → doctor-fingerprint-DqWvIhMb.mjs} +1 -1
  51. package/dist/doctor-fingerprint.mjs +1 -1
  52. package/dist/{doctor-hva3sd9f.mjs → doctor-nRLBoajo.mjs} +54 -25
  53. package/dist/{doctor-watchman-DJY550yz.mjs → doctor-watchman-CDhpC3Oh.mjs} +5 -5
  54. package/dist/{eas-build-CBFgseh1.mjs → eas-build-CpJ4h9tG.mjs} +4 -4
  55. package/dist/{eas-fallback-DFXdz4d6.mjs → eas-fallback-B3z5nL1g.mjs} +6 -6
  56. package/dist/{eas-session-ledger-aFBLTZr2.mjs → eas-session-ledger-Bspy-VJQ.mjs} +6 -6
  57. package/dist/{error-diagnostics-CCsq_3uG.mjs → error-diagnostics-DoLGklYX.mjs} +10 -10
  58. package/dist/{exec-aULwtNly.mjs → exec-CGuDzt40.mjs} +103 -103
  59. package/dist/{gc-DASUa3Z_.mjs → gc-BWoOp9q7.mjs} +2 -2
  60. package/dist/{gc-B0K4d_PL.mjs → gc-DolXpMSB.mjs} +25 -54
  61. package/dist/{guide-Civo5-zV.mjs → guide-CmZB0GtP.mjs} +194 -50
  62. package/dist/{hosted-android-CH1Sm4wo.mjs → hosted-android-ByG-ICuh.mjs} +4 -4
  63. package/dist/{hosted-client-5ur3YpxY.mjs → hosted-client-D19Lv0tg.mjs} +6 -5
  64. package/dist/{hosted-logs-BYg4yeti.mjs → hosted-logs-D7anR6Dk.mjs} +17 -11
  65. package/dist/{hosted-logs-sync-BPe8xnMu.mjs → hosted-logs-sync-D182b1eJ.mjs} +5 -5
  66. package/dist/{hosted-macos-BagT0Gn3.mjs → hosted-macos-D0DDQxvl.mjs} +6 -6
  67. package/dist/{hosted-native-kaR4nUHk.mjs → hosted-native-BzXIy97W.mjs} +15 -11
  68. package/dist/{idle-shutdown-BWHQ7mQG.mjs → idle-shutdown-6i8CHoNq.mjs} +6 -6
  69. package/dist/{ios-BKR-Dq46.mjs → ios-AdhPKXO3.mjs} +8 -8
  70. package/dist/{ios-CdAV4-1E.mjs → ios-BdZdNsAj.mjs} +6 -6
  71. package/dist/{ios-CsRVik64.mjs → ios-Qam0bT9n.mjs} +1 -1
  72. package/dist/{ios-DUL68MI5.mjs → ios-dbXzjTxx.mjs} +28 -28
  73. package/dist/{ios-device-CiBA-er9.mjs → ios-device-DLdEDWJj.mjs} +1 -1
  74. package/dist/{ios-device-Dz8gFZ0K.mjs → ios-device-DXbHZfFe.mjs} +3 -3
  75. package/dist/{ios-project-Br1tVYWX.mjs → ios-project-BzfLigfh.mjs} +7 -7
  76. package/dist/{ios-signing-BJzvDPfU.mjs → ios-signing-D-tSX1iF.mjs} +2 -2
  77. package/dist/{ios-state-BEIJRJ7P.mjs → ios-state-CWsBysyN.mjs} +1 -1
  78. package/dist/{js-swap-BfG8XpyS.mjs → js-swap-EDVOJmqx.mjs} +6 -6
  79. package/dist/{launch-CrGndh8T.mjs → launch-CKHpthsw.mjs} +20 -20
  80. package/dist/{lightened-DZ9Ip0T3.mjs → lightened-Cv4ToJRX.mjs} +5 -5
  81. package/dist/{logs-C-hfMsxK.mjs → logs-DCQ3_tGS.mjs} +6 -6
  82. package/dist/{logs-DpIKWT3A.mjs → logs-IagR9dWI.mjs} +7 -7
  83. package/dist/{macos-DZ9ZSolN.mjs → macos-Ch7vuM-G.mjs} +22 -22
  84. package/dist/{macos-DNmKwfDy.mjs → macos-pc0aVVbN.mjs} +1 -1
  85. package/dist/macos-run.mjs +1 -1
  86. package/dist/maintenance-run.mjs +6 -6
  87. package/dist/{metro-mKHEMO-a.mjs → metro-B5PVz0Wv.mjs} +4 -4
  88. package/dist/{metro-request-RDhyx85c.mjs → metro-request-2LmFpC1z.mjs} +9 -3
  89. package/dist/{named-ports-B0hCk2v-.mjs → named-ports-CA0nB9Yw.mjs} +3 -3
  90. package/dist/{native-android-DExhFqR6.mjs → native-android-B3CEDq4R.mjs} +29 -19
  91. package/dist/{native-gradle-artifact-inputs-Bcmbdc23.mjs → native-gradle-artifact-inputs-BLnO2hHR.mjs} +5 -5
  92. package/dist/{native-runtime-D4qgnjK_.mjs → native-runtime-e1OU8gEN.mjs} +6 -6
  93. package/dist/{native-source-D1AzWiuP.mjs → native-source-ChAGj7R1.mjs} +1 -1
  94. package/dist/{native-xcode-inputs-EWma1lXh.mjs → native-xcode-inputs-DL3ETb8s.mjs} +3 -3
  95. package/dist/{native-xcode-ios-Y6rzmWTc.mjs → native-xcode-ios-D4e8k2Jy.mjs} +17 -17
  96. package/dist/offload-worker.d.mts +3 -1
  97. package/dist/offload-worker.mjs +37 -23
  98. package/dist/{operation-exec-Dp4FuIGR.mjs → operation-exec-DKlBcKAL.mjs} +1 -1
  99. package/dist/{ownership-CCfiBfOP.mjs → ownership-hC7xvvxF.mjs} +3 -3
  100. package/dist/{page-CQJlcj3x.mjs → page-Dj8IqvGM.mjs} +2 -2
  101. package/dist/{phone-reverses-Drj5QQCh.mjs → phone-reverses-rvyxW1Fl.mjs} +4 -4
  102. package/dist/{placement-log-CFT8SnlS.mjs → placement-log-nnGnu8mo.mjs} +1 -1
  103. package/dist/{plan-placement-DhKCH_wF.mjs → plan-placement-D3JD-T-K.mjs} +6 -6
  104. package/dist/{ports-BNtJ5DCj.mjs → ports-CZJJfJ8Q.mjs} +3 -3
  105. package/dist/{prebuild-D0hvmO4j.mjs → prebuild-Bhs7TTcz.mjs} +12 -12
  106. package/dist/{project-DCLkDM8C.mjs → project-DWEXiBA9.mjs} +16 -16
  107. package/dist/{pull-request-BzLmzAIQ.mjs → pull-request-BpMTNkMB.mjs} +2 -2
  108. package/dist/pull-requests.mjs +1 -1
  109. package/dist/{react-native-android-Dp7vctEA.mjs → react-native-android-C6Y270GS.mjs} +37 -33
  110. package/dist/{react-native-build-vK2lFYfN.mjs → react-native-build-DaPfzf_e.mjs} +10 -10
  111. package/dist/{react-native-doctor-BtWzwZHU.mjs → react-native-doctor-DGMPxkPS.mjs} +6 -6
  112. package/dist/{react-native-ios-DW1Ax3Yv.mjs → react-native-ios-dX48_92n.mjs} +21 -17
  113. package/dist/{recordings-BWnIlhZH.mjs → recordings-AKZfsW2W.mjs} +1 -1
  114. package/dist/{registration-BwCe64PH.mjs → registration-DKjJGQ6p.mjs} +1 -1
  115. package/dist/{reload-BS_ntVV_.mjs → reload-BGwblBJ9.mjs} +1 -1
  116. package/dist/{reload-B-d7-CsI.mjs → reload-DsOByDfy.mjs} +17 -17
  117. package/dist/{remote-DScVlaMz.mjs → remote-D0uJZ76R.mjs} +9 -9
  118. package/dist/{result-Epkl6gyG.mjs → result-DuimMZKJ.mjs} +24 -20
  119. package/dist/{run-2CHAJ9Oj.mjs → run-N-BbRxnC.mjs} +2 -2
  120. package/dist/{selection-C95m--1_.mjs → selection-xS50Mt0V.mjs} +5 -4
  121. package/dist/{server-bare-CFyVFZXJ.mjs → server-bare-BTlICuaX.mjs} +2 -2
  122. package/dist/{server-command-B1gDRJB2.mjs → server-command-BC0EgMfY.mjs} +5 -5
  123. package/dist/{server-expo-CP4dURQp.mjs → server-expo-15RjL0ir.mjs} +3 -3
  124. package/dist/server-expo-gYIypb0-.mjs +2 -0
  125. package/dist/{settings-C6UTYW2K.mjs → settings-B5IBDfTx.mjs} +4 -4
  126. package/dist/{settings-CjTRNCi3.mjs → settings-CuP55ieT.mjs} +2 -2
  127. package/dist/{settings-payload-zf5EnCTg.mjs → settings-payload-BIGGQ3or.mjs} +5 -5
  128. package/dist/{settings-write-Fe0K6BeC.mjs → settings-write-D85j8mej.mjs} +6 -6
  129. package/dist/settings.schema.json +40 -2
  130. package/dist/{simslim-93xmPh-d.mjs → simslim-DKdJx0LL.mjs} +2 -2
  131. package/dist/{slot-launch-B4MHzVX2.mjs → slot-launch-D4oREwhx.mjs} +6 -6
  132. package/dist/{stage-DDrnM0CY.mjs → stage-DKC6tDXu.mjs} +2 -2
  133. package/dist/{start-LSwIFlBv.mjs → start-BsEV4S-s.mjs} +12 -12
  134. package/dist/{start-BXl5tkv8.mjs → start-DfPSLc__.mjs} +1 -1
  135. package/dist/{state-CM_HvvkS.mjs → state-CtmYTRWm.mjs} +4 -4
  136. package/dist/{state-CiflgxTP.mjs → state-DSOUqO-o.mjs} +2 -2
  137. package/dist/{stats-EgpYD536.mjs → stats-ByEUblPr.mjs} +5 -5
  138. package/dist/{stats-report-B86Cv7Uc.mjs → stats-report-BVRCqwWA.mjs} +1 -1
  139. package/dist/{status-BLDvhatv.mjs → status-C6hLlDqW.mjs} +37 -28
  140. package/dist/{status-GQ-JqvRi.mjs → status-DTFhDnd1.mjs} +1 -1
  141. package/dist/{status-DBMD7ZQT.mjs → status-FP1MH9qn.mjs} +1 -1
  142. package/dist/{status-watch-BwG4lJ1q.mjs → status-watch-D8s823CZ.mjs} +5 -5
  143. package/dist/status-worker.mjs +1 -1
  144. package/dist/{stim-desktop-1XxET4S8.mjs → stim-desktop-_WTria-r.mjs} +2 -2
  145. package/dist/{stop-4SAV_RR8.mjs → stop-5LKfVv-0.mjs} +2 -2
  146. package/dist/{stop-WyrZQuX6.mjs → stop-BVI2-L7s.mjs} +16 -16
  147. package/dist/{stop-BfNhzvXO.mjs → stop-CpTy6bod.mjs} +5 -5
  148. package/dist/supervisor-run.mjs +137 -45
  149. package/dist/{support-Cffz6_Ft.mjs → support-CqyWfZZI.mjs} +18 -8
  150. package/dist/{support-Cs24xRQa.mjs → support-D8OH0z98.mjs} +9 -9
  151. package/dist/{swiftpm-artifact-inputs-yp8D5LE4.mjs → swiftpm-artifact-inputs-uq5oV7xR.mjs} +4 -4
  152. package/dist/{swiftpm-macos-D0CzQtpp.mjs → swiftpm-macos-BuhqYB3n.mjs} +11 -11
  153. package/dist/{toolchain-BEra9AIX.mjs → toolchain-D_jotUG7.mjs} +1 -1
  154. package/dist/{toolchain-CGdgD4x4.mjs → toolchain-s5ZmG42Z.mjs} +25 -14
  155. package/dist/{trigger-CfnOfpDd.mjs → trigger-BtB4kbe0.mjs} +2 -2
  156. package/dist/trigger-D8B7QR0q.mjs +2 -0
  157. package/dist/{warm-progress-_aTMvkIH.mjs → warm-progress-q11Vdvhh.mjs} +6 -6
  158. package/dist/{web-BE89ONcc.mjs → web-DwYCTFdh.mjs} +9 -9
  159. package/dist/web-cCfM8kwV.mjs +2 -0
  160. package/dist/web-run.mjs +8 -8
  161. package/dist/windows-report.mjs +1 -1
  162. package/dist/{workspace-state-3bF4TB8P.mjs → workspace-state-BdZ-QgmB.mjs} +3 -3
  163. package/dist/{workspaces-BNEyJ1B_.mjs → workspaces-B3ahAHZc.mjs} +18 -17
  164. package/dist/{worktree-BTrii9e_.mjs → worktree-BhsML6GV.mjs} +77 -31
  165. package/dist/{worktree-DB3Ypdj6.mjs → worktree-CrjsPIs2.mjs} +1 -1
  166. package/package.json +7 -7
  167. package/dist/server-expo-D3k9mvP8.mjs +0 -2
  168. package/dist/trigger-DBZ-GBrl.mjs +0 -2
  169. package/dist/web-DQPxvFVD.mjs +0 -2
@@ -1,8 +1,8 @@
1
- import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-C6UTYW2K.mjs";
2
- import { i as findProjectRoot$1 } from "./project-DCLkDM8C.mjs";
3
- import { h as RECENT_LAUNCH_MS } from "./eas-session-ledger-aFBLTZr2.mjs";
4
- import { o as guideStatus, t as WATCHMAN_NESTED_WORKTREES } from "./doctor-watchman-DJY550yz.mjs";
5
- import "./status-watch-BwG4lJ1q.mjs";
1
+ import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-B5IBDfTx.mjs";
2
+ import { i as findProjectRoot$1 } from "./project-DWEXiBA9.mjs";
3
+ import { h as RECENT_LAUNCH_MS } from "./eas-session-ledger-Bspy-VJQ.mjs";
4
+ import { o as guideStatus, t as WATCHMAN_NESTED_WORKTREES } from "./doctor-watchman-CDhpC3Oh.mjs";
5
+ import "./status-watch-D8s823CZ.mjs";
6
6
  import { SETTINGS, SETTINGS_SCHEMA_URL, TUTORIAL_VERSION } from "@stim-cli/core/state";
7
7
  import chalk from "chalk";
8
8
  //#region src/guide/agent.ts
@@ -220,6 +220,9 @@ RULES DURING THE LOOP
220
220
  survive the run. Trust the exact device, app, Metro, and launch facts in the
221
221
  final summary. Use the full reported device ID. Never assume a simulator
222
222
  named booted belongs to this workspace.
223
+ - With no matching Android system image, android downloads one (about 2 GB)
224
+ with sdkmanager unless android.installImages is never. It never accepts SDK
225
+ licenses: give the user the refusal's \`sdkmanager --licenses\` command.
223
226
  - After each ios or android run, give the user one compact result: exact device,
224
227
  app id, launch state, cache result, total duration, and whether stim logs
225
228
  --errors passed. Include a remedy only when action remains. Do not repeat the
@@ -291,7 +294,8 @@ replacement runs while one is queued. See \`stim guide lifecycle concurrency\`.
291
294
  After maintenance.idleStopHours (default 6) with no Stim command, native run,
292
295
  Metro bundle or HMR request, agent-device command or live view, automatic
293
296
  maintenance stops the workspace as stim stop does. Device and app logs do not
294
- count. After a long pause, run stim ios or android again before driving the
297
+ count. A device hosted on a remote Mac stops with it, and stim-server stops a hosted
298
+ session whose client has been gone that long. After a long pause, run stim ios or android again before driving the
295
299
  app; see \`stim guide cleanup\`.
296
300
 
297
301
  Treat a refusal as an ownership or state mismatch: read its code and remedy.
@@ -1592,9 +1596,11 @@ RULES
1592
1596
  it; command is the \`xcrun simctl runtime delete\`
1593
1597
  line for a deletable runtime, else null. Stim never
1594
1598
  runs it
1595
- systemImages { package, directory, avdCount, command } installed
1596
- Android system images; avdCount is the AVDs whose
1597
- image.sysdir.1 names it; command is the
1599
+ systemImages { package, directory, avdCount, stimInstalled,
1600
+ command } installed Android system images; avdCount
1601
+ is the AVDs whose image.sysdir.1 names it;
1602
+ stimInstalled is true when this Stim home installed it
1603
+ (android.installImages); command is the
1598
1604
  \`sdkmanager --uninstall\` line. Stim never runs it
1599
1605
  notices why a listing is missing or partial, such as simctl
1600
1606
  timing out or an AVD or system image folder Stim
@@ -1921,6 +1927,12 @@ RULES
1921
1927
  device screens for replay, from recording.enabled
1922
1928
  hidden true when workspace.hidden is set; absent otherwise. The next
1923
1929
  command that uses the workspace clears it.
1930
+ pathMissing true when the workspace folder no longer exists on a mounted
1931
+ volume, such as after git worktree remove or rm -rf; absent
1932
+ otherwise, and for a folder on a volume that is not mounted.
1933
+ phase is then never warming or ready. status only reports it:
1934
+ the entry stays registered until stim gc --delete or
1935
+ stim worktree remove <path> removes it.
1924
1936
 
1925
1937
  Each environment also carries stage, where the workspace is as Stim
1926
1938
  Desktop and the phone app show it: { kind, since, platform, closedApps }.
@@ -2846,7 +2858,7 @@ HOSTED IOS METRO
2846
2858
  Macs; a running Metro or a pin on a port the host uses refuses the run before
2847
2859
  the build. metro.tunnel and metro.publicUrl are ignored. Supervisor restart
2848
2860
  reopens the recorded links; stop or a stopped hosted session closes them. A recorded
2849
- hosted session prevents Metro idle stop. Release runs skip the bridge.
2861
+ hosted session prevents Metro idle stop; maintenance.idleStopHours still stops the workspace and its hosted session (guide cleanup). Release runs skip the bridge.
2850
2862
  Hosted Debug runs require a supervisor and a stim-server that support these
2851
2863
  links before reservation. --no-metro-check refuses; restart a missing or older supervisor
2852
2864
  with stim stop; stim start.
@@ -3875,7 +3887,9 @@ Branch on the code, never on the message.`,
3875
3887
  tailscale ping. Check stim-server and Tailscale there,
3876
3888
  then run stim doctor. Correct --device-type / --runtime for iOS or
3877
3889
  --system-image / --device-profile for Android when the offer names
3878
- an unavailable choice. A session that exists stays recorded even if delivery
3890
+ an unavailable choice. A host that would install a missing Android image
3891
+ but cannot (android.installImages never there, unaccepted licenses, no
3892
+ cmdline-tools, low disk) declines with the command to run on that host. A session that exists stays recorded even if delivery
3879
3893
  fails: retry stim ios|android --remote <machine>, or run stim stop to reconcile it.
3880
3894
  An Expo dev client whose running or pinned Metro port is in use on the host
3881
3895
  refuses before the build: run stim stop, then stim ios --remote <machine>
@@ -4631,6 +4645,12 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
4631
4645
  Mode off, over a cable or over Wi-Fi alike. Hardware is never created or
4632
4646
  booted, so there is nothing to retry into existence: fix the cable, the
4633
4647
  trust prompt, or Developer Mode.
4648
+ On Android it also means no system image matched and Stim could not install
4649
+ one: android.installImages is never, the SDK has no cmdline-tools/latest,
4650
+ the SDK licenses are not accepted (Stim never accepts them; run the
4651
+ \`sdkmanager --licenses\` line the remedy prints), the SDK volume has under
4652
+ 8 GB free, or sdkmanager failed. The remedy names the exact sdkmanager
4653
+ command. Nothing was downloaded or created.
4634
4654
  Otherwise the owned simulator/emulator could not be created or could not
4635
4655
  reach a booted state. \`stim doctor\` checks the toolchain; \`stim status\` says what
4636
4656
  Stim thinks it owns. Re-running the command creates a fresh owned device
@@ -5673,6 +5693,40 @@ not on any remote" (worktree remove)
5673
5693
  };
5674
5694
  //#endregion
5675
5695
  //#region src/guide/lifecycle.ts
5696
+ const HOSTED_RECORDING = (noun) => `\
5697
+ agent-device record start [path] --remote-config <file> records the ${noun};
5698
+ record stop downloads the video to path, or ./recording-<time>.mp4, on this
5699
+ machine. The host writes it only in a private directory for the session in its
5700
+ temporary directory and deletes the files after the download, on stim stop or session teardown and
5701
+ when its daemon restarts. One recording runs per session; a second start, a host output
5702
+ path, record inside batch and a record stop from another agent-device session
5703
+ are refused. The host stops a recording after 10 minutes; a record stop within
5704
+ the next 15 minutes downloads it. A finished recording over 512 MiB is deleted
5705
+ instead. A host whose Stim predates hosted recording refuses
5706
+ record as a command outside its allowed list.`;
5707
+ const HOSTED_COMMANDS = (noun) => `\
5708
+ Allowed commands: devices, open, close, snapshot, diff, wait, find, get, is,
5709
+ click, fill, press, type, focus, scroll, screenshot, longpress, swipe, gesture,
5710
+ back, home, orientation, fold, appstate, alert, batch, record start and stop,
5711
+ action-button, app-switcher, hardware-button, keyboard, apps, capabilities,
5712
+ events, network, react-native, telephony and trigger-app-event. Guarded: push
5713
+ takes <app id> <inline JSON object>, never a payload file; perf allows only
5714
+ frames and memory sample; artifacts lists this session's artifacts and takes no
5715
+ provider session; settings refuses permission accessibility, screen-recording
5716
+ and input-monitoring, which are permissions of the hosting Mac. Each command
5717
+ takes only the flags and input fields Stim lists for it, so a flag a newer
5718
+ agent-device adds is refused until Stim allows it. Host paths and launch inputs
5719
+ are refused: open refuses --metro-host, --metro-port, --bundle-url,
5720
+ --launch-url, --launch-args, --launch-console, --surface and --save-script.
5721
+ Stim's Metro bridge already points the app at this machine's Metro; a client
5722
+ address would let the hosted app reach any service the hosting Mac can.
5723
+ These are refused, each with its reason in the error: install, reinstall,
5724
+ install-from-source and uninstall (Stim installs the app and tracks it), boot,
5725
+ shutdown and close --shutdown (use stim stop), logs (use stim logs), trace,
5726
+ audio, doctor, prepare, replay, test, clipboard (a ${noun} can share the
5727
+ clipboard of the hosting Mac), hover, viewport, tv-remote and agent-device's
5728
+ client-side commands. Both machines need agent-device 0.21.30 or later; an
5729
+ older host reports driver: none.`;
5676
5730
  const lifecycle = {
5677
5731
  summary: "The full worktree -> start -> ios/android -> logs -> teardown flow, with sections for builds, devices and flags",
5678
5732
  preamble: () => `ENVIRONMENT LIFECYCLE
@@ -6191,6 +6245,13 @@ Unreadable android.host blocks only its slot; restore its recorded machine and
6191
6245
  session from the host before stopping that slot.
6192
6246
 
6193
6247
  --system-image and --device-profile select installed choices on the host.
6248
+ When no image on the host matches and the host's android.installImages is
6249
+ auto, the offer names the image to install; stim-server installs it with its
6250
+ own ANDROID_HOME and sdkmanager before it creates the AVD, the client prints
6251
+ \`image installing <package> on <mac>\` and waits for it like any other
6252
+ preparation. A host set to never, or one with unaccepted SDK licenses, no
6253
+ cmdline-tools or under 8 GB free refuses with STIM_HOSTING_REFUSED naming
6254
+ the command to run on the host.
6194
6255
  The build targets the offered ABI and --remote-build independently selects a
6195
6256
  compatible build worker. Stim builds before reserving, records the session as
6196
6257
  soon as it exists, then delivers one App.apk. The emulator boots headless;
@@ -6218,7 +6279,7 @@ Status adds android.host { machine, session, selected, agent, device: { name,
6218
6279
  systemImage, api }, state } per slot. The public name is the profile and API
6219
6280
  level, never the host serial or AVD name. ready, stopped and unverified are
6220
6281
  session probe states; a conflicting local emulator remains visible with a
6221
- warning. A recorded placement keeps the workspace in use and blocks idle stop.
6282
+ warning. A recorded placement keeps the workspace in use and blocks the supervisor's idle stop and device reclaim; maintenance.idleStopHours still stops it once the host confirms the session (guide cleanup, IDLE STOP).
6222
6283
 
6223
6284
  stop and worktree remove wait for device-host.stop, park the host's eligible owned
6224
6285
  emulator within pool.androidParkedMax (delete otherwise), close the Metro links and clear placement. stop --json reports
@@ -6233,13 +6294,18 @@ arrive through local Metro.
6233
6294
  AGENT CONTROL
6234
6295
 
6235
6296
  Set hosting.agentDriver to agent-device on the hosting Mac. Both machines need
6236
- agent-device 0.21.22 or later. The host advertises hosted-android-agent and
6297
+ agent-device 0.21.30 or later. The host advertises hosted-android-agent and
6237
6298
  starts one loopback daemon per installed Android session. Its policy allows
6238
6299
  only the exact ledger-owned emulator serial and denies device shutdown.
6239
6300
  The host verifies the policy digest and android-instance backend before granting
6240
6301
  control. An older host, missing binary or unsupported policy reports driver: none;
6241
6302
  the host's notice explains unavailable control.
6242
6303
 
6304
+ On a local: machine, daemonBaseUrl is http://127.0.0.1:<port> of this
6305
+ workspace's Metro supervisor, which carries each request to the host over its
6306
+ own authenticated device-host connection (host feature hosted-agent-link). It
6307
+ works for Debug runs while stim start runs; Release runs report driver: none.
6308
+
6243
6309
  android.host.agent in stim status --json provides driver, remoteConfig and
6244
6310
  command, never its token. Each slot has a separate 0600 file under the workspace
6245
6311
  state directory at hosted-android/<slot>/agent-device-remote.json. Use that file:
@@ -6253,14 +6319,13 @@ The command shape is agent-device <command> --remote-config <file>. Open leases
6253
6319
  the emulator automatically with android-instance, the proxy provider and this
6254
6320
  session's tenant. devices is permitted for the client's open flow; inventory
6255
6321
  contains only this emulator. Never use its serial with a local agent-device.
6256
- Allowed commands are devices, open, close, snapshot, diff, wait, find, get, is,
6257
- click, fill, press, type, focus, scroll, screenshot, longpress, swipe, back, home,
6258
- orientation, appstate, alert and batch. Stim installs; install, reinstall,
6259
- uninstall, boot, shutdown, close --shutdown, record, logs, uploads and device-wide
6260
- actions are refused. Other serials in commands, flags, inputs, nested batches or
6261
- lease requests are refused. Ambient client paths and owner fields are stripped;
6262
- the host pins platform, serial, tenant, runId, clientId, deviceKey and backend.
6263
- Host paths and launch inputs are refused. Screenshots use only remote artifacts.
6322
+ ${HOSTED_COMMANDS("emulator")}
6323
+ Uploads and other serials in commands, flags, inputs, nested batches or lease
6324
+ requests are refused. Ambient client paths and owner fields are stripped; the
6325
+ host pins platform, serial, tenant, runId, clientId, deviceKey and backend.
6326
+ Screenshots use only remote artifacts.
6327
+
6328
+ ${HOSTED_RECORDING("emulator")}
6264
6329
 
6265
6330
  Stop closes the matching agent-device connection and removes the slot file only
6266
6331
  once the host confirms stop or revocation. Reinstall, stop, revocation and server
@@ -6530,7 +6595,7 @@ host gets an update note, uses uploads and shows logs already copied here.
6530
6595
  AGENT CONTROL
6531
6596
 
6532
6597
  On the hosting Mac, set hosting.agentDriver to agent-device. Both machines need
6533
- agent-device 0.21.20 or later (the policy and remote-config contract). The host
6598
+ agent-device 0.21.30 or later (the policy, command list and remote-config contract). The host
6534
6599
  starts one loopback daemon per installed iOS session under a child-aware
6535
6600
  ownership claim. Its daemon policy pins exactly that simulator UDID and denies
6536
6601
  shutdown. Stop, close, revocation, reinstall and graceful server close end its
@@ -6540,6 +6605,11 @@ session and rotates its grant; rerun stim ios to reattach and refresh the config
6540
6605
  An unresolved proxy or daemon retains its claim and blocks reinstall and native
6541
6606
  teardown; clear a named claim only after proving its owner and child are gone.
6542
6607
 
6608
+ On a local: machine, daemonBaseUrl is http://127.0.0.1:<port> of this
6609
+ workspace's Metro supervisor, which carries each request to the host over its
6610
+ own authenticated device-host connection (host feature hosted-agent-link). It
6611
+ works for Debug runs while stim start runs; Release runs report driver: none.
6612
+
6543
6613
  The client writes a separate 0600 remote-config file for each workspace slot.
6544
6614
  Status prints agent: <command>; ios.host.agent in --json carries driver,
6545
6615
  remoteConfig and command, never the token. Use the returned file:
@@ -6559,23 +6629,22 @@ and removes that slot's config after the host confirms stop or revocation.
6559
6629
  The host stops the session daemon and identity-checked agent-device runners
6560
6630
  targeting its exact simulator UDID before deleting the simulator, even without close.
6561
6631
 
6562
- Allowed: devices, open, close, snapshot, diff, wait, find, get, is, click, fill,
6563
- press, type, focus, scroll, screenshot, longpress, swipe, back, home, orientation,
6564
- appstate, alert and batch. These inspect or interact with the simulator and
6565
- installed apps. devices lists only the session's simulator, filtered by the
6566
- daemon policy. Its device claims are session-local and record / as the workspace;
6632
+ ${HOSTED_COMMANDS("simulator")}
6633
+ These inspect, interact with or record the simulator and installed apps. devices lists only the
6634
+ session's simulator, filtered by the daemon policy. Its device claims are session-local and record / as the workspace;
6567
6635
  a host-side agent-device using the same simulator is not visible to the hosted daemon.
6568
6636
  Client device selectors are stripped and requests are pinned to iOS and that
6569
6637
  UDID; an explicitly named foreign UDID is refused. Selecting another device,
6570
- boot/shutdown/erase, installs, uninstall, uploads, push, record, logs, network,
6571
- perf, trace, clipboard and settings are refused. Stim installs; the agent cannot
6572
- enumerate other host devices or write host files. Ambient client fields (cwd,
6638
+ erase and uploads are refused. The agent cannot enumerate other host devices
6639
+ or write host files. Ambient client fields (cwd,
6573
6640
  stateDir, config and remoteConfig) are stripped, including inside batch steps.
6574
6641
  Host paths and launch inputs (--out, baseline, launchConsole, developerDir,
6575
6642
  installSource and similar fields) are refused, including inside batch steps.
6576
6643
  Only agent-device's generated screenshot temp artifact is accepted and returned
6577
6644
  to the client; arbitrary host screenshot destinations are refused. Runtime
6578
- hints are dropped and only reporting/artifact metadata passes through.
6645
+ hints are refused and only reporting/artifact metadata passes through.
6646
+
6647
+ ${HOSTED_RECORDING("simulator")}
6579
6648
 
6580
6649
  If hosting.agentDriver is none, the driver cannot enforce its policy, or the
6581
6650
  host does not advertise hosted-ios-agent, agent reports
@@ -6915,6 +6984,16 @@ result as proof instead of requiring an unrelated screenshot.`
6915
6984
  is never touched: \`Reclaimed the environment; the working tree stays (it
6916
6985
  is the source checkout).\`
6917
6986
 
6987
+ A worktree deleted outside Stim stays registered. Pass its path to
6988
+ \`worktree remove\`: when the folder is gone from a mounted volume, the
6989
+ command drops the record of that path and of the projects registered under
6990
+ it, with the same \`device\`, \`lease\` and \`workspace\` lines, ending with
6991
+ \`Reclaimed the environment of the deleted folder (its folder is already
6992
+ gone).\` A path on a volume that is not mounted, or one that cannot be
6993
+ resolved, is kept and refused with the reason, since the folder may come
6994
+ back. A missing path with no registered project says \`No such worktree\`.
6995
+ \`stim status\` reports such a workspace as pathMissing.
6996
+
6918
6997
  \`gc\` names each slow step on stderr as it starts, in every mode; its
6919
6998
  report stays on stdout, and with \`--json\` stdout carries only the payload:
6920
6999
 
@@ -7174,8 +7253,9 @@ PREDICTING THE NEXT BUILD (--plan)
7174
7253
  not answer, ios.remote or android.remote set to eas or proxy, or auto that
7175
7254
  would use an EAS Simulator now (remote.easFallback), refuses with
7176
7255
  STIM_BAD_ARG. Without --eas-profile an Android plan also
7177
- refuses the experimental compiler CAS with STIM_BAD_ARG, and refuses with
7178
- STIM_NO_DEVICE when no system image is installed.
7256
+ refuses the experimental compiler CAS with STIM_BAD_ARG. With no system
7257
+ image installed it keys on the image a run would install, and refuses with
7258
+ STIM_NO_DEVICE when android.installImages is never.
7179
7259
 
7180
7260
  IOS SCHEME SELECTION
7181
7261
  Pass \`stim ios --scheme "App Staging"\` to select an exact shared Xcode
@@ -8209,7 +8289,14 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
8209
8289
  A name that is not INSTALLED on this machine refuses with STIM_BAD_ARG
8210
8290
  before anything is created, and the message lists the installed names, so a
8211
8291
  wrong guess is one command, not a created simulator. A blank value is the
8212
- same refusal.
8292
+ same refusal. The exception is an Android system image for this machine's
8293
+ ABI while android.installImages is auto (the default): \`stim android\`
8294
+ installs it with sdkmanager, printing an \`image\` line, then creates the
8295
+ AVD from it. The same applies when no image is installed at all, with
8296
+ system-images;android-36;google_apis;<host ABI>. See \`stim guide settings\`
8297
+ for the license, disk and locking rules. \`stim doctor\` reports a missing
8298
+ image as a note (android-system-image), and \`stim doctor --fix --platform
8299
+ android\` installs it right away.
8213
8300
 
8214
8301
  What counts as installed for \`--device-type\` is what an installed RUNTIME
8215
8302
  can create, not what \`xcrun simctl list devicetypes\` prints: that table
@@ -8849,7 +8936,7 @@ status's maintenance block and the maintenance log.
8849
8936
 
8850
8937
  IDLE STOP: the idle check, and gc --delete unless maintenance.mode is off (its
8851
8938
  dry run lists them in the maintenance plan), stop a workspace whose dev server
8852
- runs or whose owned simulator or emulator is booted once it has had no real
8939
+ runs, whose owned simulator or emulator is booted, or whose device is hosted on a remote Mac once it has had no real
8853
8940
  activity for maintenance.idleStopHours (default 6; 0 never; machine or project
8854
8941
  layers; STIM_MAINTENANCE_IDLE_STOP_HOURS overrides; fractions work). Six hours
8855
8942
  outlasts a lunch break, a meeting or an agent's pause between tasks, and still
@@ -8864,7 +8951,7 @@ only stays connected does not either. The stop is stim stop's: the dev
8864
8951
  server stops, the owned devices shut down through centralized teardown
8865
8952
  (never deleted), and the port is released; device leases stay. A build, a
8866
8953
  held native-run or metro-start lock, a build lock or slot, a running macOS
8867
- app, a hosted or remote session, an unexpired device lease, a managed tunnel
8954
+ app, a remote (EAS) session, an unexpired device lease, a managed tunnel
8868
8955
  or remote lock, a running owned Chrome, a device driver other than
8869
8956
  agent-device, a live agent-device claim with no session activity to judge,
8870
8957
  device activity, an emulator list or an emulator's AVD name that cannot be read keeps
@@ -8877,7 +8964,21 @@ after stim stop, and the supervisor_stopped line in metro.ndjson names
8877
8964
  automatic maintenance and the idle time as the requester. The next start, ios or android starts it
8878
8965
  again. An owned emulator the activity check missed keeps the workspace while
8879
8966
  adb lists it, and so does any emulator adb lists without an AVD name, such as
8880
- a stale offline entry that adb kill-server clears. A dev server that may still run after its supervisor
8967
+ a stale offline entry that adb kill-server clears. A workspace whose iOS, Android or macOS device is hosted on a remote Mac is
8968
+ stopped the same way once the host confirms the session is ready; stim stop's
8969
+ hosted path ends the session and the host parks or tears down the device. A host
8970
+ that does not answer, a session it cannot confirm (unknown, as after a worker
8971
+ crash) and a placement that cannot be read keep the workspace, and a live view of
8972
+ the hosted device is not seen here. On the host, stim-server stops a ready session
8973
+ whose client has had no connection, live stream or Metro link and sent no
8974
+ agent-device request for the host's own machine maintenance.idleStopHours (default 6; 0
8975
+ never; STIM_MAINTENANCE_IDLE_STOP_HOURS overrides), only while its maintenance.mode is on;
8976
+ a project value or maintenance.keep on the client does not reach it. Server downtime is not
8977
+ counted. It uses the stop a person uses, never touches a session whose journal state is
8978
+ preparing, stopping or unknown, or one with a native operation or a claim it cannot prove free
8979
+ (a session a crashed server left ready counts once its claim is proven free),
8980
+ and writes the reason to the server log and the session's idleStop journal field.
8981
+ The count is per client, not per session. A dev server that may still run after its supervisor
8881
8982
  exited is kept until stim stop ends it. So is a dev server whose requests Stim
8882
8983
  does not record: an Expo project before SDK 54, which cannot load Stim's Metro config
8883
8984
  adapter, or a dev server an older Stim started, until stim stop and stim start
@@ -9577,6 +9678,13 @@ ORPHANED WORKSPACE DIRECTORIES
9577
9678
  it. A directory with a missing or unparseable workspace.json, or a root on
9578
9679
  an unmounted volume, is reported under Skipped and never deleted.
9579
9680
 
9681
+ DELETED WORKTREES STILL REGISTERED
9682
+ A worktree deleted outside Stim keeps its registry entry; \`stim status\`
9683
+ marks it pathMissing. \`gc --delete\` prunes every such entry whose folder is
9684
+ gone from a mounted volume. \`stim worktree remove <path>\` prunes one entry,
9685
+ and the projects registered under that path, the same way. Both keep an
9686
+ entry whose volume is not mounted, since the folder may come back.
9687
+
9580
9688
  TMPDIR LEFTOVERS
9581
9689
  \`gc\` without --cache reports recognized entries directly in the user's TMPDIR
9582
9690
  under "TMPDIR leftovers", with their count, size and a remedy: Stim temp
@@ -10309,9 +10417,30 @@ KEYS STIM READS
10309
10417
  from. Readable from the machine layer too, so one
10310
10418
  machine can default every workspace to an image; a
10311
10419
  project layer still wins. The \`--system-image\` flag
10312
- overrides this per invocation, and an id this SDK has
10313
- not installed is STIM_BAD_ARG with the installed ids
10314
- printed, naming the layer the value came from.
10420
+ overrides this per invocation. An id this SDK has not
10421
+ installed is installed first (android.installImages);
10422
+ with installImages never, or an id for another ABI,
10423
+ it is STIM_BAD_ARG with the installed ids printed,
10424
+ naming the layer the value came from.
10425
+ android.installImages auto (default) or never. With auto, when no installed
10426
+ system image matches the request, \`stim android\`
10427
+ installs the one android.systemImage or
10428
+ \`--system-image\` names, else
10429
+ system-images;android-36;google_apis;<host ABI>, with
10430
+ the SDK's own \`sdkmanager --install\` before it
10431
+ creates the owned AVD; a slot whose owned AVD
10432
+ finished a boot keeps it and installs nothing. It
10433
+ installs only images for
10434
+ this machine's ABI, never accepts an SDK license (an
10435
+ unaccepted one refuses and names \`sdkmanager
10436
+ --licenses\`), needs 8 GB free on the SDK volume and
10437
+ cmdline-tools/latest, and runs one install per SDK
10438
+ root and Stim home; a second run waits for it. never
10439
+ refuses with the \`sdkmanager --install\` line instead.
10440
+ For a hosted run the host's machine value decides,
10441
+ and stim-server installs into its own ANDROID_HOME.
10442
+ \`stim gc\` marks the images Stim installed
10443
+ (stimInstalled).
10315
10444
  android.deviceProfile e.g. "pixel_fold" -- the avdmanager hardware profile a
10316
10445
  new owned AVD is created with, spelled exactly as
10317
10446
  \`avdmanager list device -c\` prints it. Defaults to
@@ -10744,7 +10873,8 @@ STIM_HOME and CI make the mode off unless STIM_MAINTENANCE is set.
10744
10873
  maintenance.keep is a project setting: pin a workspace so a pass never clears
10745
10874
  its build outputs or removes its worktree.
10746
10875
  maintenance.idleStopHours takes machine or project layers, so one workspace can
10747
- stop sooner, later or never.
10876
+ stop sooner, later or never. On a hosting Mac stim-server reads its machine value
10877
+ to stop a hosted session whose client has been gone that long.
10748
10878
  See \`guide cleanup\` for checks, plans and log paths.
10749
10879
 
10750
10880
  ${SETTINGS.filter((setting) => setting.key.startsWith("maintenance.") || /^caches\..*MaxGb$/.test(setting.key)).map((setting) => ` ${setting.key} ${setting.env ?? "project setting"} ${setting.default === void 0 ? "unset" : `default ${setting.default}`}
@@ -10941,7 +11071,10 @@ ticket, which is a credential: whoever spends it first, after setup stores it,
10941
11071
  gets the approval, and on a local network that takes only the ticket and a
10942
11072
  route to the worker, not tailnet membership. Agents show it only to the user.
10943
11073
  Offloaded builds and hosted Debug and
10944
- Release runs work there; agent control of hosted apps needs a tailnet machine.
11074
+ Release runs work there. Agent control of hosted iOS and Android Debug runs
11075
+ goes through a loopback port of this workspace's Metro supervisor, which
11076
+ carries it over its own authenticated connection; Release runs and hosted macOS
11077
+ apps there report agent control as none.
10945
11078
  \`stim-server pair\` puts \`ws://<address>:<port>\` in the phone pairing code
10946
11079
  when Tailscale is not running and \`server.lanAddresses\` is set.
10947
11080
 
@@ -11047,9 +11180,8 @@ shared daemon only when that agent-device can lease a single app (its
11047
11180
  notice, and no client is handed the Mac's desktop. STIM_AGENT_DEVICE_BIN in
11048
11181
  stim-server's environment names an agent-device binary to use instead of
11049
11182
  ~/.local/bin/agent-device. Hosted iOS uses one daemon per simulator, pinned by
11050
- its UDID policy; both machines need agent-device 0.21.20 or later. Hosted Android
11051
- uses one daemon per emulator, pinned by its serial policy, with agent-device
11052
- 0.21.22 or later on both machines. See guide lifecycle
11183
+ its UDID policy. Hosted Android uses one daemon per emulator, pinned by its
11184
+ serial policy. Both machines need agent-device 0.21.30 or later. See guide lifecycle
11053
11185
  hosted-ios. \`doctor\` on that Mac notes an installed hosted app that runs while
11054
11186
  the setting is \`none\`.
11055
11187
 
@@ -11078,10 +11210,15 @@ and no platform selection on a Mac, it also checks the macOS Xcode and SDK.
11078
11210
  A client with no Xcode and no simulator SDK, such as Linux or Windows, has no
11079
11211
  Xcode to match: the Mac's own Xcode, simulator SDK and CocoaPods are the
11080
11212
  build's toolchain, the client leaves pod install to it, and \`stim ios --remote
11081
- <mac> --remote-build <mac>\` runs the app on that Mac's hosted simulator. If
11082
- that pod install changes Podfile.lock or the Xcode project, the build fails
11083
- with fingerprint-mismatch; run pod install once on a Mac and commit the
11084
- result. A client with an Xcode still needs the same one.
11213
+ <mac> --remote-build <mac>\` runs the app on that Mac's hosted simulator. When
11214
+ that pod install, or a file it generates there, changes only fingerprint
11215
+ sources in the iOS project, the Mac builds and stores the app under its own
11216
+ fingerprint after pod install, and the client stores it under that key. The
11217
+ client's own fingerprint does not compute that key, so each run builds on the
11218
+ Mac again; a stale Podfile.lock is worth regenerating on a Mac and committing.
11219
+ Any other difference, such as the app config, fails with fingerprint-mismatch.
11220
+ A client with an Xcode still needs the same one, and there a worker pod install
11221
+ that changes the fingerprint fails with fingerprint-mismatch.
11085
11222
  Two machines build for each other when their Stim releases share a build
11086
11223
  compatibility version, which changes only when what a worker builds, how it
11087
11224
  builds, or the build messages change; their Stim builds can differ. A
@@ -11257,7 +11394,10 @@ worker's default: its offer lists \`jdks\`, and a build sent with the build-jdk
11257
11394
  feature runs with JAVA_HOME at the one of that major. A major no installed JDK
11258
11395
  has gets the install command for the worker's OS as doctor's fix. A nearby major
11259
11396
  never counts (Gradle, AGP and Kotlin support and the shared build cache assume
11260
- one JDK). Also, its Android SDK must hold the NDK, build-tools and
11397
+ one JDK). A client with no JDK sends no major, so the worker's default JDK is
11398
+ the build's JDK and doctor notes it; with no Android SDK either, \`stim android
11399
+ --remote <machine> --remote-build <machine>\` runs the app on that machine's
11400
+ hosted emulator. Also, its Android SDK must hold the NDK, build-tools and
11261
11401
  compile platform that the project's React Native version names in
11262
11402
  gradle/libs.versions.toml; Gradle and AGP come from the synced project. A
11263
11403
  package the SDK lacks is a note, not a blocker, when its offer reports the SDK
@@ -12233,6 +12373,10 @@ backend. Reserved names are case-insensitive and trimmed; they refuse with
12233
12373
  STIM_BAD_ARG before state access or a connection. The device pool switches
12234
12374
  (remote.devicePoolDisabled) also apply to automatic macOS placement.
12235
12375
 
12376
+ A hosted app is not kept forever: the idle workspace stop ends its hosted session
12377
+ after maintenance.idleStopHours without activity, and stim-server stops a session
12378
+ whose client has been gone that long (guide cleanup, IDLE STOP).
12379
+
12236
12380
  Logs: the host records the hosted app's stdout, stderr and exit like a local run.
12237
12381
  stim logs, including --errors, --json and --follow, asks the host over the same
12238
12382
  approved connection, copies the records it has not copied yet into the
@@ -1,7 +1,7 @@
1
- import { c as throwIfCancelled } from "./exec-aULwtNly.mjs";
2
- import { c as call, l as connectHost } from "./hosted-client-5ur3YpxY.mjs";
3
- import { i as requestHostedMetro } from "./metro-request-RDhyx85c.mjs";
4
- import { a as stopHostedNative, i as prepareHostedNative, r as placeHostedNative } from "./hosted-native-kaR4nUHk.mjs";
1
+ import { d as throwIfCancelled } from "./exec-CGuDzt40.mjs";
2
+ import { l as call, u as connectHost } from "./hosted-client-D19Lv0tg.mjs";
3
+ import { a as requestHostedMetro } from "./metro-request-2LmFpC1z.mjs";
4
+ import { a as stopHostedNative, i as prepareHostedNative, r as placeHostedNative } from "./hosted-native-BzXIy97W.mjs";
5
5
  //#region src/device-host/hosted-android.ts
6
6
  async function prepareHostedAndroid(machine, selectors, recorded, mode) {
7
7
  return await prepareHostedNative(machine, selectors, recorded, "android", false, mode);
@@ -1,7 +1,7 @@
1
- import { c as throwIfCancelled, o as cancellableSleep } from "./exec-aULwtNly.mjs";
2
- import { X as diagnoseConnectFailure, ct as resolveEndpoint } from "./config-D5qNWJEP.mjs";
3
- import { t as BuildConnection } from "./client-DhJOvSvh.mjs";
4
- import { g as configuredMachines } from "./selection-C95m--1_.mjs";
1
+ import { d as throwIfCancelled, l as cancellableSleep } from "./exec-CGuDzt40.mjs";
2
+ import { K as resolveEndpoint, P as diagnoseConnectFailure } from "./config-BW0fAtoK.mjs";
3
+ import { t as BuildConnection } from "./client-0_Mnfz0a.mjs";
4
+ import { g as configuredMachines } from "./selection-xS50Mt0V.mjs";
5
5
  import { createHash } from "node:crypto";
6
6
  import { lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
7
7
  import { join } from "node:path";
@@ -14,6 +14,7 @@ const HOSTED_REQUEST_MARGIN_MS = 5e3;
14
14
  const workerBoundMs = (deadlineMs) => deadlineMs + hostedWorkerSettleMs();
15
15
  const SESSION_TIMEOUT_MS = hostedWorkerSettleMs() + workerBoundMs(DEVICE_HOST_LIMITS.logsMs) + 2 * workerBoundMs(DEVICE_HOST_LIMITS.stopMs) + HOSTED_POLL_MARGIN_MS;
16
16
  const PREPARE_TIMEOUT_MS = workerBoundMs(DEVICE_HOST_LIMITS.prepareMs) + HOSTED_POLL_MARGIN_MS;
17
+ const IMAGE_INSTALL_TIMEOUT_MS = workerBoundMs(DEVICE_HOST_LIMITS.imageInstallMs);
17
18
  const INSTALL_TIMEOUT_MS = workerBoundMs(DEVICE_HOST_LIMITS.prepareMs) + HOSTED_POLL_MARGIN_MS;
18
19
  const OFFER_TIMEOUT_MS = workerBoundMs(DEVICE_HOST_LIMITS.offerMs) + HOSTED_REQUEST_MARGIN_MS;
19
20
  const RESERVE_TIMEOUT_MS = HOSTED_PARKED_CANDIDATES * (workerBoundMs(DEVICE_HOST_LIMITS.offerMs) + workerBoundMs(DEVICE_HOST_LIMITS.stopMs)) + workerBoundMs(DEVICE_HOST_LIMITS.offerMs) + HOSTED_REQUEST_MARGIN_MS;
@@ -277,4 +278,4 @@ async function upload(host, ids, missing, content) {
277
278
  if (failure) throw failure;
278
279
  }
279
280
  //#endregion
280
- export { stoppedSession as _, SESSION_TIMEOUT_MS as a, call as c, hostConnector as d, hostedSession as f, sha256 as g, settle as h, RESERVE_TIMEOUT_MS as i, connectHost as l, requireHostedAppMode as m, OFFER_TIMEOUT_MS as n, attach as o, probeHostedSession as p, PREPARE_TIMEOUT_MS as r, bundleManifest as s, INSTALL_TIMEOUT_MS as t, heldNoLonger as u, unknownSession as v, upload as y };
281
+ export { sha256 as _, RESERVE_TIMEOUT_MS as a, upload as b, bundleManifest as c, heldNoLonger as d, hostConnector as f, settle as g, requireHostedAppMode as h, PREPARE_TIMEOUT_MS as i, call as l, probeHostedSession as m, INSTALL_TIMEOUT_MS as n, SESSION_TIMEOUT_MS as o, hostedSession as p, OFFER_TIMEOUT_MS as r, attach as s, IMAGE_INSTALL_TIMEOUT_MS as t, connectHost as u, stoppedSession as v, unknownSession as y };
@@ -1,11 +1,11 @@
1
- import { t as getExecutor } from "./exec-aULwtNly.mjs";
2
- import { E as workspaceDir, k as workspaceLogsDir$1 } from "./workspace-state-3bF4TB8P.mjs";
3
- import { J as validateDeviceSlot, V as deviceSlotFileKey, at as parseMachine$1 } from "./config-D5qNWJEP.mjs";
4
- import { l as phaseLine } from "./command-output-VrXd6qPX.mjs";
5
- import { n as macosDir } from "./state-CiflgxTP.mjs";
6
- import { n as androidLogGroups, r as isAndroidCrashText } from "./android-BeeC15Ve.mjs";
1
+ import { t as getExecutor } from "./exec-CGuDzt40.mjs";
2
+ import { E as workspaceDir, k as workspaceLogsDir$1 } from "./workspace-state-BdZ-QgmB.mjs";
3
+ import { l as phaseLine } from "./command-output-DWI9tGPU.mjs";
4
+ import { U as parseMachine$1, _t as validateDeviceSlot, ut as deviceSlotFileKey } from "./config-BW0fAtoK.mjs";
5
+ import { n as macosDir } from "./state-DSOUqO-o.mjs";
6
+ import { n as androidLogGroups, r as isAndroidCrashText } from "./android-B2DSKg-A.mjs";
7
7
  import { c as readNdjsonGenerations$1, i as createNdjsonWriter } from "./ndjson-CrjIsGzw.mjs";
8
- import { c as call } from "./hosted-client-5ur3YpxY.mjs";
8
+ import { l as call } from "./hosted-client-D19Lv0tg.mjs";
9
9
  import { mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { dirname, join } from "node:path";
11
11
  import { LOG_ROTATE_BYTES, ambientWrite, withDirLockAsync } from "@stim-cli/core";
@@ -46,10 +46,16 @@ async function removeAgentAccess(file, keep) {
46
46
  if (path !== keep) rmSync(path, { force: true });
47
47
  }
48
48
  }
49
- async function agentAccess(file, credential, grant, note, platform = "macos") {
49
+ /**
50
+ * Writes the remote config that lets agent-device drive a hosted app and says how to use it. A tailnet machine is
51
+ * reached at its `tailscale serve` route. A local network machine is reached only through `relay`, the loopback port
52
+ * of this workspace's supervisor relay, or not at all when `relay` is the reason there is none.
53
+ */
54
+ async function agentAccess(file, credential, grant, note, platform = "macos", relay = `Agent control of apps hosted on ${credential.machine} over the local network is relayed only for hosted iOS and Android Debug runs.`) {
50
55
  const machine = parseMachine$1(credential.machine);
51
- if (machine?.transport === "local") {
52
- if (grant !== void 0) note(`Agent control of apps hosted on ${credential.machine} needs a tailnet machine; the local network does not carry it.`);
56
+ const local = machine?.transport === "local";
57
+ if (local && typeof relay === "string") {
58
+ if (grant !== void 0) note(relay);
53
59
  await removeAgentAccess(file);
54
60
  return {
55
61
  driver: "none",
@@ -65,7 +71,7 @@ async function agentAccess(file, credential, grant, note, platform = "macos") {
65
71
  const target = client ? join(dirname(file), client.configFile) : file;
66
72
  const access = client && issued ? client.access({
67
73
  grant: issued,
68
- baseUrl: `https://${credential.address}${port === 443 ? "" : `:${port}`}${issued.path}`,
74
+ baseUrl: local ? `http://127.0.0.1:${relay}${issued.path}` : `https://${credential.address}${port === 443 ? "" : `:${port}`}${issued.path}`,
69
75
  file: target,
70
76
  platform
71
77
  }) : null;
@@ -1,8 +1,8 @@
1
- import { n as pullHostedNativeLogs, r as readHostedNativeLogs, t as pullHostedMacosLogs } from "./hosted-logs-BYg4yeti.mjs";
2
- import { l as phaseLine } from "./command-output-VrXd6qPX.mjs";
3
- import { l as connectHost } from "./hosted-client-5ur3YpxY.mjs";
4
- import { n as readHostedIos, t as readHostedAndroid } from "./ios-state-BEIJRJ7P.mjs";
5
- import "./hosted-macos-BagT0Gn3.mjs";
1
+ import { l as phaseLine } from "./command-output-DWI9tGPU.mjs";
2
+ import { n as pullHostedNativeLogs, r as readHostedNativeLogs, t as pullHostedMacosLogs } from "./hosted-logs-D7anR6Dk.mjs";
3
+ import { u as connectHost } from "./hosted-client-D19Lv0tg.mjs";
4
+ import { n as readHostedIos, t as readHostedAndroid } from "./ios-state-CWsBysyN.mjs";
5
+ import "./hosted-macos-D0DDQxvl.mjs";
6
6
  import { watch } from "node:fs";
7
7
  import { dirname, relative, resolve, sep } from "node:path";
8
8
  import { ambientWrite, configDir } from "@stim-cli/core";
@@ -1,9 +1,9 @@
1
- import { o as cancellableSleep } from "./exec-aULwtNly.mjs";
2
- import { a as agentAccess, i as closeAgentConnection, o as removeAgentAccess, t as pullHostedMacosLogs } from "./hosted-logs-BYg4yeti.mjs";
3
- import { l as phaseLine } from "./command-output-VrXd6qPX.mjs";
4
- import { n as macosDir } from "./state-CiflgxTP.mjs";
5
- import { st as runCancellationSignal } from "./toolchain-CGdgD4x4.mjs";
6
- import { _ as stoppedSession, a as SESSION_TIMEOUT_MS, c as call, f as hostedSession, g as sha256, h as settle, i as RESERVE_TIMEOUT_MS, l as connectHost, o as attach, r as PREPARE_TIMEOUT_MS, s as bundleManifest, t as INSTALL_TIMEOUT_MS, u as heldNoLonger, v as unknownSession, y as upload } from "./hosted-client-5ur3YpxY.mjs";
1
+ import { l as cancellableSleep } from "./exec-CGuDzt40.mjs";
2
+ import { l as phaseLine } from "./command-output-DWI9tGPU.mjs";
3
+ import { a as agentAccess, i as closeAgentConnection, o as removeAgentAccess, t as pullHostedMacosLogs } from "./hosted-logs-D7anR6Dk.mjs";
4
+ import { n as macosDir } from "./state-DSOUqO-o.mjs";
5
+ import { st as runCancellationSignal } from "./toolchain-s5ZmG42Z.mjs";
6
+ import { _ as sha256, a as RESERVE_TIMEOUT_MS, b as upload, c as bundleManifest, d as heldNoLonger, g as settle, i as PREPARE_TIMEOUT_MS, l as call, n as INSTALL_TIMEOUT_MS, o as SESSION_TIMEOUT_MS, p as hostedSession, s as attach, u as connectHost, v as stoppedSession, y as unknownSession } from "./hosted-client-D19Lv0tg.mjs";
7
7
  import { randomUUID } from "node:crypto";
8
8
  import { join } from "node:path";
9
9
  import { ambientContext, ambientWrite } from "@stim-cli/core";