stim 1.27.0 → 1.29.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 (154) hide show
  1. package/dist/{acquire-artifact-BKN2Yuhg.mjs → acquire-artifact-C2DKfenN.mjs} +1 -1
  2. package/dist/{act-ROviTF_t.mjs → act-CrTcskiE.mjs} +502 -34
  3. package/dist/{activity-Cd-ysFes.mjs → activity-BR5oHSO5.mjs} +6 -5
  4. package/dist/{agent-device-usage-output-C5nCKWp9.mjs → agent-device-usage-output-W0x4SoC7.mjs} +4 -4
  5. package/dist/{android-DriNoAVy.mjs → android-BHKgeOuq.mjs} +5 -5
  6. package/dist/{android--HBgpvpW.mjs → android-BPmCmyAy.mjs} +5 -5
  7. package/dist/{android-Deb9X3_Y.mjs → android-CLU_MMnb.mjs} +1 -1
  8. package/dist/{android-cas-D5e6ecUg.mjs → android-cas-BH6K12__.mjs} +4 -4
  9. package/dist/{android-Cd6w7_qw.mjs → android-l616dRP1.mjs} +42 -39
  10. package/dist/{android-project-DUGMbq28.d.mts → android-project-CCEQyYJK.d.mts} +6 -2
  11. package/dist/api.d.mts +8 -5
  12. package/dist/api.mjs +27 -27
  13. package/dist/{apk-signed-tail-BHQHx3Rm.mjs → apk-signed-tail-B-wKoF_8.mjs} +2 -2
  14. package/dist/{artifact-0AGJYB9O.mjs → artifact-DHuFYfhD.mjs} +12 -12
  15. package/dist/{artifact-faemIZv5.mjs → artifact-Dm9ScLrh.mjs} +12 -12
  16. package/dist/{auto-placement-z-H5pJza.mjs → auto-placement-C8sJsyMN.mjs} +8 -8
  17. package/dist/{browser-web-slD8AvLp.mjs → browser-web-_tQTbQUs.mjs} +12 -12
  18. package/dist/{build-hS0QyFlQ.mjs → build-DtCU9Kim.mjs} +23 -23
  19. package/dist/{build-cache-gBJ-WKzA.mjs → build-cache-BGwTsIEa.mjs} +4 -4
  20. package/dist/{build-plan-CBqYbzYM.mjs → build-plan-CWyjMPKo.mjs} +6 -6
  21. package/dist/{cache-manifest-DEjqGGat.mjs → cache-manifest-evF_zJ9U.mjs} +1 -1
  22. package/dist/cache-manifest.mjs +1 -1
  23. package/dist/{ccache-BWTze1Ls.mjs → ccache-DsDkdP72.mjs} +19 -18
  24. package/dist/{cli-ftXDLto1.mjs → cli-3fjOg-Oc.mjs} +19 -19
  25. package/dist/cli.mjs +1 -1
  26. package/dist/{client-xsdxrhWA.mjs → client-BTUH8TF1.mjs} +41 -8
  27. package/dist/collector-run.mjs +5 -5
  28. package/dist/{command-output-Dj-WT4BP.mjs → command-output-DjCsmzLZ.mjs} +1 -1
  29. package/dist/{config-Cn94Jc0g.mjs → config-AbUjIBOQ.mjs} +121 -19
  30. package/dist/{dependencies-BGokZ-Ng.mjs → dependencies-CHNqX6Pr.mjs} +38 -38
  31. package/dist/{dependency-state-C3OtgG94.mjs → dependency-state-CPKAKCZ8.mjs} +1 -1
  32. package/dist/{dev-client-BMca82xo.mjs → dev-client-CROrxj1x.mjs} +2 -2
  33. package/dist/{device-tM41-TUq.mjs → device-Bmm5qjM-.mjs} +14 -14
  34. package/dist/device-BvpasThQ.mjs +297 -0
  35. package/dist/{device-capacity-6LP7QsaA.mjs → device-capacity-B2ChA-bz.mjs} +86 -18
  36. package/dist/device-host-worker.mjs +15 -13
  37. package/dist/{device-ios-534c14fz.mjs → device-ios-CYzivd31.mjs} +9 -9
  38. package/dist/{device-lease-run-DwsGfjUN.mjs → device-lease-run-qRq_2W2V.mjs} +4 -4
  39. package/dist/{device-pool-BnQqvs6o.mjs → device-pool-CrmiE4_x.mjs} +3 -3
  40. package/dist/{device-BJm0irrq.mjs → device-provision-CK2XiEp1.mjs} +11 -302
  41. package/dist/{doctor-Dbx1ZpD2.mjs → doctor-BO_kaFWX.mjs} +1 -1
  42. package/dist/{doctor-DyqE9n1J.mjs → doctor-Cp4-HN1f.mjs} +20 -15
  43. package/dist/{doctor-F-3VUUyN.mjs → doctor-Dr3C1iXV.mjs} +19 -19
  44. package/dist/doctor-fingerprint.mjs +1 -1
  45. package/dist/{doctor-watchman-CxDbyrrt.mjs → doctor-watchman-CJr2aXXv.mjs} +4 -4
  46. package/dist/{eas-build-CjNSWmjo.mjs → eas-build-D-9HmGZS.mjs} +2 -2
  47. package/dist/{eas-fallback-9fqb46kW.mjs → eas-fallback-Cemt2GVL.mjs} +4 -4
  48. package/dist/{eas-session-ledger-DrP4OuuM.mjs → eas-session-ledger-B0KLZx5m.mjs} +36 -7
  49. package/dist/{error-diagnostics-snej9k4j.mjs → error-diagnostics-CV_1RoEH.mjs} +8 -8
  50. package/dist/{gc-CGZ1Yg88.mjs → gc-CKHqL4aS.mjs} +81 -18
  51. package/dist/{gc-BRwAY3qT.mjs → gc-DjXwQXHK.mjs} +2 -2
  52. package/dist/{guide-_rfEh_zM.mjs → guide-CeRlWVsS.mjs} +230 -62
  53. package/dist/{hosted-android-BMKzUNnY.mjs → hosted-android-DI_vvv7U.mjs} +5 -6
  54. package/dist/{hosted-client-D7Pk_Oo1.mjs → hosted-client-CgoxdU9j.mjs} +44 -17
  55. package/dist/{hosted-logs-B1gqQuva.mjs → hosted-logs-C-4INmkn.mjs} +17 -8
  56. package/dist/{hosted-logs-sync-Dg3qrZmV.mjs → hosted-logs-sync-Bf5s02fi.mjs} +5 -5
  57. package/dist/{hosted-macos-B9w4H8hc.mjs → hosted-macos-Doh85YUM.mjs} +5 -5
  58. package/dist/{hosted-native-CdgaiuyP.mjs → hosted-native-DvZENAL-.mjs} +11 -8
  59. package/dist/{idle-shutdown-Cbvo5KEh.mjs → idle-shutdown-BM37gMfU.mjs} +7 -7
  60. package/dist/{ios-Bk4mWbtS.mjs → ios-CNDH6fNF.mjs} +8 -8
  61. package/dist/{ios-E26qSpkb.mjs → ios-CoMCWfub.mjs} +4 -4
  62. package/dist/{ios-B5HlVMhQ.mjs → ios-UM_dManb.mjs} +31 -29
  63. package/dist/{ios-device-C_QkIf1Z.mjs → ios-device-L1-pota_.mjs} +1 -1
  64. package/dist/{ios-project-D8Jcy_br.mjs → ios-project-DJYptOCh.mjs} +7 -7
  65. package/dist/{ios-state-BZ03NFgF.mjs → ios-state-Ce_dystM.mjs} +1 -1
  66. package/dist/{js-swap-Dg2a945i.mjs → js-swap-BthE4kZC.mjs} +4 -4
  67. package/dist/{launch-CRyBeNsA.mjs → launch-D798aSm8.mjs} +19 -19
  68. package/dist/{lightened-BCsdAGj_.mjs → lightened-vSxkstg6.mjs} +4 -4
  69. package/dist/{logs-aJQb-RDg.mjs → logs-BND8MiBq.mjs} +9 -8
  70. package/dist/{logs-CC_-ZzEE.mjs → logs-CilPftm3.mjs} +5 -5
  71. package/dist/{macos-BGmTpnv9.mjs → macos-BOQrKYeJ.mjs} +1 -1
  72. package/dist/{macos-DlCBhMw5.mjs → macos-CxUi9xcE.mjs} +20 -20
  73. package/dist/macos-run.mjs +1 -1
  74. package/dist/maintenance-run.mjs +13 -9
  75. package/dist/{metro-CvyD-xwe.mjs → metro-BMQHczcf.mjs} +2 -2
  76. package/dist/{metro-gateway-BnHdqMO_.mjs → metro-request-BtF7ox53.mjs} +25 -46
  77. package/dist/{named-ports-BCyMWA6b.mjs → named-ports-DcktE2Pw.mjs} +2 -2
  78. package/dist/{native-android-DlpxCyOP.mjs → native-android-BkhrCjdX.mjs} +16 -16
  79. package/dist/{native-gradle-artifact-inputs-C13qT7R_.mjs → native-gradle-artifact-inputs-Cw4P6Gyr.mjs} +3 -3
  80. package/dist/{native-runtime-DqaIBO5w.mjs → native-runtime-DyH2gkXK.mjs} +6 -6
  81. package/dist/{native-xcode-inputs-B1W8SrxB.mjs → native-xcode-inputs-DV8jr3kJ.mjs} +2 -2
  82. package/dist/{native-xcode-ios-QPP0Rm68.mjs → native-xcode-ios-DdpPG2iT.mjs} +15 -15
  83. package/dist/{ndjson-Dy2W4vRa.mjs → ndjson-CrjIsGzw.mjs} +2 -2
  84. package/dist/offload-worker.d.mts +1 -1
  85. package/dist/offload-worker.mjs +22 -22
  86. package/dist/{ownership-Bx-0cku-.mjs → ownership-Dtz9G5Gl.mjs} +2 -2
  87. package/dist/{phone-reverses-C9yAaKEv.mjs → phone-reverses-DZRad8HT.mjs} +4 -4
  88. package/dist/{placement-log-BXUbiZM6.mjs → placement-log-CoN6xrjY.mjs} +1 -1
  89. package/dist/{plan-placement-UxnQjv5Z.mjs → plan-placement-7sHuqR-r.mjs} +6 -6
  90. package/dist/{ports-uUrghqWN.mjs → ports-VQSAPZhl.mjs} +3 -3
  91. package/dist/{prebuild-BDpToDgR.mjs → prebuild-Bqp0LFGN.mjs} +9 -9
  92. package/dist/{project-DYj-HVx6.mjs → project-D1n0K4yg.mjs} +15 -15
  93. package/dist/{react-native-android-DDBccgJw.mjs → react-native-android-FQ-yX3Mv.mjs} +22 -22
  94. package/dist/{react-native-build-DaK2IFyP.mjs → react-native-build-D58bIqV9.mjs} +7 -7
  95. package/dist/{react-native-doctor-B-Mw6DcR.mjs → react-native-doctor-AkUH2aca.mjs} +5 -5
  96. package/dist/{react-native-ios-DjYwUF9U.mjs → react-native-ios-Dmsv8j7T.mjs} +14 -14
  97. package/dist/{recordings-C20iUZfp.mjs → recordings-CHMaF73C.mjs} +1 -1
  98. package/dist/{reload-fUdkH2_p.mjs → reload-BV0nD-k9.mjs} +14 -14
  99. package/dist/{reload-DJBeF_rC.mjs → reload-CDKEzzaf.mjs} +1 -1
  100. package/dist/{remote-y6n99WMW.mjs → remote-C8xyslUa.mjs} +9 -9
  101. package/dist/{result-CTqBw2Te.mjs → result-9fqcJ90W.mjs} +16 -16
  102. package/dist/{run-DaCeNKRm.mjs → run-BQAmrohh.mjs} +2 -2
  103. package/dist/{selection-Bs8phwhN.mjs → selection-D1ZDzHFX.mjs} +105 -62
  104. package/dist/{server-bare-BOh-iZEj.mjs → server-bare-CEQdB_F4.mjs} +37 -1
  105. package/dist/{server-command-8CuA51Cv.mjs → server-command-RlS-Kl4a.mjs} +5 -5
  106. package/dist/server-expo-BVV9qy31.mjs +2 -0
  107. package/dist/{server-expo-ABQs2XFA.mjs → server-expo-bB1VV2k-.mjs} +8 -5
  108. package/dist/{settings-CMHhQNwI.mjs → settings-BcVCcAT5.mjs} +2 -2
  109. package/dist/{settings-BDVI8Ivc.mjs → settings-D776ygML.mjs} +47 -3
  110. package/dist/{settings-Djl-mpjX.mjs → settings-D9LtQaUw.mjs} +2 -1
  111. package/dist/{settings-payload-cm60Zhib.mjs → settings-payload-_aatELz2.mjs} +4 -4
  112. package/dist/{settings-write-BdNRLlBn.mjs → settings-write-CkTVGQ4O.mjs} +5 -5
  113. package/dist/settings.schema.json +58 -9
  114. package/dist/{simslim-DCQwzoPy.mjs → simslim-CbpHERcv.mjs} +1 -1
  115. package/dist/{slot-launch-0l7RqSpr.mjs → slot-launch-Dbgfh8gc.mjs} +6 -6
  116. package/dist/{stage-F4cAfJGi.mjs → stage-BuHuRj1y.mjs} +1 -1
  117. package/dist/{start-DcqnF9p8.mjs → start-Cr-c3Xhq.mjs} +1 -1
  118. package/dist/{start-DrPwER_2.mjs → start-Dlv4XXTP.mjs} +11 -11
  119. package/dist/{state-CZxLyetD.mjs → state-C2AUjjhg.mjs} +1 -1
  120. package/dist/{state-BX1y5syV.mjs → state-D5ZxwCGJ.mjs} +2 -2
  121. package/dist/{stats-GxuCbles.mjs → stats-D5c-uIBp.mjs} +4 -4
  122. package/dist/{status-7ULDEJ1e.mjs → status-CK7ZoEhV.mjs} +2 -2
  123. package/dist/{status-BfnK9pUd.mjs → status-D6PBK6_-.mjs} +49 -26
  124. package/dist/{status-Bj7ZYvvc.mjs → status-DbQv--Yb.mjs} +1 -1
  125. package/dist/{status-watch-BfabQn03.mjs → status-watch-okrpea4i.mjs} +17 -6
  126. package/dist/status-worker.mjs +1 -1
  127. package/dist/{stim-desktop-CbWo21kb.mjs → stim-desktop-CYXLFpFS.mjs} +1 -1
  128. package/dist/{stop-x1Yu3He4.mjs → stop-CHtAiv79.mjs} +2 -2
  129. package/dist/{stop-D-EAr25B.mjs → stop-p9uSKuGE.mjs} +20 -19
  130. package/dist/{stop-CH79S3IZ.mjs → stop-uRQ-zYcl.mjs} +9 -5
  131. package/dist/supervisor-run.d.mts +1 -0
  132. package/dist/supervisor-run.mjs +243 -65
  133. package/dist/{support-Be0UeVZU.mjs → support-BMpQIug0.mjs} +11 -10
  134. package/dist/{support-CNg_YsOk.mjs → support-PFyTkrnr.mjs} +4 -4
  135. package/dist/{swiftpm-artifact-inputs-uPqYvGBv.mjs → swiftpm-artifact-inputs-Cddq6jN2.mjs} +1 -1
  136. package/dist/{swiftpm-macos-Ch4YjY_A.mjs → swiftpm-macos-BSj9iZlI.mjs} +8 -8
  137. package/dist/{toolchain-JYAOquPg.mjs → toolchain-B-mzR9Rh.mjs} +1 -1
  138. package/dist/{toolchain-CbCG6C5Z.mjs → toolchain-CLGnEUgT.mjs} +4 -4
  139. package/dist/{trigger-DMou-X7j.mjs → trigger-CfnOfpDd.mjs} +1 -1
  140. package/dist/trigger-DBZ-GBrl.mjs +2 -0
  141. package/dist/{warm-progress-C0RsbngN.mjs → warm-progress--KkkBBaq.mjs} +3 -3
  142. package/dist/web-BxSo493O.mjs +2 -0
  143. package/dist/web-run.mjs +5 -5
  144. package/dist/{web-Cq_AQ4DK.mjs → web-xlVssjQf.mjs} +8 -8
  145. package/dist/{workspace-state-BjqdjnJR.mjs → workspace-state-DGwkPXwq.mjs} +2 -2
  146. package/dist/{workspaces-DFbj07jp.mjs → workspaces-CvSYD_78.mjs} +106 -26
  147. package/dist/{worktree-COAJ3-OD.mjs → worktree-CaQBf6kh.mjs} +26 -47
  148. package/dist/worktree-DTOIohFe.mjs +2 -0
  149. package/package.json +7 -7
  150. package/shim/bundle-response.cjs +37 -0
  151. package/dist/server-expo-Ba_Y21vB.mjs +0 -2
  152. package/dist/trigger-qp2ji5wE.mjs +0 -2
  153. package/dist/web-Je6abcpz.mjs +0 -2
  154. package/dist/worktree-JGUd_53L.mjs +0 -2
