stim 1.29.0 → 1.31.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 (146) hide show
  1. package/dist/{acquire-artifact-C2DKfenN.mjs → acquire-artifact-P84h3ssa.mjs} +1 -1
  2. package/dist/{act-CrTcskiE.mjs → act-lcOIEy32.mjs} +18 -18
  3. package/dist/{activity-BR5oHSO5.mjs → activity-Dw4N_RFe.mjs} +4 -4
  4. package/dist/{agent-device-usage-output-W0x4SoC7.mjs → agent-device-usage-output-Boie2yB-.mjs} +4 -4
  5. package/dist/{android-CLU_MMnb.mjs → android-BeeC15Ve.mjs} +1 -1
  6. package/dist/{android-l616dRP1.mjs → android-DhiWSOFU.mjs} +47 -43
  7. package/dist/{android-BHKgeOuq.mjs → android-DsEj2CCs.mjs} +65 -35
  8. package/dist/{android-BPmCmyAy.mjs → android-aIuJZoDu.mjs} +5 -5
  9. package/dist/{android-cas-BH6K12__.mjs → android-cas-CbumHXIq.mjs} +4 -4
  10. package/dist/api.mjs +26 -26
  11. package/dist/{apk-signed-tail-B-wKoF_8.mjs → apk-signed-tail-B9Usseps.mjs} +2 -2
  12. package/dist/{artifact-Dm9ScLrh.mjs → artifact-Cr34-Yyy.mjs} +12 -12
  13. package/dist/{artifact-DHuFYfhD.mjs → artifact-ta3xA0c4.mjs} +12 -12
  14. package/dist/{auto-placement-C8sJsyMN.mjs → auto-placement-DtTRG0rk.mjs} +12 -12
  15. package/dist/{browser-web-_tQTbQUs.mjs → browser-web-DuULNZrS.mjs} +11 -11
  16. package/dist/{build-DtCU9Kim.mjs → build-BpFFbdXD.mjs} +22 -22
  17. package/dist/{build-cache-BGwTsIEa.mjs → build-cache-BsKim4V7.mjs} +4 -4
  18. package/dist/{build-plan-CWyjMPKo.mjs → build-plan-DH1rT11x.mjs} +6 -6
  19. package/dist/{cache-manifest-evF_zJ9U.mjs → cache-manifest-CfiEny4T.mjs} +1 -1
  20. package/dist/cache-manifest.mjs +1 -1
  21. package/dist/{ccache-DsDkdP72.mjs → ccache-DVDO2ocE.mjs} +16 -16
  22. package/dist/{cli-3fjOg-Oc.mjs → cli-C0jjwTuM.mjs} +18 -18
  23. package/dist/cli.mjs +1 -1
  24. package/dist/{client-BTUH8TF1.mjs → client-DhJOvSvh.mjs} +4 -4
  25. package/dist/collector-run.mjs +4 -4
  26. package/dist/{command-output-DjCsmzLZ.mjs → command-output-VrXd6qPX.mjs} +1 -1
  27. package/dist/{config-AbUjIBOQ.mjs → config-D5qNWJEP.mjs} +2 -2
  28. package/dist/{dependencies-CHNqX6Pr.mjs → dependencies-DIU-5rnG.mjs} +38 -37
  29. package/dist/{dependency-state-CPKAKCZ8.mjs → dependency-state-DZVln1P9.mjs} +1 -1
  30. package/dist/{dev-client-CROrxj1x.mjs → dev-client-DeAg0fso.mjs} +2 -2
  31. package/dist/device-C2WsPgFt.mjs +761 -0
  32. package/dist/device-DuNLOlR6.mjs +175 -0
  33. package/dist/{device-Bmm5qjM-.mjs → device-android-BjhH0Ru3.mjs} +39 -200
  34. package/dist/{device-capacity-B2ChA-bz.mjs → device-capacity-Du5wBTNJ.mjs} +175 -76
  35. package/dist/device-host-worker.mjs +49 -36
  36. package/dist/{device-ios-CYzivd31.mjs → device-ios-CUYUhSYO.mjs} +27 -17
  37. package/dist/{device-lease-run-qRq_2W2V.mjs → device-lease-run-CHXQEn-7.mjs} +4 -4
  38. package/dist/{device-pool-CrmiE4_x.mjs → device-pool-kUHO7MHO.mjs} +3 -3
  39. package/dist/{device-provision-CK2XiEp1.mjs → device-provision-e7bKS7lx.mjs} +8 -8
  40. package/dist/{doctor-BO_kaFWX.mjs → doctor-B6kIVgU9.mjs} +1 -1
  41. package/dist/{doctor-Cp4-HN1f.mjs → doctor-BGcsAgAV.mjs} +15 -15
  42. package/dist/doctor-fingerprint.mjs +1 -1
  43. package/dist/{doctor-Dr3C1iXV.mjs → doctor-hva3sd9f.mjs} +37 -26
  44. package/dist/{doctor-watchman-CJr2aXXv.mjs → doctor-watchman-DJY550yz.mjs} +4 -4
  45. package/dist/{eas-build-D-9HmGZS.mjs → eas-build-CBFgseh1.mjs} +2 -2
  46. package/dist/{eas-fallback-Cemt2GVL.mjs → eas-fallback-DFXdz4d6.mjs} +4 -4
  47. package/dist/{eas-session-ledger-B0KLZx5m.mjs → eas-session-ledger-aFBLTZr2.mjs} +19 -6
  48. package/dist/{error-diagnostics-CV_1RoEH.mjs → error-diagnostics-CCsq_3uG.mjs} +8 -8
  49. package/dist/{gc-CKHqL4aS.mjs → gc-B0K4d_PL.mjs} +17 -17
  50. package/dist/{gc-DjXwQXHK.mjs → gc-DASUa3Z_.mjs} +2 -2
  51. package/dist/{guide-CeRlWVsS.mjs → guide-Civo5-zV.mjs} +178 -28
  52. package/dist/{hosted-android-DI_vvv7U.mjs → hosted-android-CH1Sm4wo.mjs} +3 -3
  53. package/dist/{hosted-client-CgoxdU9j.mjs → hosted-client-5ur3YpxY.mjs} +36 -12
  54. package/dist/{hosted-logs-C-4INmkn.mjs → hosted-logs-BYg4yeti.mjs} +6 -6
  55. package/dist/{hosted-logs-sync-Bf5s02fi.mjs → hosted-logs-sync-BPe8xnMu.mjs} +7 -11
  56. package/dist/{hosted-macos-Doh85YUM.mjs → hosted-macos-BagT0Gn3.mjs} +5 -5
  57. package/dist/{hosted-native-DvZENAL-.mjs → hosted-native-kaR4nUHk.mjs} +9 -8
  58. package/dist/{idle-shutdown-BM37gMfU.mjs → idle-shutdown-BWHQ7mQG.mjs} +6 -6
  59. package/dist/{ios-CNDH6fNF.mjs → ios-BKR-Dq46.mjs} +8 -8
  60. package/dist/{ios-CoMCWfub.mjs → ios-CdAV4-1E.mjs} +4 -4
  61. package/dist/{ios-UM_dManb.mjs → ios-DUL68MI5.mjs} +33 -32
  62. package/dist/{ios-device-L1-pota_.mjs → ios-device-Dz8gFZ0K.mjs} +1 -1
  63. package/dist/{ios-project-DJYptOCh.mjs → ios-project-Br1tVYWX.mjs} +7 -7
  64. package/dist/{ios-state-Ce_dystM.mjs → ios-state-BEIJRJ7P.mjs} +1 -1
  65. package/dist/{js-swap-BthE4kZC.mjs → js-swap-BfG8XpyS.mjs} +4 -4
  66. package/dist/{launch-D798aSm8.mjs → launch-CrGndh8T.mjs} +19 -19
  67. package/dist/{lightened-vSxkstg6.mjs → lightened-DZ9Ip0T3.mjs} +4 -4
  68. package/dist/{logs-CilPftm3.mjs → logs-C-hfMsxK.mjs} +7 -6
  69. package/dist/{logs-BND8MiBq.mjs → logs-DpIKWT3A.mjs} +7 -7
  70. package/dist/{macos-BOQrKYeJ.mjs → macos-DNmKwfDy.mjs} +1 -1
  71. package/dist/{macos-CxUi9xcE.mjs → macos-DZ9ZSolN.mjs} +19 -19
  72. package/dist/macos-run.mjs +1 -1
  73. package/dist/maintenance-run.mjs +5 -5
  74. package/dist/{metro-BMQHczcf.mjs → metro-mKHEMO-a.mjs} +2 -2
  75. package/dist/{metro-request-BtF7ox53.mjs → metro-request-RDhyx85c.mjs} +1 -1
  76. package/dist/{named-ports-DcktE2Pw.mjs → named-ports-B0hCk2v-.mjs} +2 -2
  77. package/dist/{native-android-BkhrCjdX.mjs → native-android-DExhFqR6.mjs} +16 -16
  78. package/dist/{native-gradle-artifact-inputs-Cw4P6Gyr.mjs → native-gradle-artifact-inputs-Bcmbdc23.mjs} +3 -3
  79. package/dist/{native-runtime-DyH2gkXK.mjs → native-runtime-D4qgnjK_.mjs} +6 -6
  80. package/dist/{native-xcode-inputs-DV8jr3kJ.mjs → native-xcode-inputs-EWma1lXh.mjs} +2 -2
  81. package/dist/{native-xcode-ios-DdpPG2iT.mjs → native-xcode-ios-Y6rzmWTc.mjs} +15 -15
  82. package/dist/offload-worker.mjs +19 -19
  83. package/dist/{ownership-Dtz9G5Gl.mjs → ownership-CCfiBfOP.mjs} +2 -2
  84. package/dist/{phone-reverses-DZRad8HT.mjs → phone-reverses-Drj5QQCh.mjs} +4 -4
  85. package/dist/{placement-log-CoN6xrjY.mjs → placement-log-CFT8SnlS.mjs} +1 -1
  86. package/dist/{plan-placement-7sHuqR-r.mjs → plan-placement-DhKCH_wF.mjs} +6 -6
  87. package/dist/{ports-VQSAPZhl.mjs → ports-BNtJ5DCj.mjs} +3 -3
  88. package/dist/{prebuild-Bqp0LFGN.mjs → prebuild-D0hvmO4j.mjs} +9 -9
  89. package/dist/{project-D1n0K4yg.mjs → project-DCLkDM8C.mjs} +15 -15
  90. package/dist/{react-native-android-FQ-yX3Mv.mjs → react-native-android-Dp7vctEA.mjs} +24 -24
  91. package/dist/{react-native-build-D58bIqV9.mjs → react-native-build-vK2lFYfN.mjs} +7 -7
  92. package/dist/{react-native-doctor-AkUH2aca.mjs → react-native-doctor-BtWzwZHU.mjs} +9 -8
  93. package/dist/{react-native-ios-Dmsv8j7T.mjs → react-native-ios-DW1Ax3Yv.mjs} +16 -15
  94. package/dist/{recordings-CHMaF73C.mjs → recordings-BWnIlhZH.mjs} +1 -1
  95. package/dist/{reload-BV0nD-k9.mjs → reload-B-d7-CsI.mjs} +14 -14
  96. package/dist/{reload-CDKEzzaf.mjs → reload-BS_ntVV_.mjs} +1 -1
  97. package/dist/{remote-C8xyslUa.mjs → remote-DScVlaMz.mjs} +8 -8
  98. package/dist/{result-9fqcJ90W.mjs → result-Epkl6gyG.mjs} +16 -16
  99. package/dist/{run-BQAmrohh.mjs → run-2CHAJ9Oj.mjs} +1 -1
  100. package/dist/{selection-D1ZDzHFX.mjs → selection-C95m--1_.mjs} +3 -3
  101. package/dist/{server-bare-CEQdB_F4.mjs → server-bare-CFyVFZXJ.mjs} +1 -1
  102. package/dist/{server-command-RlS-Kl4a.mjs → server-command-B1gDRJB2.mjs} +4 -4
  103. package/dist/{server-expo-bB1VV2k-.mjs → server-expo-CP4dURQp.mjs} +2 -2
  104. package/dist/server-expo-D3k9mvP8.mjs +2 -0
  105. package/dist/{settings-D776ygML.mjs → settings-C6UTYW2K.mjs} +1 -1
  106. package/dist/{settings-BcVCcAT5.mjs → settings-CjTRNCi3.mjs} +2 -2
  107. package/dist/{settings-payload-_aatELz2.mjs → settings-payload-zf5EnCTg.mjs} +4 -4
  108. package/dist/{settings-write-CkTVGQ4O.mjs → settings-write-Fe0K6BeC.mjs} +5 -5
  109. package/dist/settings.schema.json +45 -3
  110. package/dist/{simslim-CbpHERcv.mjs → simslim-93xmPh-d.mjs} +1 -1
  111. package/dist/{slot-launch-Dbgfh8gc.mjs → slot-launch-B4MHzVX2.mjs} +6 -6
  112. package/dist/{stage-BuHuRj1y.mjs → stage-DDrnM0CY.mjs} +1 -1
  113. package/dist/{start-Cr-c3Xhq.mjs → start-BXl5tkv8.mjs} +1 -1
  114. package/dist/{start-Dlv4XXTP.mjs → start-LSwIFlBv.mjs} +10 -10
  115. package/dist/{state-D5ZxwCGJ.mjs → state-CM_HvvkS.mjs} +2 -2
  116. package/dist/{state-C2AUjjhg.mjs → state-CiflgxTP.mjs} +1 -1
  117. package/dist/{stats-D5c-uIBp.mjs → stats-EgpYD536.mjs} +4 -4
  118. package/dist/{status-D6PBK6_-.mjs → status-BLDvhatv.mjs} +26 -25
  119. package/dist/{status-DbQv--Yb.mjs → status-DBMD7ZQT.mjs} +1 -1
  120. package/dist/{status-CK7ZoEhV.mjs → status-GQ-JqvRi.mjs} +1 -1
  121. package/dist/{status-watch-okrpea4i.mjs → status-watch-BwG4lJ1q.mjs} +4 -4
  122. package/dist/status-worker.mjs +1 -1
  123. package/dist/{stim-desktop-CYXLFpFS.mjs → stim-desktop-1XxET4S8.mjs} +1 -1
  124. package/dist/{stop-CHtAiv79.mjs → stop-4SAV_RR8.mjs} +2 -2
  125. package/dist/{stop-uRQ-zYcl.mjs → stop-BfNhzvXO.mjs} +4 -4
  126. package/dist/{stop-p9uSKuGE.mjs → stop-WyrZQuX6.mjs} +15 -15
  127. package/dist/supervisor-run.mjs +13 -13
  128. package/dist/{support-PFyTkrnr.mjs → support-Cffz6_Ft.mjs} +15 -11
  129. package/dist/{support-BMpQIug0.mjs → support-Cs24xRQa.mjs} +9 -9
  130. package/dist/{swiftpm-artifact-inputs-Cddq6jN2.mjs → swiftpm-artifact-inputs-yp8D5LE4.mjs} +1 -1
  131. package/dist/{swiftpm-macos-BSj9iZlI.mjs → swiftpm-macos-D0CzQtpp.mjs} +8 -8
  132. package/dist/toolchain-BEra9AIX.mjs +2 -0
  133. package/dist/{toolchain-CLGnEUgT.mjs → toolchain-CGdgD4x4.mjs} +19 -11
  134. package/dist/{warm-progress--KkkBBaq.mjs → warm-progress-_aTMvkIH.mjs} +3 -3
  135. package/dist/{web-xlVssjQf.mjs → web-BE89ONcc.mjs} +8 -8
  136. package/dist/web-DQPxvFVD.mjs +2 -0
  137. package/dist/web-run.mjs +4 -4
  138. package/dist/{workspace-state-DGwkPXwq.mjs → workspace-state-3bF4TB8P.mjs} +2 -2
  139. package/dist/{workspaces-CvSYD_78.mjs → workspaces-BNEyJ1B_.mjs} +15 -12
  140. package/dist/{worktree-CaQBf6kh.mjs → worktree-BTrii9e_.mjs} +24 -24
  141. package/dist/{worktree-DTOIohFe.mjs → worktree-DB3Ypdj6.mjs} +1 -1
  142. package/package.json +7 -7
  143. package/dist/device-BvpasThQ.mjs +0 -297
  144. package/dist/server-expo-BVV9qy31.mjs +0 -2
  145. package/dist/toolchain-B-mzR9Rh.mjs +0 -2
  146. package/dist/web-BxSo493O.mjs +0 -2