@@ -1,8 +1,8 @@
1
- import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-BDVI8Ivc.mjs";
2
- import { i as findProjectRoot$1 } from "./project-DYj-HVx6.mjs";
3
- import { h as RECENT_LAUNCH_MS } from "./eas-session-ledger-DrP4OuuM.mjs";
4
- import { o as guideStatus, t as WATCHMAN_NESTED_WORKTREES } from "./doctor-watchman-CxDbyrrt.mjs";
5
- import "./status-watch-BfabQn03.mjs";
1
+ import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-D776ygML.mjs";
2
+ import { i as findProjectRoot$1 } from "./project-D1n0K4yg.mjs";
3
+ import { h as RECENT_LAUNCH_MS } from "./eas-session-ledger-B0KLZx5m.mjs";
4
+ import { o as guideStatus, t as WATCHMAN_NESTED_WORKTREES } from "./doctor-watchman-CJr2aXXv.mjs";
5
+ import "./status-watch-okrpea4i.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
@@ -288,6 +288,12 @@ activity prevent reclaim. The supervisor's own idle shutdown default is 30m.
288
288
  Read the holder names in progress and build.waitingFor in status; do not start
289
289
  replacement runs while one is queued. See \`stim guide lifecycle concurrency\`.
290
290
 
291
+ After maintenance.idleStopHours (default 6) with no Stim command, native run,
292
+ Metro bundle or HMR request, agent-device command or live view, automatic
293
+ 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
295
+ app; see \`stim guide cleanup\`.
296
+
291
297
  Treat a refusal as an ownership or state mismatch: read its code and remedy.
292
298
  Never reach for --force first.
293
299
  Stim leaves externally started Metro servers alone. Stop them with their original
@@ -1236,9 +1242,10 @@ leased until <time>" for each one.`,
1236
1242
  null when off; plan lists what the next start, ios or
1237
1243
  android would reclaim, in the \`reclaimed\` shape without
1238
1244
  freedMb, and is empty while under budget
1239
- deviceHosts one { machine, state, dnsName?, deviceId?, requestedAt?, expiresAt?,
1240
- host? } per remote.machines entry. state is "approved",
1241
- "pending", "not-asked", "revoked", "lapsed", "key-changed", "outdated",
1245
+ deviceHosts one { machine, state, dnsName?, fingerprint?, deviceId?, requestedAt?,
1246
+ expiresAt?, host? } per remote.machines entry. state is "approved",
1247
+ "pending", "not-asked", "revoked", "lapsed", "key-changed",
1248
+ "key-unconfirmed", "outdated",
1242
1249
  "not-on-tailnet", "tailscale-off", "unreachable", "invalid",
1243
1250
  "credentials-unavailable" or "busy". Setup tickets stay private.
1244
1251
  Only --fix asks for access or forgets removed names. A
@@ -1254,7 +1261,12 @@ leased until <time>" for each one.`,
1254
1261
  expires, absent for a Stim Desktop ticket; "lapsed" is a
1255
1262
  pending request whose expiry passed. --fix asks again.
1256
1263
  "key-changed" means the worker did not prove the
1257
- stim-server key pinned at approval. "outdated" means its
1264
+ stim-server key pinned at approval. "key-unconfirmed" is a
1265
+ local: machine that approved this one but whose key no
1266
+ person confirmed, so nothing pinned it; fingerprint is the
1267
+ key's fingerprint to compare with the one stim-server setup
1268
+ printed there, and only stim doctor --fix in a terminal asks.
1269
+ A local: entry has no dnsName. "outdated" means its
1258
1270
  stim-server speaks protocol 1; the finding names the
1259
1271
  stim-server service update command to run there.
1260
1272
  toolchain { entries, projectNode } on macOS, else null. entries is one { name, value,
@@ -1267,11 +1279,12 @@ leased until <time>" for each one.`,
1267
1279
  pins Node (bin, version and match are null when no install
1268
1280
  fits the pin; match is "exact", or "major" for the newest
1269
1281
  install of the pinned major not older than the pin), else null
1270
- remoteMachines one { machine, state, diagnosis?, dnsName?, deviceId?, requestedAt?,
1271
- expiresAt?, offloadable?, reasons?, problems?, capacity?, host? } per
1282
+ remoteMachines one { machine, state, diagnosis?, dnsName?, fingerprint?, deviceId?,
1283
+ requestedAt?, expiresAt?, offloadable?, reasons?, problems?, capacity?, host? } per
1272
1284
  remote.machines entry, for its build approval; state is "approved", "pending", "not-asked",
1273
1285
  "revoked" (revoked or denied), "lapsed" (the request lapsed
1274
- before approval), "key-changed", "outdated",
1286
+ before approval), "key-changed", "key-unconfirmed" (as in
1287
+ deviceHosts), "outdated",
1275
1288
  "not-on-tailnet", "tailscale-off", "unreachable" or