@@ -1,9 +1,9 @@
1
1
  import { C as reportSignal, t as getExecutor } from "./exec-aULwtNly.mjs";
2
- import { M as withDirLock$1, N as withDirLockAsync$1, w as workspaceAgentDeviceDir } from "./workspace-state-DGwkPXwq.mjs";
3
- import { G as projectDeviceSlots, V as deviceSlotKey } from "./config-AbUjIBOQ.mjs";
4
- import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-DjCsmzLZ.mjs";
5
- import { n as isInsideProject } from "./metro-BMQHczcf.mjs";
6
- import { r as cdpEndpoint } from "./state-D5ZxwCGJ.mjs";
2
+ import { M as withDirLock$1, N as withDirLockAsync$1, w as workspaceAgentDeviceDir } from "./workspace-state-3bF4TB8P.mjs";
3
+ import { H as deviceSlotKey, K as projectDeviceSlots } from "./config-D5qNWJEP.mjs";
4
+ import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-VrXd6qPX.mjs";
5
+ import { n as isInsideProject } from "./metro-mKHEMO-a.mjs";
6
+ import { r as cdpEndpoint } from "./state-CM_HvvkS.mjs";
7
7
  import { accessSync, constants, existsSync, mkdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
8
  import { delimiter, dirname, join, resolve } from "node:path";
9
9
  import { workspaceId } from "@stim-cli/core";
@@ -362,7 +362,7 @@ function loadLine({ loadPerCore, busyAt, limit }) {
362
362
  return `load ${loadPerCore}/core (busy at ${busyAt}${limit === null ? "" : `, holding at ${limit}`})`;
363
363
  }
364
364
  /** The plain status lines for the `concurrency.maxBuilds` and `concurrency.maxDevices` caps that are set. */
365
- function slotUsageLines({ builds, devices }) {
365
+ function slotUsageLines({ builds, devices, platformDevices }) {
366
366
  const lines = [];
367
367
  if (builds) {
368
368
  const holders = builds.holders.map((holder) => holder.unresolved ? `slot ${holder.slot} unresolved` : holder.client ? `offloaded for ${holder.client}` : holder.workspace ? basename$1(holder.workspace) : `slot ${holder.slot}`);
@@ -375,6 +375,19 @@ function slotUsageLines({ builds, devices }) {
375
375
  lines.push(`devices ${devices.inUse}/${devices.max} (concurrency.maxDevices)${holders.length ? `: ${holders.join(", ")}` : ""}`);
376
376
  }
377
377
  }
378
+ for (const [platform, setting, noun] of [[
379
+ "ios",
380
+ "concurrency.maxIosDevices",
381
+ "iOS simulators"
382
+ ], [
383
+ "android",
384
+ "concurrency.maxAndroidDevices",
385
+ "Android emulators"
386
+ ]]) {
387
+ const slots = platformDevices?.[platform];
388
+ if (!slots) continue;
389
+ lines.push(slots.inUse === null ? `${noun} ?/${slots.max} (${setting}): ${slots.unknown ?? "not counted"}` : `${noun} ${slots.inUse}/${slots.max} (${setting})`);
390
+ }
378
391
  return lines;
379
392
  }
380
393
  function parseDfFree(output) {
@@ -1,12 +1,12 @@
1
1
  import { t as getExecutor } from "./exec-aULwtNly.mjs";
2
- import { r as readWorkspaceState$1 } from "./workspace-state-DGwkPXwq.mjs";
3
- import { H as deviceSlotPlatforms, V as deviceSlotKey, p as getProject } from "./config-AbUjIBOQ.mjs";
4
- import { v as launchErrorPreview } from "./command-output-DjCsmzLZ.mjs";
5
- import { I as readWorkspaceLaunches } from "./project-D1n0K4yg.mjs";
6
- import { o as androidHome, u as androidToolCwd } from "./android-BHKgeOuq.mjs";
7
- import { d as resolveProjectMetro } from "./metro-BMQHczcf.mjs";
8
- import { i as parseLogcatLine, n as androidLogGroups, r as isAndroidCrashText } from "./android-CLU_MMnb.mjs";
9
- import { S as parseLease, v as deviceLeasePath, y as fileLeaseIo } from "./activity-BR5oHSO5.mjs";
2
+ import { r as readWorkspaceState$1 } from "./workspace-state-3bF4TB8P.mjs";
3
+ import { H as deviceSlotKey, U as deviceSlotPlatforms, m as getProject } from "./config-D5qNWJEP.mjs";
4
+ import { v as launchErrorPreview } from "./command-output-VrXd6qPX.mjs";
5
+ import { I as readWorkspaceLaunches } from "./project-DCLkDM8C.mjs";
6
+ import { o as androidHome, u as androidToolCwd } from "./android-DsEj2CCs.mjs";
7
+ import { d as resolveProjectMetro } from "./metro-mKHEMO-a.mjs";
8
+ import { i as parseLogcatLine, n as androidLogGroups, r as isAndroidCrashText } from "./android-BeeC15Ve.mjs";
9
+ import { S as parseLease, v as deviceLeasePath, y as fileLeaseIo } from "./activity-Dw4N_RFe.mjs";
10
10
  import { r as deviceConsoleLevel } from "./ios-device-CiBA-er9.mjs";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
12
  import { existsSync, readFileSync, renameSync } from "node:fs";
@@ -1,24 +1,24 @@
1
1
  import { D as ownership_claim_exports, S as process_identity_exports, c as throwIfCancelled, l as WorkspaceProcessCleanupError, m as declareSpawnsOn, t as getExecutor, v as stopDeclaringSpawnsOn, x as withDrainingCancellation } from "./exec-aULwtNly.mjs";
2
- import { E as workspaceDir, u as workspaceLastUsed } from "./workspace-state-DGwkPXwq.mjs";
3
- import { F as isOnMountedVolume, G as projectDeviceSlots, I as listMountedVolumes, L as measuredDirectorySizeAsync, N as directorySizeAsync, O as withConfigLockAsync$1, P as formatBytes, R as volumeRootFor, S as removeProject, _ as loadConfig$1, d as getConfigDir, j as acquireAvdClaim } from "./config-AbUjIBOQ.mjs";
4
- import { d as quotedPath$1, h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-DjCsmzLZ.mjs";
2
+ import { E as workspaceDir, u as workspaceLastUsed } from "./workspace-state-3bF4TB8P.mjs";
3
+ import { C as removeProject, F as formatBytes, I as isOnMountedVolume, K as projectDeviceSlots, L as listMountedVolumes, M as acquireAvdClaim, P as directorySizeAsync, R as measuredDirectorySizeAsync, d as getConfigDir, k as withConfigLockAsync$1, v as loadConfig$1, z as volumeRootFor } from "./config-D5qNWJEP.mjs";
4
+ import { d as quotedPath$1, h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-VrXd6qPX.mjs";
5
5
  import { t as runOperationFile } from "./operation-exec-Dp4FuIGR.mjs";
6
- import { $t as TRASH_MANIFEST, Ft as matchWorktreeEntry, Wt as resolveSourceCheckoutAsync, Zt as TRASH_CLAIMS, en as deleteTrashEntry, jt as listWorktreesAsync } from "./settings-D776ygML.mjs";
7
- import { i as findProjectRoot$1, v as detectIsExpo } from "./project-D1n0K4yg.mjs";
8
- import { Ct as forgetCreatedDeviceAsync, F as listAvdsAsync, L as listOrphanedAvdDirectories, V as ownedAvdDirectory, ft as POOL_SETTING_REMEDY, h as avdNameAbsent, vt as parkedMaxSetting, wt as readCreatedDevices$1 } from "./android-BHKgeOuq.mjs";
9
- import { $ as gradleVersionLines, $n as memoryCacheKind, B as includesArchives, Ct as describeError, En as runProcessOperation, F as gcOptionsOf, Ft as withEasProjectLock, G as planCacheEmptying, H as includesRecordings, J as selectsBeyondCaches, Jn as parseArchiveSelector, K as previewScopedEmptying, L as openGcLog, Q as deleteGradleVersions, St as deleteEasSessions, U as includesWorkspaceOutputs, V as includesParkedDevices, W as isWorkspacesScope, X as collectGradleVersions, Y as trimCaches, Zn as collectMemoryReport, _t as findStaleDeviceRecords, ar as scopedMemoryReport, at as DEVICE_LIST_TIMEOUT_MS, bt as withAndroidAvdSizes, ct as collectParkedSims, dt as deleteProjectDevices, er as memoryLines, et as gradleVersionsPending, fr as sizeCaches, gt as findOrphanedDevices, ht as eraseParkedDevices, ir as reclaimMemory, it as collectInventory, lt as deleteParkedAvds, mt as deviceSweepIsScoped, nr as memorySweepIsScoped, ot as collectDeviceLeases, pt as describeUnverifiableDevices, q as selectCaches, rr as memoryWorkPending, rt as getMachineCacheReport, sr as phase, st as collectParkedAvds, tr as memoryScope, tt as includesGradleVersions, ur as discoverCaches, ut as deleteParkedSims, vt as findStaleProjectDevices, wt as withRemoteSessionGcLocks, xt as collectEasSessionSweep, yt as unverifiedDeviceCommand, z as emptyCaches } from "./ccache-DsDkdP72.mjs";
10
- import { n as easMachineStateRoot$1, o as removeEasSessionClaimAsync, r as readEasSessionLedger$1 } from "./eas-session-ledger-B0KLZx5m.mjs";
11
- import { At as mapLimited, Dt as createGcResults, Et as GC_OUTPUT, I as idleDeviceLines, M as collectIdleDevices, Mt as sizeConcurrency, N as collectIdleDevicesAsync, R as parseIdleDuration, a as collectOrphanedWorkspaces, b as workspaceInUseAsync, c as isInsideWorkspaces, f as rootPresence, g as ARTIFACT_DIRS, i as clearWorkspaceOutputs, jt as readConcurrency, kt as eachLimited, n as REBUILD_COST, o as collectWorkspaceOutputs, p as sizeText, r as WORKSPACE_OUTPUT_DIRS, s as deleteOrphanedWorkspaces, t as LIGHTEN_AFTER_MS, u as listWorkspaceDirs, v as withIdleWorkspace, wt as listBuildSlots, z as shutDownIdleDevices } from "./workspaces-CvSYD_78.mjs";
6
+ import { $t as TRASH_MANIFEST, Ft as matchWorktreeEntry, Wt as resolveSourceCheckoutAsync, Zt as TRASH_CLAIMS, en as deleteTrashEntry, jt as listWorktreesAsync } from "./settings-C6UTYW2K.mjs";
7
+ import { i as findProjectRoot$1, v as detectIsExpo } from "./project-DCLkDM8C.mjs";
8
+ import { B as listOrphanedAvdDirectories, Et as readCreatedDevices$1, R as listAvdsAsync, Tt as forgetCreatedDeviceAsync, U as ownedAvdDirectory, bt as parkedMaxSetting, h as avdNameAbsent, mt as POOL_SETTING_REMEDY } from "./android-DsEj2CCs.mjs";
9
+ import { $ as gradleVersionLines, $n as memoryCacheKind, B as includesArchives, Ct as describeError, En as runProcessOperation, F as gcOptionsOf, Ft as withEasProjectLock, G as planCacheEmptying, H as includesRecordings, J as selectsBeyondCaches, Jn as parseArchiveSelector, K as previewScopedEmptying, L as openGcLog, Q as deleteGradleVersions, St as deleteEasSessions, U as includesWorkspaceOutputs, V as includesParkedDevices, W as isWorkspacesScope, X as collectGradleVersions, Y as trimCaches, Zn as collectMemoryReport, _t as findStaleDeviceRecords, ar as scopedMemoryReport, at as DEVICE_LIST_TIMEOUT_MS, bt as withAndroidAvdSizes, ct as collectParkedSims, dt as deleteProjectDevices, er as memoryLines, et as gradleVersionsPending, fr as sizeCaches, gt as findOrphanedDevices, ht as eraseParkedDevices, ir as reclaimMemory, it as collectInventory, lt as deleteParkedAvds, mt as deviceSweepIsScoped, nr as memorySweepIsScoped, ot as collectDeviceLeases, pt as describeUnverifiableDevices, q as selectCaches, rr as memoryWorkPending, rt as getMachineCacheReport, sr as phase, st as collectParkedAvds, tr as memoryScope, tt as includesGradleVersions, ur as discoverCaches, ut as deleteParkedSims, vt as findStaleProjectDevices, wt as withRemoteSessionGcLocks, xt as collectEasSessionSweep, yt as unverifiedDeviceCommand, z as emptyCaches } from "./ccache-DVDO2ocE.mjs";
10
+ import { n as easMachineStateRoot$1, o as removeEasSessionClaimAsync, r as readEasSessionLedger$1 } from "./eas-session-ledger-aFBLTZr2.mjs";
11
+ import { At as mapLimited, Dt as createGcResults, Et as GC_OUTPUT, I as idleDeviceLines, M as collectIdleDevices, Mt as sizeConcurrency, N as collectIdleDevicesAsync, R as parseIdleDuration, a as collectOrphanedWorkspaces, b as workspaceInUseAsync, c as isInsideWorkspaces, f as rootPresence, g as ARTIFACT_DIRS, i as clearWorkspaceOutputs, jt as readConcurrency, kt as eachLimited, n as REBUILD_COST, o as collectWorkspaceOutputs, p as sizeText, r as WORKSPACE_OUTPUT_DIRS, s as deleteOrphanedWorkspaces, t as LIGHTEN_AFTER_MS, u as listWorkspaceDirs, v as withIdleWorkspace, wt as listBuildSlots, z as shutDownIdleDevices } from "./workspaces-BNEyJ1B_.mjs";
12
12
  import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
13
- import { N as listBuildLocks, k as removeExpiredLease } from "./activity-BR5oHSO5.mjs";
14
- import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-CoMCWfub.mjs";
13
+ import { N as listBuildLocks, k as removeExpiredLease } from "./activity-Dw4N_RFe.mjs";
14
+ import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-CdAV4-1E.mjs";
15
15
  import { t as resolveMaintenanceSettings } from "./settings-D9LtQaUw.mjs";
16
- import { r as readCollectors } from "./ownership-Dtz9G5Gl.mjs";
17
- import { A as deleteSelectedArchives, O as describeDereferenced, j as sweepArchiveStaging, k as reclaimProject } from "./worktree-CaQBf6kh.mjs";
18
- import { p as writeCacheFile } from "./warm-progress--KkkBBaq.mjs";
19
- import { a as restoreProblem, o as workspaceKeys } from "./lightened-vSxkstg6.mjs";
20
- import { C as candidateRootsAsync, D as worktreeRemovalReason, E as worktreePullRequestNote, S as maintenancePinned, T as removeWorktrees, _ as finishedWorkspaces, a as previewMaintenance, b as cachedDeviceActivity, c as deleteTempLeftovers, d as appRoots, f as artifactWorktrees, g as stopIdleWorkspace, h as planIdleStop, l as tempLeftoverLines, m as collectArtifactsAsync, o as triggeringRoot, p as clearArtifact, s as collectTempLeftovers, t as deleteIdleWorkspaceDevices, u as tempLeftoverSection, w as collectWorktreeSweep, x as cachedDeviceActivityAsync, y as ownedDeviceUsage } from "./act-CrTcskiE.mjs";
21
- import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-W0x4SoC7.mjs";
16
+ import { r as readCollectors } from "./ownership-CCfiBfOP.mjs";
17
+ import { A as deleteSelectedArchives, O as describeDereferenced, j as sweepArchiveStaging, k as reclaimProject } from "./worktree-BTrii9e_.mjs";
18
+ import { p as writeCacheFile } from "./warm-progress-_aTMvkIH.mjs";
19
+ import { a as restoreProblem, o as workspaceKeys } from "./lightened-DZ9Ip0T3.mjs";
20
+ import { C as candidateRootsAsync, D as worktreeRemovalReason, E as worktreePullRequestNote, S as maintenancePinned, T as removeWorktrees, _ as finishedWorkspaces, a as previewMaintenance, b as cachedDeviceActivity, c as deleteTempLeftovers, d as appRoots, f as artifactWorktrees, g as stopIdleWorkspace, h as planIdleStop, l as tempLeftoverLines, m as collectArtifactsAsync, o as triggeringRoot, p as clearArtifact, s as collectTempLeftovers, t as deleteIdleWorkspaceDevices, u as tempLeftoverSection, w as collectWorktreeSweep, x as cachedDeviceActivityAsync, y as ownedDeviceUsage } from "./act-lcOIEy32.mjs";
21
+ import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-Boie2yB-.mjs";
22
22
  import { claimRemoveCommand, isClaimRefusal, isClaimUnavailable, readClaimSet, releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
23
23
  import { existsSync, lstatSync, readFileSync, readdirSync, statSync } from "node:fs";
24
24
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -1,3 +1,3 @@
1
- import { _t as findStaleDeviceRecords, ft as describeParkedSims, gt as findOrphanedDevices, pt as describeUnverifiableDevices, q as selectCaches, ut as deleteParkedSims, vt as findStaleProjectDevices } from "./ccache-DsDkdP72.mjs";
2
- import { a as runGc, i as readGcReport, n as executeGc, o as withGcMaintenanceClaim, r as gcCommand, s as formatGcReport, t as collectGcReport } from "./gc-CKHqL4aS.mjs";
1
+ import { _t as findStaleDeviceRecords, ft as describeParkedSims, gt as findOrphanedDevices, pt as describeUnverifiableDevices, q as selectCaches, ut as deleteParkedSims, vt as findStaleProjectDevices } from "./ccache-DVDO2ocE.mjs";
2
+ import { a as runGc, i as readGcReport, n as executeGc, o as withGcMaintenanceClaim, r as gcCommand, s as formatGcReport, t as collectGcReport } from "./gc-B0K4d_PL.mjs";
3
3
  export { collectGcReport, gcCommand as default, deleteParkedSims, describeParkedSims, describeUnverifiableDevices, executeGc, findOrphanedDevices, findStaleDeviceRecords, findStaleProjectDevices, formatGcReport, readGcReport, runGc, selectCaches, withGcMaintenanceClaim };
@@ -1,8 +1,8 @@
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";
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";
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
@@ -418,6 +418,7 @@ FULL TOPIC LIST
418
418
  stim guide lifecycle budget # disk and memory budgets, automatic reclaim
419
419
  stim guide lifecycle options # every flag, Android variants, --device-type, --system-image, --device-profile
420
420
  stim guide lifecycle devices # ios --device and android --device on a physical phone
421
+ stim guide lifecycle tools # device location|permission|push|network on the owned simulator or emulator
421
422
  stim guide lifecycle release # Release configurations and ...Release variants
422
423
  stim guide api # typed run, stop, diagnostics and cancellation from the main package
423
424
  stim guide facts # the --json payloads
@@ -703,7 +704,7 @@ Do not point independent Stim homes at a concurrently writable shared cache.
703
704
  //#endregion
704
705
  //#region src/guide/facts.ts
705
706
  const facts = {
706
- summary: "The --json payloads: `start`, `ios`, `android`, `web`, `ios|android --plan`, `reload`, `stop`, `status`, `doctor`, `device lock`/`unlock`, `gc`, and the error contract",
707
+ summary: "The --json payloads: `start`, `ios`, `android`, `web`, `ios|android --plan`, `reload`, `stop`, `status`, `doctor`, `device lock`/`unlock`, `device location|permission|push|network`, `gc`, and the error contract",
707
708
  preamble: () => `SLOTS
708
709
  Named ios/android runs add slot to their JSON facts. Default-run fields remain
709
710
  compatible. status adds a slots array per environment with each named slot's
@@ -713,7 +714,7 @@ Named collector, lease-holder, and launch keys use platform:slot internally.
713
714
  FACTS CONTRACT
714
715
 
715
716
  \`start\`, \`ios\`, \`android\`, \`web\`, \`reload\`, \`stop\`, \`status\`, \`stats\`, \`doctor\`,
716
- \`gc\`, and \`device lock\`/\`device unlock\` each print exactly ONE line of JSON on
717
+ \`gc\`, \`device lock\`/\`device unlock\`, and \`device location|permission|push|network\` each print exactly ONE line of JSON on
717
718
  stdout for \`--json\`. Every other line goes to stderr, so it is always safe
718
719
  to pipe. \`logs --json\` is the one exception: it is NDJSON, one record per
719
720
  line by design (see \`guide logs\`), not this single-payload contract.
@@ -2503,8 +2504,9 @@ RULES
2503
2504
  \`guide lifecycle\`), so the sums can differ from what they sum.
2504
2505
 
2505
2506
  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\`):
2507
+ concurrency.maxBuilds is set, capacity.devices only while
2508
+ concurrency.maxDevices is set, and capacity.platformDevices only for the
2509
+ platforms whose cap is set (see \`guide lifecycle concurrency\`):
2508
2510
 
2509
2511
  load { cpus, loadPerCore, busyAt, limit, state }. loadPerCore is the
2510
2512
  5-minute load average divided by cpus, to one decimal. busyAt is
@@ -2527,6 +2529,11 @@ RULES
2527
2529
  device, with its device slot; for a device no workspace records,
2528
2530
  label is its name and workspace and slot are null. inUse is null
2529
2531
  and unknown says why when the devices could not be listed.
2532
+ platformDevices { ios?: { max, inUse, unknown? }, android?: { max, inUse,
2533
+ unknown? } }, the booted owned simulators and emulators counted
2534
+ against concurrency.maxIosDevices and concurrency.maxAndroidDevices.
2535
+ Each key is present only while its cap is set, whether or not
2536
+ concurrency.maxDevices is.
2530
2537
 
2531
2538
  The memory budget plans before a boot
2532
2539
  and always uses the estimate. What is using CPU and memory now is the
@@ -2667,7 +2674,9 @@ CAPACITY REFUSALS
2667
2674
  capacityRefusals?: [{ at, kind: "device", platform: "ios" | "android",
2668
2675
  max, workspace }]
2669
2676
  Only device refusals with STIM_AT_CAPACITY are recorded; build caps wait.
2670
- at is the ISO timestamp, max is concurrency.maxDevices, and workspace is
2677
+ at is the ISO timestamp, max is the cap of the limit that was full
2678
+ (concurrency.maxDevices, or the platform's concurrency.maxIosDevices or
2679
+ concurrency.maxAndroidDevices), and workspace is
2671
2680
  the workspace id used by status and Desktop. The list is newest first:
2672
2681
  the last 50 from the last 7 days, omitted when empty. Desktop uses events
2673
2682
  within 6 hours for its device-limit suggestion, including terminal runs.
@@ -4643,7 +4652,11 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
4643
4652
  then until SpringBoard has finished starting, which \`simctl launch\` needs.
4644
4653
  Booted alone does not end that wait. The failure names the udid and the wait.
4645
4654
  After boot, a process-spawn probe must finish within 30 seconds before
4646
- installation. If it fails, the refusal includes observed host memory pressure
4655
+ installation. A probe that times out while the simulator still reports Booted
4656
+ is retried for about three minutes, since a loaded host can leave a booted
4657
+ simulator unresponsive for a while; a timeout on a simulator that no longer
4658
+ reports Booted, and any other probe failure, refuse at once. If it
4659
+ fails, the refusal includes observed host memory pressure
4647
4660
  when available. Free memory before retrying under pressure; see
4648
4661
  \`stim guide lifecycle simslim\`. Booted alone does not prove readiness.
4649
4662
  The same probe lists the simulator's launchd jobs and requires a running
@@ -4715,6 +4728,35 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
4715
4728
  no token left in its \`state.json\` (its workspace directory was recreated).
4716
4729
  The remedy for that last one is \`stim device unlock\`, which releases by
4717
4730
  holder rather than by token.`
4731
+ },
4732
+ STIM_DEVICE_TOOL_TARGET: {
4733
+ summary: "a device tool found no owned, running simulator or emulator in that slot to act on",
4734
+ body: () => `STIM_DEVICE_TOOL_TARGET
4735
+ \`stim device location|permission|push|network\` act only on this workspace's
4736
+ own local simulator or emulator in the slot. The message says which check
4737
+ failed: the slot's device is hosted on another Mac, the workspace runs an
4738
+ EAS Simulator session, the slot has no owned device (a physical device
4739
+ reached with \`--device\` is never one), the recorded simulator is gone or not
4740
+ owned by this Stim home, or it is not booted or running. Permission and push
4741
+ also refuse when no app is recorded for the device. Run the platform command
4742
+ the remedy names (\`stim ios\` or \`stim android\`, with \`--slot\` for a named
4743
+ slot) and retry. No tool runs before this refusal.`
4744
+ },
4745
+ STIM_DEVICE_TOOL_UNSUPPORTED: {
4746
+ summary: "that device tool has no equivalent on that platform",
4747
+ body: () => `STIM_DEVICE_TOOL_UNSUPPORTED
4748
+ The platform lacks the action: Android cannot clear a simulated location
4749
+ (\`adb emu geo fix\` only sets one), iOS has no network switch, and Android
4750
+ has no simulated push. The remedy names the nearest thing.`
4751
+ },
4752
+ STIM_DEVICE_TOOL_FAILED: {
4753
+ summary: "simctl or adb failed, or the device did not report the change afterwards",
4754
+ body: () => `STIM_DEVICE_TOOL_FAILED
4755
+ The tool call exited non-zero or timed out, with its output in the message, or
4756
+ the read-back after an Android permission or network change did not show the
4757
+ requested state. For a permission, the app must declare the permission in its
4758
+ manifest; when it declares none of the service's permissions the call refuses
4759
+ with this code. Check the device with \`stim status\` and retry.`
4718
4760
  },
4719
4761
  STIM_DEVICE_WIRELESS_FAILED: {
4720
4762
  summary: "an iPhone paired over Wi-Fi timed out or dropped during install or launch; use the cable",
@@ -4745,8 +4787,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
4745
4787
  STIM_AT_CAPACITY: {
4746
4788
  summary: "owned-device slot wait timed out, or --no-wait reached the cap or queue",
4747
4789
  body: () => `STIM_AT_CAPACITY
4748
- Only when concurrency.maxDevices is set (unset by default). New owned
4749
- devices queue in FIFO order across $STIM_HOME for 600 seconds by default.
4790
+ Only when concurrency.maxDevices, concurrency.maxIosDevices or
4791
+ concurrency.maxAndroidDevices is set (all unset by default). A boot must fit
4792
+ its platform cap and concurrency.maxDevices; the message names the limit that
4793
+ was full with its count and cap. New owned devices queue in FIFO order across $STIM_HOME for 600 seconds by default.
4750
4794
  This refusal means the wait expired, or \`--no-wait\` / \`--wait 0\`
4751
4795
  found the cap full or another run queued. The message gives the current
4752
4796
  count and, on timeout, how long it waited. iOS waits beside its build,
@@ -4764,7 +4808,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
4764
4808
  --no-wait and --wait 0 refuse at once. Builds under remote-only refuse with
4765
4809
  STIM_OFFLOAD_REFUSED instead.
4766
4810
  Stop an environment (\`stim stop\`), pass a longer \`--wait <seconds>\`,
4767
- or raise concurrency.maxDevices. With --remote auto, remote.machines and
4811
+ or raise the limit the message names (concurrency.maxDevices, or the
4812
+ platform's concurrency.maxIosDevices / maxAndroidDevices). On a stim-server
4813
+ worker the hosted offer and reserve name the full limit too, including
4814
+ concurrency.maxMacosApps. With --remote auto, remote.machines and
4768
4815
  the opt-in remote.easFallback (billed EAS Simulator) are tried before this
4769
4816
  wait; \`stim logs --source placement\` says why neither took the run. Waiting prints holder names and elapsed
4770
4817
  time; status JSON exposes build.waitingFor independently of phase.
@@ -5734,8 +5781,11 @@ SpringBoard is back; an already slim simulator is not touched. Turn sound on
5734
5781
  for one device with Sound (iOS) or Media sound (Android) in its Stim Desktop
5735
5782
  options; the choice lasts until that device next boots. Android 14 and older images have no shell command that can
5736
5783
  set media volume, so startup warns, as it does whenever a mute is not
5737
- confirmed. Host volume, Android alarm and ringtone volumes, hosted devices and
5738
- physical devices are unchanged.
5784
+ confirmed. A hosted simulator or emulator on a named Mac is muted the same way
5785
+ after the host boots or adopts it (best effort; a failed mute is not reported
5786
+ to the client), and Stim Desktop's Sound options do not reach
5787
+ it. Host volume, Android alarm and ringtone volumes and physical devices are
5788
+ unchanged.
5739
5789
 
5740
5790
  Repeat step 3 whenever a NATIVE input changes. A JS-only edit needs nothing --
5741
5791
  that is what Fast Refresh over the running dev server is for. \`stim reload\` is
@@ -6282,7 +6332,7 @@ The same setup serves macos --remote and macos.remote. Approval is separate from
6282
6332
  and phone control. Set ios.remote to the machine name for a default (machine scope for every app on this machine);
6283
6333
  no flag or setting runs here. eas and proxy keep their remote backend meanings.
6284
6334
  --remote auto (or ios.remote = auto / android.remote = auto) stays here when
6285
- there is a free concurrency.maxDevices slot (0 means unlimited), no device
6335
+ there is a free concurrency.maxDevices slot and platform cap slot (0 means unlimited), no device
6286
6336
  waiter ahead, normal host memory pressure, no budget shortfall,
6287
6337
  and 5-minute load per core below server.maxLoadPerCore. Without remote.machines,
6288
6338
  auto and remote are local and remote-only refuses with STIM_HOSTING_REFUSED. An unknown local device count also stays local; boot admission
@@ -6317,7 +6367,7 @@ when it names a machine, then remote.machines order, so the first listed host wi
6317
6367
  room fills before the next gets a run. Load and free memory do not rank hosts.
6318
6368
  Automatic build offload resolves later, after the device architecture is known.
6319
6369
 
6320
- When no host admits and this machine is at its concurrency.maxDevices cap (or runs
6370
+ When no host admits and this machine is at its concurrency.maxDevices or per-platform cap (or runs
6321
6371
  are queued ahead), remote.easFallback (default false; EAS Simulator is billed)
6322
6372
  runs the device on an EAS Simulator exactly as --remote eas would: the build
6323
6373
  stays here, nothing starts an EAS cloud build, stop ends the session, and
@@ -6358,7 +6408,8 @@ refuses. The host boots headless and ignores this Mac's iosSimulatorApp setting.
6358
6408
  the offered simulator architecture, not this machine's. --remote-build remains
6359
6409
  independent and selects a compatible build worker for a Debug cache miss.
6360
6410
 
6361
- The host's own owned devices count toward concurrency.maxDevices.
6411
+ The host's own owned devices count toward concurrency.maxDevices and its per-platform cap
6412
+ (concurrency.maxIosDevices, concurrency.maxAndroidDevices; hosted macOS apps use concurrency.maxMacosApps).
6362
6413
 
6363
6414
  The host's person sees Hosted here rows in stim-server devices; --json adds
6364
6415
  hostedSessions beside devices. Rows show client, platform, device, installed
@@ -7702,7 +7753,8 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
7702
7753
  wait also records a capacityWaits event in stats,
7703
7754
  with reclaimed when one or more devices were
7704
7755
  shut down for it.
7705
- While at the cap, only the queue head reclaims:
7756
+ While at the cap, only the queue head reclaims (or a run behind a
7757
+ head held back only by its own platform's cap):
7706
7758
  it shuts down the longest-idle eligible owned
7707
7759
  device in another workspace of this Stim home,
7708
7760
  one per attempt, at most once every 15 seconds,
@@ -7722,6 +7774,35 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
7722
7774
  and the command to remove that exact claim.
7723
7775
  See \`guide errors STIM_AT_CAPACITY\`.
7724
7776
 
7777
+ concurrency.maxIosDevices booted owned iOS simulators at once.
7778
+ concurrency.maxAndroidDevices booted owned Android emulators at once.
7779
+ concurrency.maxMacosApps hosted macOS apps on a worker at once.
7780
+ Each is 0 (no per-platform limit) unless set, and
7781
+ each only tightens: a run must fit its platform's
7782
+ cap AND concurrency.maxDevices. maxDevices counts
7783
+ simulators and emulators together, local and
7784
+ hosted, and counts hosted macOS apps as a pool of
7785
+ their own, so a macOS app is bounded by
7786
+ maxMacosApps and by maxDevices, and never adds to
7787
+ the simulator and emulator total. Leaving the new
7788
+ settings unset changes no existing cap.
7789
+ Local admission applies the iOS and Android caps
7790
+ with the same queue and reclaim as maxDevices; a
7791
+ waiter held back only by its own platform's cap
7792
+ does not hold up a waiter of another platform.
7793
+ Reclaim for a full platform cap only shuts down
7794
+ devices of that platform. Hosted admission on a
7795
+ worker (offer and reserve) applies all three,
7796
+ counting the worker's local devices too.
7797
+ Local \`stim macos\` runs are not counted, so
7798
+ maxMacosApps limits hosted macOS apps only.
7799
+ A refusal names the full limit, its count and its
7800
+ cap, for example "1 Stim iOS simulator(s) are
7801
+ already booted and concurrency.maxIosDevices is 1".
7802
+ Status JSON capacity.platformDevices reports
7803
+ { max, inUse } for each of ios and android whose
7804
+ cap is set.
7805
+
7725
7806
  \`stim doctor\` prints one note echoing the caps and the current active count,
7726
7807
  but ONLY when a cap is set. \`stim gc\` reports stale build slots the way it
7727
7808
  reports stale build locks, and \`gc --delete\` clears them. Set the caps
@@ -8453,6 +8534,60 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
8453
8534
  The chosen device is on the phase line and in \`--json\` (\`udid\` or
8454
8535
  \`serial\`, plus \`deviceName\`), so an agent can hand the same id to its
8455
8536
  device tool.`
8537
+ },
8538
+ tools: {
8539
+ summary: "device location, permission, push and network: change the owned simulator or emulator and read it back",
8540
+ body: () => ` \`stim device location|permission|push|network\` change the workspace's own
8541
+ simulator or emulator. Each takes the platform first, like \`device lock\`,
8542
+ and \`--slot <name>\` and \`--json\`:
8543
+
8544
+ stim device location <ios|android> --set <lat,lng> # --set 45.5,-73.6
8545
+ stim device location ios --clear
8546
+ stim device permission <ios|android> <grant|revoke|reset> <service>
8547
+ stim device push ios --payload '<json with an "aps" key>'
8548
+ stim device network android <on|off>
8549
+
8550
+ THE TARGET is the slot's owned, booted simulator or emulator, resolved the
8551
+ way \`reload\` resolves it: the project record says \`owned\`, the ledger
8552
+ agrees, and the serial belongs to the recorded AVD. A hosted device, an EAS
8553
+ Simulator session, a physical device (\`--device\`), a device Stim does not
8554
+ own, and a device that is not running refuse with STIM_DEVICE_TOOL_TARGET and
8555
+ run no tool. An action the platform lacks (Android \`--clear\`, iOS network,
8556
+ Android push) refuses with STIM_DEVICE_TOOL_UNSUPPORTED. A tool call that
8557
+ fails, or a device that disagrees with the change afterwards, is
8558
+ STIM_DEVICE_TOOL_FAILED. A bad value is STIM_BAD_ARG.
8559
+
8560
+ \`--set\` takes latitude and longitude as ONE value so a negative latitude is
8561
+ not read as a flag. Android's \`adb emu geo fix\` takes longitude first; Stim
8562
+ swaps them. The emulator has no way to clear a location.
8563
+
8564
+ \`permission\` acts on the app of the slot's last launch, else the project's
8565
+ bundle id or Android package. iOS services are simctl's own: all, calendar,
8566
+ contacts, contacts-limited, location, location-always, media-library,
8567
+ microphone, motion, photos, photos-add, reminders, siri. iOS notifications
8568
+ and camera are not simctl services. Android services are calendar, camera,
8569
+ contacts, location, microphone, motion, notifications, photos; one service is
8570
+ one or two \`pm\` permissions. A permission the app did not declare is
8571
+ listed in \`skipped\` and the call succeeds when the app declares at least one;
8572
+ an app that declares none is STIM_DEVICE_TOOL_FAILED.
8573
+ \`push\` needs the app to hold notification permission on the simulator, which
8574
+ \`simctl privacy\` cannot grant: without it simctl answers "Source is not
8575
+ authorized" and the call is STIM_DEVICE_TOOL_FAILED; open the app and accept
8576
+ its prompt.
8577
+ Android \`reset\` revokes the permission and clears its user-set flags so
8578
+ the app asks again. A grant needs one of the
8579
+ service's permissions to read back granted; a revoke or reset needs all of
8580
+ them not granted, and a reset also no USER_SET or USER_FIXED flag. Changing a
8581
+ permission can terminate the running app on both platforms.
8582
+
8583
+ \`--json\` prints ONE line: { platform, slot, deviceId, deviceName, tool,
8584
+ action, ..., readBack }. \`readBack\` is read from the device after the change:
8585
+ Android permissions are { permissions: [{ name, granted }] } from
8586
+ \`dumpsys package\`, and Android network is { wifi, data } from \`settings get
8587
+ global wifi_on|mobile_data\`. \`readBack\` is null where the platform has no
8588
+ read: iOS location, permission and push, and Android location. Then the exit
8589
+ status of simctl or adb is the only confirmation; Stim never echoes the
8590
+ request as a read-back.`
8456
8591
  },
8457
8592
  release: {
8458
8593
  summary: "Release configurations and ...Release variants: Metro skipped, process-proven launch, the JS swap",
@@ -10130,7 +10265,7 @@ KEYS STIM READS
10130
10265
  restores stock services when Stim applied the profile. Absolute paths, root or
10131
10266
  symlink escapes, and missing files are refused before
10132
10267
  simulator creation. Remote and unowned simulators are
10133
- never changed.
10268
+ never slimmed.
10134
10269
  ios.signingIdentity e.g. "Apple Development: Jane (TEAMID5678)" -- the
10135
10270
  keychain identity to re-seal a \`--device\` build with,
10136
10271
  overriding the one Stim derives from the artifact's own
@@ -10324,8 +10459,9 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
10324
10459
  lifecycle hosted-android.
10325
10460
  remote.easFallback true lets "auto" or "remote" (ios.remote, android.remote
10326
10461
  or --remote) run the simulator or emulator on a
10327
- billed EAS Simulator when this machine is at its
10328
- concurrency.maxDevices cap (or has runs queued) and no
10462
+ billed EAS Simulator when this machine is at a
10463
+ device cap (concurrency.maxDevices or a per-platform
10464
+ cap, or has runs queued) and no
10329
10465
  remote.machines entry takes the run, instead of waiting
10330
10466
  or refusing with STIM_AT_CAPACITY. Default false. A
10331
10467
  busy machine with a free slot never uses it. Stim checks
@@ -10559,12 +10695,20 @@ machine's. They live under a top-level \`concurrency\` key in
10559
10695
  "concurrency": { "maxBuilds": 2, "maxDevices": 3 }
10560
10696
  }
10561
10697
 
10562
- The keys are concurrency.maxBuilds and concurrency.maxDevices.
10698
+ The keys are concurrency.maxBuilds and concurrency.maxDevices, plus the
10699
+ per-platform device caps concurrency.maxIosDevices,
10700
+ concurrency.maxAndroidDevices and concurrency.maxMacosApps. A boot must fit
10701
+ its platform cap and concurrency.maxDevices; the per-platform caps only
10702
+ tighten (see \`guide lifecycle concurrency\`).
10563
10703
 
10564
10704
  or via the environment, which overrides the file:
10565
10705
 
10566
10706
  STIM_MAX_BUILDS=2 STIM_MAX_DEVICES=3 stim ios
10567
10707
 
10708
+ concurrency.maxIosDevices STIM_MAX_IOS_DEVICES
10709
+ concurrency.maxAndroidDevices STIM_MAX_ANDROID_DEVICES
10710
+ concurrency.maxMacosApps STIM_MAX_MACOS_APPS
10711
+
10568
10712
  Unset, 0, or any non-positive value means NO enforcement -- the default, where
10569
10713
  Stim limits nothing. See \`guide lifecycle concurrency\` for what each cap
10570
10714
  does.
@@ -10931,6 +11075,13 @@ answer, an incompatible Stim build, CPU, Xcode, simulator SDK or CocoaPods, no
10931
11075
  Bundler for an app whose Gemfile.lock pins CocoaPods, no iPhone simulator on
10932
11076
  the runtime \`stim ios\` builds for here, low disk, or busy. With Package.swift
10933
11077
  and no platform selection on a Mac, it also checks the macOS Xcode and SDK.
11078
+ A client with no Xcode and no simulator SDK, such as Linux or Windows, has no
11079
+ Xcode to match: the Mac's own Xcode, simulator SDK and CocoaPods are the
11080
+ 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.
10934
11085
  Two machines build for each other when their Stim releases share a build
10935
11086
  compatibility version, which changes only when what a worker builds, how it
10936
11087
  builds, or the build messages change; their Stim builds can differ. A
@@ -12186,10 +12337,9 @@ script such as mini-desktop.sh use these instead:
12186
12337
  quit stim stop (verified stop; the host frees the slot
12187
12338
  and removes the app's defaults)
12188
12339
  clean stim worktree remove
12189
- 3 concurrent slots concurrency.maxDevices on the host; one bundle id
12190
- slot per session
12191
-
12192
- The host's own owned devices count toward concurrency.maxDevices.
12340
+ 3 concurrent slots concurrency.maxMacosApps and concurrency.maxDevices
12341
+ on the host, counted apart from simulators and
12342
+ emulators; one bundle id slot per session
12193
12343
 
12194
12344
  The agent-device rows work once the host's agent field names agent-device.
12195
12345
 
@@ -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-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";
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";
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
1
  import { c as throwIfCancelled, o as cancellableSleep } from "./exec-aULwtNly.mjs";
2
- import { Y as diagnoseConnectFailure, st as resolveEndpoint } from "./config-AbUjIBOQ.mjs";
3
- import { t as BuildConnection } from "./client-BTUH8TF1.mjs";
4
- import { g as configuredMachines } from "./selection-D1ZDzHFX.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";
5
5
  import { createHash } from "node:crypto";
6
6
  import { lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
7
7
  import { join } from "node:path";
@@ -232,25 +232,49 @@ function bundleManifest(bundle) {
232
232
  content
233
233
  };
234
234
  }
235
+ /** stim-server answers one connection's requests in arrival order, so chunks sent in order reach it in order. */
236
+ const UPLOAD_WINDOW = 64;
235
237
  async function upload(host, ids, missing, content) {
236
238
  if (!Array.isArray(missing)) throw new Error(`${host.machine} answered device-host.app.offer without missing content.`);
237
- for (const entry of missing) {
239
+ const files = missing.map((entry) => {
238
240
  const read = isJsonObject(entry) && typeof entry.sha256 === "string" ? content.get(entry.sha256) : void 0;
239
- if (!read || !isJsonObject(entry) || typeof entry.offset !== "number") throw new Error(`${host.machine} asked for content this app does not have.`);
240
- const bytes = read();
241
- let offset = entry.offset;
242
- do {
243
- const data = bytes.subarray(offset, offset + HOSTED_APP_CHUNK_BYTES).toString("base64");
241
+ if (!read || !isJsonObject(entry) || typeof entry.sha256 !== "string" || typeof entry.offset !== "number") throw new Error(`${host.machine} asked for content this app does not have.`);
242
+ return {
243
+ digest: entry.sha256,
244
+ start: entry.offset,
245
+ read
246
+ };
247
+ });
248
+ const inFlight = /* @__PURE__ */ new Set();
249
+ let failure;
250
+ const send = async (digest, offset, end, data) => {
251
+ try {
244
252
  const next = (await call(host, "device-host.app.chunk", {
245
253
  ...ids,
246
- sha256: entry.sha256,
254
+ sha256: digest,
247
255
  offset,
248
256
  data
249
257
  })).offset;
250
- if (typeof next !== "number" || next <= offset && next !== bytes.length) throw new Error(`${host.machine} did not accept app content at byte ${offset}.`);
251
- offset = next;
258
+ if (typeof next !== "number" || next < end) throw new Error(`${host.machine} did not accept app content at byte ${offset}.`);
259
+ } catch (error) {
260
+ failure ??= error instanceof Error ? error : new Error(String(error));
261
+ }
262
+ };
263
+ for (const { digest, start, read } of files) {
264
+ if (failure) break;
265
+ const bytes = read();
266
+ let offset = start;
267
+ do {
268
+ if (inFlight.size >= UPLOAD_WINDOW) await Promise.race(inFlight);
269
+ if (failure) break;
270
+ const end = Math.min(offset + HOSTED_APP_CHUNK_BYTES, bytes.length);
271
+ const pending = send(digest, offset, end, bytes.subarray(offset, end).toString("base64")).finally(() => inFlight.delete(pending));
272
+ inFlight.add(pending);
273
+ offset = end;
252
274
  } while (offset < bytes.length);
253
275
  }
276
+ await Promise.all(inFlight);
277
+ if (failure) throw failure;
254
278
  }
255
279
  //#endregion
256
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 };
@@ -1,11 +1,11 @@
1
1
  import { t as getExecutor } from "./exec-aULwtNly.mjs";
2
- import { E as workspaceDir, k as workspaceLogsDir$1 } from "./workspace-state-DGwkPXwq.mjs";
3
- import { B as deviceSlotFileKey, it as parseMachine$1, q as validateDeviceSlot } from "./config-AbUjIBOQ.mjs";
4
- import { l as phaseLine } from "./command-output-DjCsmzLZ.mjs";
5
- import { n as macosDir } from "./state-C2AUjjhg.mjs";
6
- import { n as androidLogGroups, r as isAndroidCrashText } from "./android-CLU_MMnb.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";
7
7
  import { c as readNdjsonGenerations$1, i as createNdjsonWriter } from "./ndjson-CrjIsGzw.mjs";
8
- import { c as call } from "./hosted-client-CgoxdU9j.mjs";
8
+ import { c as call } from "./hosted-client-5ur3YpxY.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";