1276
1289
  "invalid". diagnosis is { layer, code, title, message, remedy }
1277
1290
  for the first layer that stopped this machine, present for
@@ -1286,6 +1299,11 @@ leased until <time>" for each one.`,
1286
1299
  nothing behind the route), server-not-ready (503: running but
1287
1300
  not serving; its message gives the cause the server reports),
1288
1301
  server-no-answer (silent route while tailscale ping reaches the Mac), server-outdated and connect-failed (none of the above).
1302
+ A local: machine never reads Tailscale and reports
1303
+ lan-not-listening (nothing accepts connections on its
1304
+ stim-server port), lan-no-answer (no reply: the network, or
1305
+ the macOS firewall on that machine), server-not-ready or
1306
+ connect-failed.
1289
1307
  Tailscale's own "offline" flag lags a reachable peer, so an
1290
1308
  answer from the machine outranks it. host has the same shape and presence rule as in
1291
1309
  deviceHosts, as do expiresAt (a pending request's lapse
@@ -1834,8 +1852,8 @@ RULES
1834
1852
  reason is null for an entry --delete acts on, and otherwise a stable code
1835
1853
  to branch on; detail is the text line, for the user. Never parse detail.
1836
1854
  A linked worktree's detail is never null.
1837
- workspaceBuildOutputs unresolved | in-use | last-use-unknown |
1838
- recently-used
1855
+ workspaceBuildOutputs unresolved | locked | lock-unknown | in-use |
1856
+ last-use-unknown | recently-used
1839
1857
  workspaceLogs unresolved | in-use | collector
1840
1858
  recordings unresolved | retained | recently-recorded
1841
1859
  memory in-use | busy | unknown | build-running |
@@ -2041,7 +2059,7 @@ RULES
2041
2059
  Each booted simulator and detected emulator in environments (and in
2042
2060
  slots) carries activity; a shut-down or physical device has none:
2043
2061
 
2044
- activity { state, driver?, lastActivityAt?, recent?, basis }
2062
+ activity { state, driver?, lastActivityAt?, recent?, basis, unknown? }
2045
2063
 
2046
2064
  state "driven" a live claim or driver holds the device now
2047
2065
  "active" no driver, but activity in the last 10 minutes
@@ -2064,6 +2082,8 @@ RULES
2064
2082
  workspace-use, supervisor-start, page-log or viewer, each
2065
2083
  rounded down to the minute. viewer is now while a
2066
2084
  stim-server client streams the device's frames
2085
+ unknown for "driven" only: the checks that could not be read, in
2086
+ basis's vocabulary; absent when every check was read
2067
2087
  basis the evidence behind state, strongest first:
2068
2088
  agent-device-claim, agent-device-lease agent-device state,
2069
2089
  read only; live only when every recorded process is alive
@@ -2445,8 +2465,8 @@ RULES
2445
2465
  minutes. It caches them in $STIM_HOME/agent-sessions.json, which one-shot
2446
2466
  status reads and ignores once it is 2 minutes old. Both sources are other
2447
2467
  tools' internal files; a missing or changed one only drops its sessions.
2448
- \`start\`, \`ios\`, \`android\`, \`web\`, \`reload\` and \`worktree warm\`
2449
- also record the CLAUDE_CODE_SESSION_ID or CODEX_THREAD_ID of the shell
2468
+ \`start\`, \`ios\`, \`android\`, \`web\`, \`reload\`, \`logs\` and
2469
+ \`worktree warm\` also record the CLAUDE_CODE_SESSION_ID or CODEX_THREAD_ID of the shell
2450
2470
  that ran them, so that session is listed for 30 minutes after the command
2451
2471
  even when status cannot see it, and for as long as it runs.
2452
2472
 
@@ -2480,7 +2500,35 @@ RULES
2480
2500
 
2481
2501
  capacity.committedMb sums memoryMb; in a \`status --watch --json\` line each
2482
2502
  figure, including an environment's memoryMb, is held on its own (see
2483
- \`guide lifecycle\`), so the sums can differ from what they sum. The memory budget plans before a boot
2503
+ \`guide lifecycle\`), so the sums can differ from what they sum.
2504
+
2505
+ capacity.load is always present. capacity.builds is present only while
2506
+ concurrency.maxBuilds is set, and capacity.devices only while
2507
+ concurrency.maxDevices is set (see \`guide lifecycle concurrency\`):
2508
+
2509
+ load { cpus, loadPerCore, busyAt, limit, state }. loadPerCore is the
2510
+ 5-minute load average divided by cpus, to one decimal. busyAt is
2511
+ server.maxLoadPerCore (\`guide settings\`). state is free under
2512
+ busyAt, busy at or over it, where automatic placement prefers
2513
+ another machine, or holding at or over limit. limit is null
2514
+ because no setting sets it yet, so state is never holding.
2515
+
2516
+ builds { max, inUse, holders: [{ slot, workspace, client, since,
2517
+ unresolved? }] }. inUse counts the slots below max that a new
2518
+ build cannot take. workspace is the root of the local build in
2519
+ the slot; client is the device id of the client whose offloaded
2520
+ build this machine runs in it. An unresolved slot has a claim
2521
+ whose holder Stim cannot identify; both are null, and the slot
2522
+ stays in use until that claim is removed.
2523
+ devices { max, inUse, unknown?, holders: [{ platform, label, workspace,
2524
+ slot, booting? }] }, the owned devices the cap counts: booted or
2525
+ booting stim simulators, owned emulators adb lists, and boots in
2526
+ progress. label is the label of the workspace that records the
2527
+ device, with its device slot; for a device no workspace records,
2528
+ label is its name and workspace and slot are null. inUse is null
2529
+ and unknown says why when the devices could not be listed.
2530
+
2531
+ The memory budget plans before a boot
2484
2532
  and always uses the estimate. What is using CPU and memory now is the
2485
2533
  top-level machine section:
2486
2534
 
@@ -2779,19 +2827,19 @@ comes from \`start --remote\`, eas/proxy in \`ios.remote\`, or \`android.remote\
2779
2827
 
2780
2828
  HOSTED IOS METRO
2781
2829
  ios --remote <machine> keeps Metro local and needs no start --remote.
2782
- The supervisor watches private gateway requests in workspace state, binds
2783
- only this machine's Tailscale address and accepts only the pinned hosting peer
2784
- with a per-session secret. The host's bridge is loopback-only. For an Expo
2785
- dev client it listens on this machine's Metro port, which the dev server
2830
+ The supervisor watches hosted Metro requests in workspace state and keeps a
2831
+ few authenticated connections open to the host for each session. The host
2832
+ pairs one with each connection the device makes to its loopback-only bridge,
2833
+ and the supervisor forwards it to this Metro, so the host never connects back
2834
+ to this machine and a shared or ACL-restricted host works. For an Expo
2835
+ dev client the bridge listens on this machine's Metro port, which the dev server
2786
2836
  writes into the manifest. ios --remote starts Metro on a port free on both
2787
2837
  Macs; a running Metro or a pin on a port the host uses refuses the run before
2788
- the build. Port and secret
2789
- stay in 0600 workspace state and never appear in status, JSON or logs.
2790
- metro.tunnel and metro.publicUrl are ignored. Supervisor restart recreates
2791
- the recorded gateway; stop or a stopped hosted session closes it. A recorded
2838
+ the build. metro.tunnel and metro.publicUrl are ignored. Supervisor restart
2839
+ reopens the recorded links; stop or a stopped hosted session closes them. A recorded
2792
2840
  hosted session prevents Metro idle stop. Release runs skip the bridge.
2793
- Hosted Debug runs require the supervisor's private gateway support before
2794
- reservation. --no-metro-check refuses; restart a missing or older supervisor
2841
+ Hosted Debug runs require a supervisor and a stim-server that support these
2842
+ links before reservation. --no-metro-check refuses; restart a missing or older supervisor
2795
2843
  with stim stop; stim start.
2796
2844
  Native iOS and Android logs are pulled from the host by stim logs, including --errors;
2797
2845
  JavaScript logs still arrive through Metro. Stop pulls native logs before
@@ -2853,8 +2901,8 @@ BUNDLE WARMUP
2853
2901
  device logs may prove a request, but bundle completion may stay unverified.
2854
2902
 
2855
2903
  HOSTED ANDROID
2856
- android --remote <machine> keeps Metro here through the private tailnet
2857
- gateway. The host reverses the client Metro port into its loopback bridge
2904
+ android --remote <machine> keeps Metro here through the same client-opened
2905
+ links as hosted iOS. The host reverses the client Metro port into its loopback bridge
2858
2906
  on the exact owned emulator. Each run and reload restores that reverse;
2859
2907
  no adb command for the host serial runs here. metro.tunnel and metro.publicUrl
2860
2908
  are ignored. See guide lifecycle hosted-android.
@@ -2962,8 +3010,8 @@ WHAT THE SUPERVISOR IS
2962
3010
  (default 60; 0 never stops) with no bundle request, no client log record
2963
3011
  (in-app console logs; for Expo or metro.command, any stdout line of the
2964
3012
  dev server) and no Stim
2965
- command in the workspace (start, ios, android, reload, worktree warm). It
2966
- checks once a minute. It keeps running while a bundle response is in
3013
+ command in the workspace (start, ios, android, reload, logs, worktree
3014
+ warm). It checks once a minute. It keeps running while a bundle response is in
2967
3015
  flight, while a build in the workspace is in progress, while a stim ios,
2968
3016
  android or stop run holds the workspace's native-run lock, while the
2969
3017
  workspace holds an unexpired device lease (\`stim device lock\` or a
@@ -2996,8 +3044,9 @@ WHAT THE SUPERVISOR IS
2996
3044
  own stops show only in the log).
2997
3045
  requested a Stim command stopped it and says which: stim stop,
2998
3046
  stim worktree remove, stim gc --delete, stim start
2999
- --reset-cache, or budget reclaim (with the workspace whose
3000
- ios, android or start run reclaimed it)
3047
+ --reset-cache, budget reclaim (with the workspace whose
3048
+ ios, android or start run reclaimed it), or automatic
3049
+ maintenance with its idle reason (guide cleanup, IDLE STOP)
3001
3050
  signal a SIGTERM or SIGINT with no Stim stop request recorded,
3002
3051
  so it likely came from outside Stim (level warn)
3003
3052
  server-exited the dev server exited on its own (level error). Expo CLI
@@ -3487,7 +3536,15 @@ msg and
3487
3536
  failure failed or cancelled runs: { code, message, remedy, phase }
3488
3537
  device { name, runtime? } of the simulator, emulator or device;
3489
3538
  never its serial or UDID
3539
+ loadPerCore this machine's 5-minute load average per CPU when the run
3540
+ started, to one decimal
3541
+ boot { startedAt, loadPerCore } of the run's first owned
3542
+ simulator or emulator boot: epoch milliseconds when it
3543
+ started, once any concurrency.maxDevices wait was over,
3544
+ and the load per core then. Absent when the run booted
3545
+ nothing.
3490
3546
  stimVersion the stim that ran the build
3547
+ Records written before these fields existed lack loadPerCore and boot.
3491
3548
  A run that stopped before it had an app to build (a refused flag, a missing
3492
3549
  project) writes no record. Writing the record never changes the run's result.
3493
3550
 
@@ -3591,7 +3648,9 @@ WHAT WRITES WHAT
3591
3648
  and, on Expo, one per dev-client manifest
3592
3649
  request (manifest_request_started, _finished,
3593
3650
  _failed: debug level, with platform and requestId;
3594
- launch verification reads them as progress)
3651
+ launch verification reads them as progress), and
3652
+ an hmr_update debug record, at most once a minute,
3653
+ when Metro pushes a Fast Refresh change to the app
3595
3654
  client.ndjson in-app console logs and redboxes -- BARE PROJECTS ONLY.
3596
3655
  In expo-child and command-child mode everything the
3597
3656
  dev server prints lands in metro.ndjson with raw: true,
@@ -5661,7 +5720,7 @@ STIM_SUPERVISOR_EXITED, ...) before any build work. Release builds and
5661
5720
  \`--no-metro-check\` neither check nor start the dev server; hosted Debug iOS
5662
5721
  refuses --no-metro-check with STIM_BAD_ARG. \`--remote\`
5663
5722
  with eas or proxy starts it the way \`stim start --remote\` does. A named
5664
- hosting Mac keeps Metro local through a private bridge; see hosted-ios. Step 2 remains useful to warm
5723
+ hosting Mac keeps Metro local through links this machine opens; see hosted-ios. Step 2 remains useful to warm
5665
5724
  Metro while other work happens.
5666
5725
 
5667
5726
  Each time Stim boots an owned local simulator or emulator, it mutes it: iOS
@@ -5841,7 +5900,8 @@ WAITING FOR A CHANGE
5841
5900
  status payload per line: one at once, then one each time the payload
5842
5901
  changes, never two identical ones in a row. In a watch line, a usage
5843
5902
  figure repeats its value in the previous line until it moves by a step: an owner's cpuPercent 5 points, an
5844
- owner's or environment's memoryMb and capacity.committedMb 16 MB. An owner's row
5903
+ owner's or environment's memoryMb and capacity.committedMb 16 MB, and
5904
+ capacity.load as a whole until its loadPerCore moves 1 per core or its state changes. An owner's row
5845
5905
  changes as a whole, so its residentMb and processes update with it. A change
5846
5906
  in only a bookkeeping timestamp prints no line: each pullRequest.checkedAt,
5847
5907
  maintenance.lastChecks, maintenance.lastPass.startedAt and durationMs, and
@@ -6087,8 +6147,8 @@ soon as it exists, then delivers one App.apk. The emulator boots headless;
6087
6147
  androidEmulatorApp is ignored with a note.
6088
6148
 
6089
6149
  React Native Debug requires the local Metro supervisor. metro.publicUrl and metro.tunnel
6090
- are ignored with a note. A private tailnet gateway reaches the host loopback
6091
- bridge; the host reverses the client's Metro port into that bridge on its exact
6150
+ are ignored with a note. Connections this machine opens to the host carry each
6151
+ device connection from the host loopback bridge to local Metro; the host reverses the client's Metro port into that bridge on its exact
6092
6152
  ledger-owned serial and sets debug_http_host to localhost:<clientMetroPort>.
6093
6153
  Each run and stim reload android restores the reverse, including after a host
6094
6154
  adb server restart. Reload broadcasts through the local Metro and never runs
@@ -6111,7 +6171,7 @@ session probe states; a conflicting local emulator remains visible with a
6111
6171
  warning. A recorded placement keeps the workspace in use and blocks idle stop.
6112
6172
 
6113
6173
  stop and worktree remove wait for device-host.stop, park the host's eligible owned
6114
- emulator within pool.androidParkedMax (delete otherwise), close the gateway and clear placement. stop --json reports
6174
+ emulator within pool.androidParkedMax (delete otherwise), close the Metro links and clear placement. stop --json reports
6115
6175
  outcomes.device["android:host:<slot>"]. Forbidden or unknown-session also clears
6116
6176
  placement; an unreachable host keeps it and fails cleanup. A clean host restart
6117
6177
  parks eligible devices; a later reserve by the same client adopts a compatible
@@ -6317,9 +6377,10 @@ sessions.
6317
6377
 
6318
6378
 
6319
6379
  Stim builds or fetches before reserving, records the session immediately, then
6320
- uploads the app on every run. React Native and Expo Debug keep Metro here; the supervisor owns a
6321
- private gateway bound to this machine's Tailscale address, pinned to the host peer
6322
- and protected by a per-session secret. The host exposes only a loopback bridge.
6380
+ uploads the app on every run. React Native and Expo Debug keep Metro here; the supervisor keeps
6381
+ authenticated connections open to the host, and the host pairs one with each
6382
+ connection the simulator makes to its loopback-only bridge. The host never
6383
+ connects back to this machine.
6323
6384
  For an Expo dev client the bridge listens on this machine's Metro port, because
6324
6385
  the dev server writes that port into the manifest's bundle URL. When this run
6325
6386
  starts Metro, it asks the host and picks a port free on both Macs, moving the
@@ -6327,8 +6388,8 @@ recorded port if the host uses it. A running Metro or a metro.port pin on a port
6327
6388
  the host uses refuses before the build: run stim stop, then stim ios --remote
6328
6389
  <machine> without stim start, or pin a port free on both Macs.
6329
6390
  No start --remote is needed; metro.tunnel and metro.publicUrl are ignored.
6330
- Debug requires a running supervisor with private gateway support before reserving
6331
- a simulator. --no-metro-check refuses with STIM_BAD_ARG for hosted Debug runs.
6391
+ Debug requires a running supervisor and a host stim-server that support these
6392
+ links before reserving a simulator. --no-metro-check refuses with STIM_BAD_ARG for hosted Debug runs.
6332
6393
  If its supervisor is missing or older, run stim stop; stim start, then retry.
6333
6394
  Non-Debug runs skip Metro. Launch is unverified until this workspace's Metro
6334
6395
  provides bundle evidence, or the host proves a live release process. Native Xcode
@@ -6341,14 +6402,14 @@ hosting Mac, refuses for that slot: run stim stop first.
6341
6402
  Status adds ios.host { machine, session, selected, device: { name, runtime },
6342
6403
  agent, state } per slot. A shutdown local simulator is replaced in status; a
6343
6404
  booted or unknown local simulator stays visible alongside ios.host with a warning.
6344
- The default slot appears only in ios, never in slots[]. No host UDID or gateway secret enters local device state or
6405
+ The default slot appears only in ios, never in slots[]. No host UDID enters local device state or
6345
6406
  status. Ready is normal; stopped has a rerun hint; unknown or unreachable is
6346
6407
  unverified. A clean host server restart stops its sessions and retains eligible
6347
6408
  parked devices. A running session left by a crash stays unknown until explicit
6348
6409
  stop; the restarted server never re-attaches to a booted device.
6349
6410
 
6350
6411
  stop and worktree remove wait for the host to stop, park its eligible owned
6351
- simulator within pool.iosParkedMax (delete otherwise), close the gateway and clear placement. stop --json
6412
+ simulator within pool.iosParkedMax (delete otherwise), close the Metro links and clear placement. stop --json
6352
6413
  reports each hosted slot under outcomes.device["ios:host:<slot>"], retaining
6353
6414
  local device outcomes and successful siblings when another slot fails. Revoked or
6354
6415
  missing sessions clear placement too. An unreachable host retains placement
@@ -7866,7 +7927,7 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
7866
7927
 
7867
7928
  Warm registers the app it prepares, so \`stim status\` lists the workspace
7868
7929
  with phase "warming" while it runs and "ready" once it succeeds, until the
7869
- first start, ios, android, web or reload there or for 2 hours
7930
+ first start, ios, android, web, reload or logs there or for 2 hours
7870
7931
  (\`guide facts status\`). In a monorepo worktree root, that app is the one
7871
7932
  the source checkout has registered.
7872
7933
 
@@ -8651,6 +8712,52 @@ supervisor's idle rules and records (guide lifecycle budget). While the level is
8651
8712
  check also names abnormally large processes (guide lifecycle simslim) in
8652
8713
  status's maintenance block and the maintenance log.
8653
8714
 
8715
+ IDLE STOP: the idle check, and gc --delete unless maintenance.mode is off (its
8716
+ dry run lists them in the maintenance plan), stop a workspace whose dev server
8717
+ runs or whose owned simulator or emulator is booted once it has had no real
8718
+ activity for maintenance.idleStopHours (default 6; 0 never; machine or project
8719
+ layers; STIM_MAINTENANCE_IDLE_STOP_HOURS overrides; fractions work). Six hours
8720
+ outlasts a lunch break, a meeting or an agent's pause between tasks, and still
8721
+ frees the memory overnight. Real activity is the newest of: a Stim command in
8722
+ the workspace (start, ios, android, macos, web, reload, logs, worktree warm),
8723
+ the end of its last native build, the start, progress or end of a Metro
8724
+ bundle or manifest request, or an HMR update, in metro.ndjson, an agent-device command in the workspace's
8725
+ agent-device sessions, and an open stim-server live view of its device.
8726
+ Device and system log lines, in-app console logs, dev server output,
8727
+ collector writes and maintenance's own records never count, and an app that
8728
+ only stays connected does not either. The stop is stim stop's: the dev
8729
+ server stops, the owned devices shut down through centralized teardown
8730
+ (never deleted), and the port is released; device leases stay. A build, a
8731
+ held native-run or metro-start lock, a build lock or slot, a running macOS
8732
+ app, a hosted or remote session, an unexpired device lease, a managed tunnel
8733
+ or remote lock, a running owned Chrome, a device driver other than
8734
+ agent-device, a live agent-device claim with no session activity to judge,
8735
+ device activity, an emulator list or an emulator's AVD name that cannot be read keeps
8736
+ the workspace;
8737
+ the check decides again under the native-run and metro-start locks. Each stop
8738
+ is a maintenance_action line naming the idle time (gc --delete records itself
8739
+ as the requester), each workspace kept past the window a maintenance_skip line
8740
+ with the reason. The port is released, so status shows the workspace idle as
8741
+ after stim stop, and the supervisor_stopped line in metro.ndjson names
8742
+ automatic maintenance and the idle time as the requester. The next start, ios or android starts it
8743
+ again. An owned emulator the activity check missed keeps the workspace while
8744
+ adb lists it, and so does any emulator adb lists without an AVD name, such as
8745
+ a stale offline entry that adb kill-server clears. A dev server that may still run after its supervisor
8746
+ exited is kept until stim stop ends it. So is a dev server whose requests Stim
8747
+ does not record: an Expo project before SDK 54, which cannot load Stim's Metro config
8748
+ adapter, or a dev server an older Stim started, until stim stop and stim start
8749
+ restart it. Unlike the other actions, it can stop the workspace whose dev server
8750
+ supervisor or status --watch timer started the pass; a pass a command starts,
8751
+ gc --delete included, never stops the command's own workspace.
8752
+ A dev server run through metro.command is kept: Stim sees none of its
8753
+ bundle or HMR requests. A Metro log that cannot be read, or that rotated
8754
+ within the window, and agent-device sessions, a state.json or a stim-server
8755
+ viewer record that cannot be read or verified keep the workspace too. A STIM_HOME-scoped home never
8756
+ idle-stops, because its devices are machine-wide. maintenance.keep does not keep a workspace from idle
8757
+ stop, which deletes nothing; set maintenance.idleStopHours 0 at workspace
8758
+ scope instead.
8759
+ stim settings set maintenance.idleStopHours 1 --scope machine
8760
+
8654
8761
  In on mode a pass runs, cheapest to rebuild first:
8655
8762
  1. orphaned workspace directories whose project is gone, and registered
8656
8763
  caches whose directory no longer exists
@@ -8695,7 +8802,8 @@ live build lock, or in a Metro store with a running or unverifiable dev
8695
8802
  server. Anything the pass cannot verify is kept. A device is deleted only when
8696
8803
  its workspace is idle: no dev server, native run, build, lease, managed lock,
8697
8804
  driven or busy device, and no recorded use within the window. Below disk
8698
- pressure level 3 a pass never stops a dev server or watchman; removing a
8805
+ pressure level 3 a pass stops a dev server only by IDLE STOP above and never
8806
+ stops watchman; removing a
8699
8807
  finished worktree or orphaned directory does tear down that workspace's own
8700
8808
  dev server, owned devices and Chrome profile, as gc --delete does. ccache evicts by itself under
8701
8809
  caches.ccacheMaxGb.
@@ -8751,8 +8859,8 @@ DISK PRESSURE LEVELS
8751
8859
  gradle-versions, run again after step 5 so a daemon that did not exit
8752
8860
  still keeps them
8753
8861
  A directory is cleared only when it is a real directory inside its
8754
- worktree, git tracks nothing in it, its worktree is not in use, holds no
8755
- lock or build and is not pinned, and, for the node_modules and ios/Pods of
8862
+ worktree, git tracks nothing in it, its worktree is not in use, is not
8863
+ locked with git worktree lock, holds no build lock and is not pinned, and, for the node_modules and ios/Pods of
8756
8864
  level 3, nothing under it, nor the worktree's git index, HEAD or Stim
8757
8865
  state, changed within the short window. A build directory of level 2 also
8758
8866
  stays in a worktree where no Stim workspace has recorded any state; a build
@@ -9729,7 +9837,12 @@ WORKSPACE BUILD OUTPUTS
9729
9837
  detected cache, "Workspace build outputs", with a per-workspace size, last
9730
9838
  use and verdict. Plain \`gc --delete\` lightens every workspace, before
9731
9839
  anything else, by clearing them, and prints the bytes freed per workspace.
9732
- A running dev server, a booted or hosted simulator or emulator and a managed
9840
+ A workspace whose worktree is locked with git worktree lock is never
9841
+ lightened: not its outputs, not its project's build directories, at any
9842
+ disk pressure level, including gc --older-than and the budget, and gc and
9843
+ the maintenance log name the lock. The outputs also stay when git lists
9844
+ nothing for a project inside a git checkout (code lock-unknown). A
9845
+ running dev server, a booted or hosted simulator or emulator and a managed
9733
9846
  tunnel no longer keep them. They stay while the workspace is building (its
9734
9847
  native-run.lock is held, a live or unresolvable build lock or slot names
9735
9848
  it, or its build claim is live), while its macOS app or build runs or cannot
@@ -9749,8 +9862,8 @@ WORKSPACE BUILD OUTPUTS
9749
9862
  1 keeps its own rules. A running, building, unverified or hosted macOS app
9750
9863
  keeps its workspace untouched.
9751
9864
  stim gc --delete --cache workspaces --older-than 7
9752
- Last use is the newest of the lastUsedAt that start, ios, android, reload
9753
- and worktree warm record in state.json, lastBuild.startedAt,
9865
+ Last use is the newest of the lastUsedAt that start, ios, android, reload,
9866
+ logs and worktree warm record in state.json, lastBuild.startedAt,
9754
9867
  supervisor.startedAt and the mtimes under logs/, so a dev server that keeps
9755
9868
  logging keeps its workspace in use.
9756
9869
  A workspace with none of those was last used when its workspace.json was
@@ -9768,10 +9881,11 @@ WORKTREE DEPENDENCIES
9768
9881
  Plain \`gc --delete\` also lightens linked worktrees: it deletes the
9769
9882
  node_modules and ios/Pods at the root or a project root of a linked
9770
9883
  worktree that has a Stim workspace, never the source checkout. A worktree
9771
- keeps them while it is in use (its dev server runs, a native run or build
9772
- holds it), while it was used in the last 15 minutes (a git index, HEAD or
9773
- reflog write, a Stim state or log write, or a write at the top of the
9774
- directory), while git tracks a file in them, while a stim-server service
9884
+ locked with git worktree lock keeps them always, so a rollback checkout
9885
+ stays runnable. Otherwise a worktree keeps them while it is in use (its
9886
+ dev server runs, a native run or build holds it), while it was used in
9887
+ the last 15 minutes (a git index, HEAD or reflog write, a Stim state or
9888
+ log write, or a write at the top of the directory), while git tracks a file in them, while a stim-server service
9775
9889
  or the stim on PATH runs from it, while a live process has its command
9776
9890
  line or working directory in it, and when the running processes cannot be
9777
9891
  listed (always on Windows). It also keeps them when \`stim worktree warm\`
@@ -10485,6 +10599,8 @@ floors below; report measures and plans and deletes nothing; off disables it.
10485
10599
  STIM_HOME and CI make the mode off unless STIM_MAINTENANCE is set.
10486
10600
  maintenance.keep is a project setting: pin a workspace so a pass never clears
10487
10601
  its build outputs or removes its worktree.
10602
+ maintenance.idleStopHours takes machine or project layers, so one workspace can
10603
+ stop sooner, later or never.
10488
10604
  See \`guide cleanup\` for checks, plans and log paths.
10489
10605
 
10490
10606
  ${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}`}
@@ -10653,6 +10769,38 @@ machine a \`priority\` in its JSON:
10653
10769
  A host reports its own load limit in its device offer; a stim-server older than
10654
10770
  that does not, and this machine's \`server.maxLoadPerCore\` stands in for it.
10655
10771
 
10772
+ REMOTE MACHINES ON THE LOCAL NETWORK
10773
+ A machine on the same local network, without Tailscale, is named
10774
+ \`local:<host>\`: its private IPv4 address or host name, with an optional
10775
+ stim-server port (default 7787). On the worker, a person first chooses where
10776
+ stim-server listens with the machine setting \`server.lanAddresses\`, a list of
10777
+ network interface names or private IPv4 addresses. It defaults to [], which
10778
+ listens on no local network address; wildcard, loopback, public and IPv6
10779
+ addresses are refused, and the running server applies a change within seconds.
10780
+ An interface name follows the interface onto whatever private network it
10781
+ joins, so name the address on a machine that moves between networks, and an
10782
+ interface only on a worker that stays put. Then the person runs the setup
10783
+ command \`stim doctor --fix\` prints here:
10784
+
10785
+ stim settings set server.lanAddresses '["10.0.0.92"]' # on the worker
10786
+ stim settings set remote.machines '["local:10.0.0.92"]' # on this machine
10787
+ stim doctor --fix
10788
+
10789
+ Every connection runs Stim's Noise handshake, so plain WebSocket carries it
10790
+ without TLS, and the address never identifies anyone. Nothing on a local network
10791
+ vouches for the worker's key, so \`stim-server setup\` prints the worker's server
10792
+ key fingerprint and \`stim doctor --fix\`, run by a person in a terminal, shows
10793
+ the fingerprint the worker answered with and pins the key only after they
10794
+ confirm it matches. Until then the entry reports key-unconfirmed and is not
10795
+ used. Agents never answer that question. The printed setup command carries the
10796
+ ticket, which is a credential: whoever spends it first, after setup stores it,
10797
+ gets the approval, and on a local network that takes only the ticket and a
10798
+ route to the worker, not tailnet membership. Agents show it only to the user.
10799
+ Offloaded builds and hosted Debug and
10800
+ Release runs work there; agent control of hosted apps needs a tailnet machine.
10801
+ \`stim-server pair\` puts \`ws://<address>:<port>\` in the phone pairing code
10802
+ when Tailscale is not running and \`server.lanAddresses\` is set.
10803
+
10656
10804
  Automatic membership is separate from approval. In Desktop Settings > Remote
10657
10805
  Machines, use Builds enabled and Simulators enabled for this machine or a
10658
10806
  configured remote. The equivalent machine settings list the excluded members;
@@ -10893,7 +11041,8 @@ the ones it offloaded.
10893
11041
  \`server.maxLoadPerCore\` (default 2) is also the busy threshold for
10894
11042
  automatic iOS, Android and macOS placement. It is the load per core at which a
10895
11043
  machine counts as saturated: each machine applies its own value, and a remote
10896
- machine past it is skipped like a full one.
11044
+ machine past it is skipped like a full one. \`stim status\` shows this machine's
11045
+ load per core against it, as \`capacity.load\` in JSON.
10897
11046
 
10898
11047
  Device, Release and
10899
11048
  \`--remote eas|proxy\` builds, Android builds with the Apple Clang CAS compiler cache,
@@ -11090,7 +11239,7 @@ scope, so it needs no --scope. Run it from the workspace:
11090
11239
 
11091
11240
  \`stim status --json\` then reports hidden: true on that environment, and
11092
11241
  clients that read it list the workspace under Hidden. The next start, ios,
11093
- android, web, macos, reload or worktree warm in the workspace clears it, so
11242
+ android, web, macos, reload, logs or worktree warm in the workspace clears it, so
11094
11243
  a workspace in use is never hidden. \`worktree remove\` drops it with the
11095
11244
  workspace.
11096
11245
 
@@ -11625,7 +11774,10 @@ owned app, including copies opened through LaunchServices (open, agent-device
11625
11774
  open). stim macos, stim stop, stim worktree remove and stim gc --delete stop all
11626
11775
  of them: SIGTERM, up to 5 s, then SIGKILL, and success only once each has
11627
11776
  exited. When an app cannot be verified or does not exit, stop reports
11628
- STIM_MACOS_OWNER_UNVERIFIED or a failure, and removal keeps the workspace.
11777
+ STIM_MACOS_OWNER_UNVERIFIED or a failure, and removal keeps the workspace. For
11778
+ a hosted session the same rule covers every app bundle the session received, so
11779
+ stop and a replacement launch also end a copy that LaunchServices started from
11780
+ an earlier attempt.
11629
11781
  Local stim macos starts the app in the background without activating it or
11630
11782
  changing focus: it sets STIM_BACKGROUND_LAUNCH=1 in the app's environment, which
11631
11783
  Stim Desktop honors, including for reopen events from open -g. An app that
@@ -12015,6 +12167,12 @@ method the relay does not forward, is refused with an agent-device UNAUTHORIZED
12015
12167
  error whose details.reason is STIM_AGENT_REQUEST_REFUSED and whose message names
12016
12168
  the refused command or method; do not retry it.
12017
12169
 
12170
+ longpress, swipe, back and the other gestures are not in that list; the
12171
+ longpress and swipe that stim guide lifecycle lists belong to hosted Android and
12172
+ iOS sessions. click <ref> --button secondary reaches agent-device, but its native
12173
+ macOS backend, which the lease requires, answers UNSUPPORTED_OPERATION, so a
12174
+ hosted macOS app has no right click or context menu yet.
12175
+
12018
12176
  Agents that built, launched and drove test copies on another Mac with an SSH
12019
12177
  script such as mini-desktop.sh use these instead:
12020
12178
 
@@ -12023,7 +12181,8 @@ script such as mini-desktop.sh use these instead:
12023
12181
  launch the same command; the host launches it under the
12024
12182
  session's own home
12025
12183
  shot <out.png> agent-device screenshot --remote-config <path>
12026
- click, rclick, key, type agent-device click, press or type --remote-config <path>
12184
+ click, key, type agent-device click, press or type --remote-config <path>
12185
+ rclick unavailable: secondary click is not supported
12027
12186
  quit stim stop (verified stop; the host frees the slot
12028
12187
  and removes the app's defaults)
12029
12188
  clean stim worktree remove
@@ -12034,6 +12193,15 @@ The host's own owned devices count toward concurrency.maxDevices.
12034
12193
 
12035
12194
  The agent-device rows work once the host's agent field names agent-device.
12036
12195
 
12196
+ On macOS 27, agent-device screenshot of a hosted app can return an image of the
12197
+ window-sharing indicator (66x20 points, 132x40 pixels) instead of the app
12198
+ window. macOS adds that small window to the app while something captures the
12199
+ app, and agent-device picks it as the front window (callstack/agent-device#3961).
12200
+ snapshot -i lists it as an axdialog named "Window" with a
12201
+ WindowSharingSessionButton before the real window. Read the UI with snapshot
12202
+ until agent-device selects the app's main window. Commands that use the front
12203
+ window's frame, such as scroll, may also target the indicator.
12204
+
12037
12205
  DESKTOP DOGFOOD
12038
12206
 
12039
12207
  This repository's apps/desktop/.stim.json selects the full StimDesktop app,
@@ -1,7 +1,7 @@
1
1
  import { c as throwIfCancelled } from "./exec-aULwtNly.mjs";
2
- import { c as call, l as connectHost } from "./hosted-client-D7Pk_Oo1.mjs";
3
- import { i as requestHostedMetro } from "./metro-gateway-BnHdqMO_.mjs";
4
- import { a as stopHostedNative, i as prepareHostedNative, r as placeHostedNative } from "./hosted-native-CdgaiuyP.mjs";
2
+ import { c as call, l as connectHost } from "./hosted-client-CgoxdU9j.mjs";
3
+ import { i as requestHostedMetro } from "./metro-request-BtF7ox53.mjs";
4
+ import { a as stopHostedNative, i as prepareHostedNative, r as placeHostedNative } from "./hosted-native-DvZENAL-.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);
@@ -19,12 +19,11 @@ async function stopHostedAndroid(root, slot, signal) {
19
19
  async function reopenHostedAndroidMetro(root, placement, clientMetroPort, signal) {
20
20
  const host = await connectHost(placement.machine, void 0, true, signal);
21
21
  try {
22
- const gateway = await requestHostedMetro(root, placement.session, host.credential, signal);
22
+ await requestHostedMetro(root, placement.session, host.credential, signal);
23
23
  throwIfCancelled(signal, "reload");
24
24
  await call(host, "device-host.metro.open", {
25
25
  session: placement.session,
26
- clientMetroPort,
27
- ...gateway
26
+ clientMetroPort
28
27
  });
29
28
  } finally {
30
29
  host.connection.close();