stim 1.18.0 → 1.20.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 (178) hide show
  1. package/README.md +21 -4
  2. package/dist/{activity-BxnkDZDi.mjs → activity-BrGh9EAI.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
  4. package/dist/android-0vv-OruW.mjs +6 -0
  5. package/dist/android-Brx6EKvJ.mjs +1258 -0
  6. package/dist/{android-DC3ZLuw0.mjs → android-BsYNR81W.mjs} +103 -45
  7. package/dist/{android-CBwCNicO.mjs → android-CK3fpEyZ.mjs} +2 -2
  8. package/dist/{android-cas-BBFyr9CA.mjs → android-cas-DCAuXryb.mjs} +9 -5
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/api-run.mjs +159 -8
  11. package/dist/{api-D0VtFhqk.mjs → api-zuX3ynYN.mjs} +9 -7
  12. package/dist/api.d.mts +104 -4
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-D-PUENug.mjs → app-install-0LgaQRT7.mjs} +39 -18
  15. package/dist/artifact-CnC0mfov.mjs +807 -0
  16. package/dist/artifact-DClXJNWx.mjs +772 -0
  17. package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
  18. package/dist/{web-DTU0uiWj.mjs → browser-web-CzBmhmgs.mjs} +136 -174
  19. package/dist/{budget-DIhL2BKx.mjs → budget-BONq9vXY.mjs} +3096 -3244
  20. package/dist/build-BixRI6sB.mjs +462 -0
  21. package/dist/build-plan-CP0tckNU.mjs +553 -0
  22. package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/ccache-CjHQ5F8g.mjs +142 -0
  25. package/dist/{chrome-DJnmnS5q.mjs → chrome-Dp2lMLBe.mjs} +1 -1
  26. package/dist/{cli-DNJMwADx.mjs → cli-B2R8wH1F.mjs} +20 -20
  27. package/dist/cli.mjs +1 -1
  28. package/dist/{client-DzhapoMB.mjs → client-BLy1Pw2V.mjs} +172 -165
  29. package/dist/collector-run.d.mts +10 -0
  30. package/dist/collector-run.mjs +7 -7
  31. package/dist/{command-output-CBtzyIgF.mjs → command-output-BjPN99ZB.mjs} +2 -2
  32. package/dist/{config-CgYMahz7.mjs → config-D0LhTY3S.mjs} +13 -13
  33. package/dist/{created-devices-DKbeWsiK.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
  34. package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
  35. package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
  36. package/dist/{dev-client-CLnIH02x.mjs → dev-client-ClATaJoH.mjs} +2 -2
  37. package/dist/{device-D7oCHGWi.mjs → device-B7lsC0K1.mjs} +8 -8
  38. package/dist/device-DVCwAFlX.mjs +727 -0
  39. package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-Ca_ke1LE.mjs} +25 -15
  40. package/dist/device-host-worker.mjs +38 -18
  41. package/dist/{device-ios-6MewKKnc.mjs → device-ios-CRUqPxKw.mjs} +12 -11
  42. package/dist/{device-lease-Co-EwifR.mjs → device-lease-DHOBXGgS.mjs} +135 -22
  43. package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
  44. package/dist/{device-pool-F5WvRPtD.mjs → device-pool-L2-5GxMy.mjs} +3 -3
  45. package/dist/{device-remote-tHbd1fKy.mjs → device-remote-Bmg42063.mjs} +17 -69
  46. package/dist/doctor-C2MSuMMg.mjs +515 -0
  47. package/dist/{doctor-B9ckYUoU.mjs → doctor-DPAqhVCK.mjs} +334 -721
  48. package/dist/doctor-watchman-CB4NnVZm.mjs +260 -0
  49. package/dist/{simslim-EHBQ2R4G.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
  50. package/dist/{stim-installations-aR_WsNOA.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
  51. package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
  52. package/dist/errors-DzkMYh8Q.mjs +205 -0
  53. package/dist/{exec-DWhCZDGm.mjs → exec-B81Qodjn.mjs} +69 -15
  54. package/dist/{gc-Dh6mXOKC.mjs → gc-PWp34zGb.mjs} +23 -22
  55. package/dist/{gradle-C6GKnunQ.mjs → gradle-C2OEKCCI.mjs} +50 -125
  56. package/dist/{guide-tm6igAaa.mjs → guide-Dai9lphv.mjs} +862 -538
  57. package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
  58. package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-Io01s5By.mjs} +9 -3
  59. package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
  60. package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
  61. package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
  62. package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-BdAQi21M.mjs} +23 -16
  63. package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
  64. package/dist/ios-BZ9dg2Fr.mjs +9 -0
  65. package/dist/{ios-B3SbOWdw.mjs → ios-CXLIUxXJ.mjs} +180 -24
  66. package/dist/ios-CZuv6gRv.mjs +1112 -0
  67. package/dist/{ios-Bvbf0SGY.mjs → ios-VGvNdsv2.mjs} +1 -1
  68. package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-B1B14xND.mjs} +1 -1
  69. package/dist/{ios-device-vOaByMhw.mjs → ios-device-BreZOpM0.mjs} +3 -3
  70. package/dist/ios-project-B9drt_aY.mjs +197 -0
  71. package/dist/{ios-state-B2pES6Vs.mjs → ios-state-CjrL2qv-.mjs} +1 -1
  72. package/dist/js-swap-C8icNYIY.mjs +432 -0
  73. package/dist/launch-DxH0THLP.mjs +745 -0
  74. package/dist/launch-YrbqaIFj.mjs +1530 -0
  75. package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
  76. package/dist/{logs-1Ylc1Ri6.mjs → logs-DHaRNfg7.mjs} +11 -11
  77. package/dist/macos-C0iljhsN.mjs +2 -0
  78. package/dist/{macos-DF6C7wUU.mjs → macos-V_3Ui7g4.mjs} +125 -155
  79. package/dist/macos-run.mjs +1 -1
  80. package/dist/maintenance-run.mjs +13 -10
  81. package/dist/{metro-Dh8T4Ytd.mjs → metro-D_j9sN-B.mjs} +209 -43
  82. package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
  83. package/dist/miss-reason-BPAzZS0r.mjs +238 -0
  84. package/dist/{named-ports-BFIz1Shz.mjs → named-ports-C2lvoPsb.mjs} +12 -5
  85. package/dist/native-android-lHzaew7r.mjs +226 -0
  86. package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
  87. package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
  88. package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
  89. package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
  90. package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
  91. package/dist/offload-worker.d.mts +12 -6
  92. package/dist/offload-worker.mjs +409 -73
  93. package/dist/{ownership-D6Se7gg_.mjs → ownership-DXzMMSx6.mjs} +2 -2
  94. package/dist/{placement-log-BcPhRwR4.mjs → placement-log-reFbjqEr.mjs} +7 -3
  95. package/dist/plan-BDk2AeY_.mjs +260 -0
  96. package/dist/plan-placement-D_YYlE6N.mjs +73 -0
  97. package/dist/{ports-BLTtfBq-.mjs → ports-jzvAJXXL.mjs} +3 -3
  98. package/dist/{prebuild-juCyreaR.mjs → prebuild-Bw44QxVh.mjs} +4 -4
  99. package/dist/{preview-D5V07Nrl.mjs → preview-BaBJ72Al.mjs} +51 -34
  100. package/dist/project-B8_duAzW.mjs +1067 -0
  101. package/dist/project-plan-BPwbLwQu.mjs +10 -0
  102. package/dist/{pull-request-u4vp7zmK.mjs → pull-request-vOhLNmIb.mjs} +1 -1
  103. package/dist/pull-requests.mjs +1 -1
  104. package/dist/react-native-android-chm1DMlA.mjs +921 -0
  105. package/dist/react-native-build-oAw6gQeW.mjs +239 -0
  106. package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
  107. package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
  108. package/dist/{recordings-BAWltsVt.mjs → recordings-Bk-VivUV.mjs} +1 -1
  109. package/dist/{reload-DvyWzVjJ.mjs → reload-D34GkY78.mjs} +17 -14
  110. package/dist/remote-BU9UyhCJ.mjs +192 -0
  111. package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
  112. package/dist/result-BDoRk1k3.mjs +186 -0
  113. package/dist/{run-vhtDgpHO.mjs → run-qvff78hv.mjs} +3 -3
  114. package/dist/{server-bare-B9E7S1aR.mjs → server-bare-dWjAarki.mjs} +6 -6
  115. package/dist/server-command-7XIKlWtO.mjs +69 -0
  116. package/dist/{server-expo-DoBHhuzK.mjs → server-expo-CsYu2aKL.mjs} +107 -82
  117. package/dist/server-expo-DV43vep4.mjs +2 -0
  118. package/dist/settings-Bbztm4oV.mjs +1503 -0
  119. package/dist/{settings-Byp2AQ_E.mjs → settings-CT3E71-i.mjs} +6 -7
  120. package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
  121. package/dist/settings.schema.json +156 -6
  122. package/dist/simslim-ChMfe8rg.mjs +149 -0
  123. package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-B9hn96wd.mjs} +6 -6
  124. package/dist/{stage-g_WqWeaE.mjs → stage-BNKKdDNc.mjs} +6 -3
  125. package/dist/start-CbQCSnXQ.mjs +2 -0
  126. package/dist/{start-D-IeOyoK.mjs → start-CdvcTaXr.mjs} +113 -77
  127. package/dist/{state-xnqpx3AD.mjs → state-Boo0IMJq.mjs} +4 -2
  128. package/dist/{state-BG-aAk4k.mjs → state-DI84A-uu.mjs} +29 -10
  129. package/dist/{stats-DY6ekz8F.mjs → stats-BIIDrjA8.mjs} +6 -6
  130. package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
  131. package/dist/{status-DCjZeE-K.mjs → status-DARMkc9q.mjs} +80 -294
  132. package/dist/status-watch-DvmI3SmN.mjs +296 -0
  133. package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
  134. package/dist/{stop-DIJtD2GL.mjs → stop-CCZS-C9m.mjs} +2 -2
  135. package/dist/stop-WQPQHLuy.mjs +72 -0
  136. package/dist/{stop-BTjs3xbc.mjs → stop-iNemHsJC.mjs} +81 -33
  137. package/dist/supervisor-run.d.mts +7 -2
  138. package/dist/supervisor-run.mjs +32 -20
  139. package/dist/{support-Bwvbrq5-.mjs → support-CnE_SIjt.mjs} +17 -7
  140. package/dist/{support-BaayeYCf.mjs → support-DCco5fut.mjs} +61 -8
  141. package/dist/swiftpm-macos-afeNUExW.mjs +119 -0
  142. package/dist/{native-run-B06FkmZx.mjs → tailnet-CoJUb2tB.mjs} +113 -6
  143. package/dist/toolchain-BIupIro1.mjs +2 -0
  144. package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-DqyDXs30.mjs} +225 -315
  145. package/dist/{trigger-CJMhwXe8.mjs → trigger-C0MWBi8O.mjs} +3 -3
  146. package/dist/trigger-SHLOWJ4O.mjs +2 -0
  147. package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-C3ASD6z5.mjs} +134 -37
  148. package/dist/{status-Dcr0Qexd.mjs → watchman-CQl51YZu.mjs} +75 -7
  149. package/dist/web-B3eldHFH.mjs +123 -0
  150. package/dist/web-BLXpOe6b.mjs +2 -0
  151. package/dist/web-run.mjs +10 -10
  152. package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
  153. package/dist/{workspaces-xXItD8Dj.mjs → workspaces-D2xSHBDY.mjs} +1297 -1211
  154. package/dist/{worktree-BSYlofkq.mjs → worktree-BxDqaTev.mjs} +102 -63
  155. package/dist/worktree-q7_OZNY0.mjs +2 -0
  156. package/package.json +8 -6
  157. package/shim/bundle-response.cjs +2 -1
  158. package/shim/bundle-response.d.cts +1 -1
  159. package/shim/expo-metro-config.cjs +1 -1
  160. package/shim/native-android.gradle +101 -0
  161. package/dist/android-BKA16DTf.mjs +0 -4
  162. package/dist/android-BvwuMUJ9.mjs +0 -3572
  163. package/dist/guide-status-Bhf9SJXc.mjs +0 -125
  164. package/dist/ios-CPdkoKaa.mjs +0 -3953
  165. package/dist/ios-DNpdygiv.mjs +0 -7
  166. package/dist/macos-Ck7OBMNY.mjs +0 -2
  167. package/dist/metro-store-BAHFcJm6.mjs +0 -106
  168. package/dist/plan-placement-CtxkCO54.mjs +0 -1859
  169. package/dist/project-C3ChRLZy.mjs +0 -212
  170. package/dist/projects-DD7dBTCj.mjs +0 -92
  171. package/dist/server-expo-Db9HBUoa.mjs +0 -2
  172. package/dist/settings-CQyMElEP.mjs +0 -701
  173. package/dist/start-NTc1Ifqs.mjs +0 -2
  174. package/dist/stop-BGhKMOuH.mjs +0 -48
  175. package/dist/trigger-DWAq9hkw.mjs +0 -2
  176. package/dist/web-B6_bFDn7.mjs +0 -2
  177. package/dist/worktree-BJfnU6r5.mjs +0 -2
  178. package/dist/worktree-CsKYexJM.mjs +0 -753
@@ -1,9 +1,9 @@
1
- import { a as call, o as connectHost } from "./hosted-client-C-rMtppF.mjs";
2
- import { i as requestHostedMetro } from "./metro-gateway-CEUw9RMH.mjs";
3
- import { n as prepareHostedNative, r as stopHostedNative, t as placeHostedNative } from "./hosted-native-DeeOG8xZ.mjs";
1
+ import { o as call, s as connectHost } from "./hosted-client-Io01s5By.mjs";
2
+ import { i as requestHostedMetro } from "./metro-gateway-BBJldOdi.mjs";
3
+ import { n as prepareHostedNative, r as stopHostedNative, t as placeHostedNative } from "./hosted-native-BdAQi21M.mjs";
4
4
  //#region src/device-host/hosted-android.ts
5
- async function prepareHostedAndroid(machine, selectors, recorded) {
6
- return await prepareHostedNative(machine, selectors, recorded, "android");
5
+ async function prepareHostedAndroid(machine, selectors, recorded, mode) {
6
+ return await prepareHostedNative(machine, selectors, recorded, "android", false, mode);
7
7
  }
8
8
  async function placeHostedAndroid(target, options) {
9
9
  return await placeHostedNative(target, {
@@ -1,4 +1,5 @@
1
- import { C as pinnedEndpoint$1, t as BuildConnection, y as configuredMachines } from "./client-DzhapoMB.mjs";
1
+ import { c as pinnedEndpoint$1 } from "./tailnet-CoJUb2tB.mjs";
2
+ import { t as BuildConnection, x as configuredMachines } from "./client-BLy1Pw2V.mjs";
2
3
  import { lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
  import { HOSTED_APP_CHUNK_BYTES, hostedMacosAppSlot, isJsonObject, readDeviceHostMachines } from "@stim-cli/core/state";
@@ -7,6 +8,7 @@ import { createHash } from "node:crypto";
7
8
  const CONNECT_TIMEOUT_MS = 1e4;
8
9
  /** Covers 90s stop + 15s final logs + three 10s worker group-settle bounds, with 45s for polling and transport. */
9
10
  const SESSION_TIMEOUT_MS = 18e4;
11
+ const PREPARE_TIMEOUT_MS = 355e3;
10
12
  const INSTALL_TIMEOUT_MS = 3e5;
11
13
  const sleep = (ms) => new Promise((done) => setTimeout(done, ms));
12
14
  const sha256 = (content) => createHash("sha256").update(content).digest("hex");
@@ -37,7 +39,7 @@ function hostingCredential(machine) {
37
39
  /** Connects only to the pinned node of an approved remote Mac, and only when it grants `device-host`. */
38
40
  async function connectHost(machine, timeoutMs = CONNECT_TIMEOUT_MS, strict = false) {
39
41
  const credential = hostingCredential(machine);
40
- const target = pinnedEndpoint$1(credential);
42
+ const target = await pinnedEndpoint$1(credential);
41
43
  if (typeof target === "string") throw Object.assign(/* @__PURE__ */ new Error(`Stim does not connect to ${machine}: ${target}.`), { code: "STIM_HOSTING_REFUSED" });
42
44
  const opened = await BuildConnection.open(target, credential.deviceToken, timeoutMs, "device-host").catch((error) => {
43
45
  throw Object.assign(new Error(`${machine} is unreachable. Check stim-server and its tailnet serve route on ${machine}.`, { cause: error }), { code: strict ? "STIM_HOSTING_REFUSED" : "closed" });
@@ -52,6 +54,10 @@ async function connectHost(machine, timeoutMs = CONNECT_TIMEOUT_MS, strict = fal
52
54
  connection: opened
53
55
  };
54
56
  }
57
+ function requireHostedAppMode(host, platform, mode) {
58
+ if (mode !== "process") return;
59
+ if (!host.connection.supports(platform === "ios" ? "hosted-ios-process" : "hosted-android-process")) throw credentialRefusal(`${host.machine} does not support hosted ${platform} process apps.`, `Update stim-server on ${host.machine} to a version supporting hosted ${platform} process apps, then retry.`);
60
+ }
55
61
  const gatewaySecrets = /* @__PURE__ */ new WeakMap();
56
62
  function redactHostText(host, message) {
57
63
  for (const secret of [host.credential.deviceToken, gatewaySecrets.get(host)]) if (secret) message = message.replaceAll(secret, "[redacted]");
@@ -193,4 +199,4 @@ async function upload(host, ids, missing, content) {
193
199
  }
194
200
  }
195
201
  //#endregion
196
- export { call as a, hostedSession as c, sha256 as d, sleep as f, bundleManifest as i, probeHostedSession as l, upload as m, SESSION_TIMEOUT_MS as n, connectHost as o, unknownSession as p, attach as r, heldNoLonger as s, INSTALL_TIMEOUT_MS as t, settle as u };
202
+ export { bundleManifest as a, heldNoLonger as c, requireHostedAppMode as d, settle as f, upload as g, unknownSession as h, attach as i, hostedSession as l, sleep as m, PREPARE_TIMEOUT_MS as n, call as o, sha256 as p, SESSION_TIMEOUT_MS as r, connectHost as s, INSTALL_TIMEOUT_MS as t, probeHostedSession as u };
@@ -1,7 +1,7 @@
1
- import { n as prepareHostedNative, r as stopHostedNative, t as placeHostedNative } from "./hosted-native-DeeOG8xZ.mjs";
1
+ import { n as prepareHostedNative, r as stopHostedNative, t as placeHostedNative } from "./hosted-native-BdAQi21M.mjs";
2
2
  //#region src/device-host/hosted-ios.ts
3
- async function prepareHostedIos(machine, selectors, recorded) {
4
- return await prepareHostedNative(machine, selectors, recorded, "ios");
3
+ async function prepareHostedIos(machine, selectors, recorded, mode) {
4
+ return await prepareHostedNative(machine, selectors, recorded, "ios", false, mode);
5
5
  }
6
6
  async function placeHostedIos(target, options) {
7
7
  return await placeHostedNative(target, {
@@ -1,11 +1,11 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { l as phaseLine } from "./command-output-CBtzyIgF.mjs";
3
- import { L as deviceSlotFileKey, W as validateDeviceSlot } from "./config-CgYMahz7.mjs";
4
- import { v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-C59dqG-Z.mjs";
5
- import { t as macosDir } from "./state-xnqpx3AD.mjs";
6
- import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
7
- import { S as parseMachine$1 } from "./client-DzhapoMB.mjs";
8
- import { a as call } from "./hosted-client-C-rMtppF.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { L as deviceSlotFileKey, W as validateDeviceSlot } from "./config-D0LhTY3S.mjs";
3
+ import { w as workspaceLogsDir$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
4
+ import { l as phaseLine } from "./command-output-BjPN99ZB.mjs";
5
+ import { o as parseMachine$1 } from "./tailnet-CoJUb2tB.mjs";
6
+ import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
7
+ import { n as macosDir } from "./state-Boo0IMJq.mjs";
8
+ import { o as call } from "./hosted-client-Io01s5By.mjs";
9
9
  import { mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { dirname, join } from "node:path";
11
11
  import { isJsonObject, parseHostedAgentGrant, parseHostedLogsCursor } from "@stim-cli/core/state";
@@ -1,7 +1,7 @@
1
- import { l as phaseLine } from "./command-output-CBtzyIgF.mjs";
2
- import { t as macosDir } from "./state-xnqpx3AD.mjs";
3
- import { a as call, c as hostedSession, d as sha256, f as sleep, i as bundleManifest, m as upload, n as SESSION_TIMEOUT_MS, o as connectHost, p as unknownSession, r as attach, s as heldNoLonger, t as INSTALL_TIMEOUT_MS, u as settle } from "./hosted-client-C-rMtppF.mjs";
4
- import { i as agentAccess, r as closeAgentConnection, t as pullHostedMacosLogs } from "./hosted-logs-DN8Iz4mJ.mjs";
1
+ import { l as phaseLine } from "./command-output-BjPN99ZB.mjs";
2
+ import { n as macosDir } from "./state-Boo0IMJq.mjs";
3
+ import { a as bundleManifest, c as heldNoLonger, f as settle, g as upload, h as unknownSession, i as attach, l as hostedSession, m as sleep, n as PREPARE_TIMEOUT_MS, o as call, p as sha256, r as SESSION_TIMEOUT_MS, s as connectHost, t as INSTALL_TIMEOUT_MS } from "./hosted-client-Io01s5By.mjs";
4
+ import { i as agentAccess, r as closeAgentConnection, t as pullHostedMacosLogs } from "./hosted-logs-DP-ABU_M.mjs";
5
5
  import { rmSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
  import { hostedMacosBundleId, parseHostedMacosDevice, validHostedAppArguments } from "@stim-cli/core/state";
@@ -18,7 +18,8 @@ async function placeHostedMacos(host, { root, bundle, bundleId, handoff, argumen
18
18
  let session = null;
19
19
  if (recorded) {
20
20
  try {
21
- session = await settle(host, await attach(host, recorded.session), ["preparing", "stopping"], SESSION_TIMEOUT_MS);
21
+ session = await settle(host, await attach(host, recorded.session), ["preparing"], PREPARE_TIMEOUT_MS);
22
+ session = await settle(host, session, ["stopping"], SESSION_TIMEOUT_MS);
22
23
  } catch (error) {
23
24
  if (!heldNoLonger(error)) throw error;
24
25
  }
@@ -49,7 +50,7 @@ async function placeHostedMacos(host, { root, bundle, bundleId, handoff, argumen
49
50
  }
50
51
  };
51
52
  reserved(placement);
52
- session = await settle(host, session, ["preparing"], SESSION_TIMEOUT_MS);
53
+ session = await settle(host, session, ["preparing"], PREPARE_TIMEOUT_MS);
53
54
  if (session.state === "unknown") throw unknownSession(host, session);
54
55
  if (session.state !== "ready") throw new Error(`The hosted session ${session.id} on ${host.machine} is ${session.state}.`);
55
56
  const device = parseHostedMacosDevice(session.device);
@@ -1,11 +1,11 @@
1
- import { r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-C59dqG-Z.mjs";
2
- import { a as call, c as hostedSession, d as sha256, f as sleep, i as bundleManifest, m as upload, n as SESSION_TIMEOUT_MS, o as connectHost, p as unknownSession, r as attach, s as heldNoLonger, t as INSTALL_TIMEOUT_MS, u as settle } from "./hosted-client-C-rMtppF.mjs";
3
- import { i as agentAccess, n as pullHostedNativeLogs, r as closeAgentConnection } from "./hosted-logs-DN8Iz4mJ.mjs";
4
- import { a as requireHostedMetro, i as requestHostedMetro, n as closeHostedMetro } from "./metro-gateway-CEUw9RMH.mjs";
5
- import { s as writeHostedNative } from "./ios-state-B2pES6Vs.mjs";
1
+ import { r as readWorkspaceState$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
2
+ import { a as bundleManifest, c as heldNoLonger, d as requireHostedAppMode, f as settle, g as upload, h as unknownSession, i as attach, l as hostedSession, m as sleep, n as PREPARE_TIMEOUT_MS, o as call, p as sha256, r as SESSION_TIMEOUT_MS, s as connectHost, t as INSTALL_TIMEOUT_MS } from "./hosted-client-Io01s5By.mjs";
3
+ import { i as agentAccess, n as pullHostedNativeLogs, r as closeAgentConnection } from "./hosted-logs-DP-ABU_M.mjs";
4
+ import { a as requireHostedMetro, i as requestHostedMetro, n as closeHostedMetro } from "./metro-gateway-BBJldOdi.mjs";
5
+ import { s as writeHostedNative } from "./ios-state-CjrL2qv-.mjs";
6
6
  import { readFileSync, rmSync } from "node:fs";
7
7
  import { join } from "node:path";
8
- import { hostedNativeRecords, isJsonObject, parseHostedAndroidDevice, parseHostedChoice, parseHostedDevice, parseHostedNativeOffer, parseHostedNativePlacement, unreadableHostedNative } from "@stim-cli/core/state";
8
+ import { hostedNativeRecords, isJsonObject, parseHostedAndroidDevice, parseHostedChoice, parseHostedDevice, parseHostedNativeOffer, parseHostedNativePlacement, requireAutomaticMachine, unreadableHostedNative } from "@stim-cli/core/state";
9
9
  import { randomUUID } from "node:crypto";
10
10
  //#region src/device-host/hosted-native.ts
11
11
  function hostingRefusal(machine, error) {
@@ -16,14 +16,16 @@ function hostingRefusal(machine, error) {
16
16
  }
17
17
  const androidAgentRemoteConfig = (root, slot) => join(workspaceDir(root), "hosted-android", slot, "agent-device-remote.json");
18
18
  const iosAgentRemoteConfig = (root, slot) => join(workspaceDir(root), "hosted-ios", slot, "agent-device-remote.json");
19
- async function prepareHostedNative(machine, selectors, recorded, platform = "ios", resumeOnly = false) {
19
+ async function prepareHostedNative(machine, selectors, recorded, platform = "ios", resumeOnly = false, mode) {
20
20
  let host;
21
21
  try {
22
22
  host = await connectHost(machine, void 0, true);
23
+ requireHostedAppMode(host, platform, mode);
23
24
  if (recorded) {
24
25
  let session = null;
25
26
  try {
26
- session = await settle(host, await attach(host, recorded.session, void 0, platform), ["preparing", "stopping"], SESSION_TIMEOUT_MS, platform);
27
+ session = await settle(host, await attach(host, recorded.session, void 0, platform), ["preparing"], PREPARE_TIMEOUT_MS, platform);
28
+ session = await settle(host, session, ["stopping"], SESSION_TIMEOUT_MS, platform);
27
29
  } catch (error) {
28
30
  if (!heldNoLonger(error)) throw error;
29
31
  }
@@ -47,7 +49,7 @@ async function prepareHostedNative(machine, selectors, recorded, platform = "ios
47
49
  const offer = await call(host, "device-host.offer", {
48
50
  platform,
49
51
  ...selectors
50
- }, 3e3);
52
+ }, 45e3);
51
53
  const parsedOffer = parseHostedNativeOffer(offer);
52
54
  const choice = platform === "ios" ? offer.platform === "ios" ? parseHostedChoice(offer.choice) : null : parsedOffer?.platform === "android" ? parsedOffer.choice : null;
53
55
  if (typeof offer.declined === "string") throw new Error(offer.declined);
@@ -68,18 +70,21 @@ async function prepareHostedNative(machine, selectors, recorded, platform = "ios
68
70
  }
69
71
  async function reserveHostedNative(host, target, params, platform) {
70
72
  try {
73
+ if (target.selection?.selected === "auto") requireAutomaticMachine("device", host.machine);
71
74
  return hostedSession(host, await call(host, "device-host.reserve", params), platform);
72
75
  } catch (error) {
73
76
  if (target.selection?.selected !== "auto") throw error;
74
77
  throw Object.assign(/* @__PURE__ */ new Error(`${error instanceof Error ? error.message : String(error)} Retry stim ${platform} --remote auto; the build already targets ${host.machine}'s architecture.`), { remedy: `Retry stim ${platform} --remote auto.` });
75
78
  }
76
79
  }
77
- async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId, selectors, release, devClientScheme, reserved, note, metro = requestHostedMetro, metroPort, platform = "ios" }) {
80
+ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId, selectors, release, mode = release ? "release" : "development", devClientScheme, reserved, note, enterPhase = () => {}, metro = requestHostedMetro, metroPort, platform = "ios" }) {
78
81
  let host = target.host;
79
82
  try {
80
- if (!release && metro === requestHostedMetro) requireHostedMetro(root);
83
+ if (mode === "development" && metro === requestHostedMetro) requireHostedMetro(root);
84
+ enterPhase("device");
81
85
  host = await connectHost(host.machine, void 0, true);
82
86
  target.host = host;
87
+ requireHostedAppMode(host, platform, mode);
83
88
  let session = (target.session ? await attach(host, target.session.id, void 0, platform) : null) ?? await reserveHostedNative(host, target, {
84
89
  platform,
85
90
  workspace: root,
@@ -104,7 +109,7 @@ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId
104
109
  }
105
110
  };
106
111
  reserved(placement);
107
- session = await settle(host, session, ["preparing"], SESSION_TIMEOUT_MS, platform);
112
+ session = await settle(host, session, ["preparing"], PREPARE_TIMEOUT_MS, platform);
108
113
  if (session.state !== "ready") throw unknownSession(host, session);
109
114
  const device = platform === "ios" ? parseHostedDevice(session.device) : parseHostedAndroidDevice(session.device);
110
115
  if (!device || device.architecture !== target.choice.architecture || "avdName" in device && "systemImage" in target.choice && (device.systemImage !== target.choice.systemImage || device.deviceProfile !== target.choice.deviceProfile)) throw new Error(platform === "ios" ? "The reserved simulator does not match the offered architecture." : "The reserved emulator does not match the offered architecture or selectors.");
@@ -113,7 +118,7 @@ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId
113
118
  device
114
119
  };
115
120
  reserved(placement);
116
- if (!release) {
121
+ if (mode === "development") {
117
122
  const gateway = await metro(root, session.id, host.credential);
118
123
  await call(host, "device-host.metro.open", {
119
124
  session: session.id,
@@ -146,13 +151,14 @@ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId
146
151
  const offer = {
147
152
  ...ids,
148
153
  bundleId,
149
- mode: release ? "release" : "development",
150
- ...!release && devClientScheme ? { devClientScheme } : {},
154
+ mode,
155
+ ...mode === "development" && devClientScheme ? { devClientScheme } : {},
151
156
  manifest: {
152
157
  sha256: sha256(manifest),
153
158
  size: manifest.length
154
159
  }
155
160
  };
161
+ enterPhase("install");
156
162
  note(`Delivering ${files.length} files to ${host.machine} (${"runtime" in device ? device.runtime : device.systemImage}, ${device.architecture})`);
157
163
  await upload(host, ids, (await call(host, "device-host.app.offer", offer)).missing, content);
158
164
  let missing = (await call(host, "device-host.app.offer", offer)).missing;
@@ -181,6 +187,7 @@ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId
181
187
  }
182
188
  }
183
189
  await upload(host, ids, missing, content);
190
+ enterPhase("launch");
184
191
  note(`Launching on ${host.machine}`);
185
192
  let delivery = await call(host, "device-host.app.launch", ids);
186
193
  const deadline = Date.now() + INSTALL_TIMEOUT_MS;
@@ -197,7 +204,7 @@ async function placeHostedNative(target, { root, slot, bundle, handoff, bundleId
197
204
  };
198
205
  return {
199
206
  placement,
200
- launched: release && delivery.launched === true ? true : "unverified"
207
+ launched: mode !== "development" && delivery.launched === true ? true : "unverified"
201
208
  };
202
209
  } catch (error) {
203
210
  throw hostingRefusal(host.machine, error);
@@ -1,10 +1,10 @@
1
- import { o as formatLongDuration } from "./command-output-CBtzyIgF.mjs";
2
- import { R as deviceSlotKey, _ as loadConfig$1 } from "./config-CgYMahz7.mjs";
3
- import { a as updateWorkspaceState, r as readWorkspaceState$1 } from "./workspace-state-C59dqG-Z.mjs";
4
- import { E as workspaceBuildInProgress, S as collectOwnedDeviceActivity } from "./budget-DIhL2BKx.mjs";
5
- import { E as teardownOwnedAvd, I as canonicalPath, O as teardownOwnedIosSim } from "./workspaces-xXItD8Dj.mjs";
6
- import { m as workspaceDeviceLastUseAt } from "./activity-BxnkDZDi.mjs";
7
- import { d as listAllIosSims } from "./ios-B3SbOWdw.mjs";
1
+ import { R as deviceSlotKey, _ as loadConfig$1 } from "./config-D0LhTY3S.mjs";
2
+ import { a as updateWorkspaceState, r as readWorkspaceState$1 } from "./workspace-state-CSIFuuDa.mjs";
3
+ import { o as formatLongDuration } from "./command-output-BjPN99ZB.mjs";
4
+ import { T as canonicalPath, b as teardownOwnedIosSim, v as teardownOwnedAvd } from "./workspaces-D2xSHBDY.mjs";
5
+ import { f as collectOwnedDeviceActivity, g as workspaceBuildInProgress } from "./budget-BONq9vXY.mjs";
6
+ import { m as workspaceDeviceLastUseAt } from "./activity-BrGh9EAI.mjs";
7
+ import { d as listAllIosSims } from "./ios-CXLIUxXJ.mjs";
8
8
  import { DEVICE_IDLE_SHUTDOWN_KEY, DEVICE_RECLAIM_REASON, readDeviceIdleShutdowns } from "@stim-cli/core/state";
9
9
  //#region src/devices/idle-shutdown.ts
10
10
  const SIM_LIST_TIMEOUT_MS = 1e4;
@@ -0,0 +1,9 @@
1
+ import { h as shortUdid, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-BjPN99ZB.mjs";
2
+ import { D as schemesFromInfoPlist, T as pickDevClientScheme } from "./app-install-0LgaQRT7.mjs";
3
+ import { n as ensureWorkspaceStorageSafely } from "./native-runtime-BRmWL7ru.mjs";
4
+ import { t as devClientScheme } from "./dev-client-ClATaJoH.mjs";
5
+ import { f as podAction, h as resolveDeviceType, i as deviceLabel, m as resolveConfiguration, n as buildLogFile, s as iosConfigurationSetting, t as appNameFromPath, u as isReleaseConfiguration, v as resolveRuntime } from "./support-DCco5fut.mjs";
6
+ import { a as lastBuildRecord, i as iosFacts, n as cacheDescription, s as writeLastBuild } from "./ios-project-B9drt_aY.mjs";
7
+ import { n as registerIos, r as runIosOperation, t as iosCommand } from "./ios-CZuv6gRv.mjs";
8
+ import { a as collectorEntry, o as replaceCollector } from "./launch-YrbqaIFj.mjs";
9
+ export { appNameFromPath, buildLogFile, cacheDescription, collectorEntry, iosCommand as default, devClientScheme, deviceLabel, ensureWorkspaceStorageSafely, formatDuration, iosConfigurationSetting, iosFacts, isReleaseConfiguration, lastBuildRecord, phaseLine, pickDevClientScheme, podAction, registerIos, replaceCollector, resolveConfiguration, resolveDeviceType, resolveRuntime, runIosOperation, schemesFromInfoPlist, shortHash, shortUdid, writeLastBuild };
@@ -1,14 +1,14 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { _ as loadConfig$1, j as formatBytes } from "./config-D0LhTY3S.mjs";
2
3
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
3
- import { _ as loadConfig$1 } from "./config-CgYMahz7.mjs";
4
- import { r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-DKbeWsiK.mjs";
5
- import { at as isStimOwnedSim } from "./android-DC3ZLuw0.mjs";
6
- import { n as settingDefault, t as STIM_DESKTOP_OPEN_OPTIONS } from "./stim-desktop-Behws_fi.mjs";
4
+ import { n as settingDefault, t as STIM_DESKTOP_OPEN_OPTIONS } from "./stim-desktop-8GQX2OV8.mjs";
5
+ import { it as isStimOwnedSim } from "./android-BsYNR81W.mjs";
6
+ import { r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-HU_DAb_Q.mjs";
7
7
  import { closeSync, existsSync, lstatSync, mkdtempSync, openSync, readSync, readdirSync, rmSync, writeFileSync } from "node:fs";
8
8
  import { dirname, isAbsolute, join, resolve } from "node:path";
9
9
  import { IOS_SIMULATOR_APPS, settingDefinition } from "@stim-cli/core/state";
10
- import { tmpdir } from "node:os";
11
10
  import { createHash } from "node:crypto";
11
+ import { tmpdir, totalmem } from "node:os";
12
12
  //#region src/engine/installed-artifact.ts
13
13
  const READ_CHUNK_BYTES = 1048576;
14
14
  const DEVICE_PATH_TIMEOUT_MS = 3e4;
@@ -139,6 +139,136 @@ function deviceHoldsBundle({ udid, bundleId, appPath }, { exec = null } = {}) {
139
139
  return artifactsMatch(hashBundle(appPath), installed);
140
140
  }
141
141
  //#endregion
142
+ //#region src/memory-culprits.ts
143
+ const GIB = 1024 ** 3;
144
+ const UNITS = {
145
+ B: 1,
146
+ K: 1024,
147
+ M: 1024 ** 2,
148
+ G: GIB,
149
+ T: 1024 * GIB
150
+ };
151
+ const GENERAL_FLOOR_BYTES = 8 * GIB;
152
+ const GENERAL_SHARE_OF_RAM = .25;
153
+ const TOP_ROWS = 20;
154
+ const GRADLE_DAEMON = /\borg\.gradle\.launcher\.daemon\.bootstrap\.GradleDaemon\b/;
155
+ const KOTLIN_DAEMON = /\bKotlinCompileDaemon\b/;
156
+ const GRADLE_NOTE = "Stim stops only idle daemons; the next build starts a new one.";
157
+ const RESTARTABLE = [
158
+ {
159
+ name: "fseventsd",
160
+ matches: ({ name }) => name === "fseventsd",
161
+ bytes: 2 * GIB,
162
+ command: "sudo killall fseventsd",
163
+ note: "launchd restarts it at once, and file watchers rescan their folders once."
164
+ },
165
+ {
166
+ name: "Watchman",
167
+ matches: ({ name }) => name === "watchman",
168
+ bytes: 2 * GIB,
169
+ command: "stim gc --delete --cache watchman",
170
+ note: "Stim stops the daemon only when no workspace uses it; the next Metro starts a fresh one."
171
+ },
172
+ {
173
+ name: "Gradle daemon",
174
+ matches: ({ name }, commandLine) => name === "java" && GRADLE_DAEMON.test(commandLine ?? ""),
175
+ command: "stim gc --delete --cache gradle-daemons",
176
+ note: GRADLE_NOTE
177
+ },
178
+ {
179
+ name: "Kotlin daemon",
180
+ matches: ({ name }, commandLine) => name === "java" && KOTLIN_DAEMON.test(commandLine ?? ""),
181
+ command: "stim gc --delete --cache gradle-daemons",
182
+ note: GRADLE_NOTE
183
+ }
184
+ ];
185
+ /** Parses `top -l 1 -stats pid,mem,command` output: the rows after its `PID MEM COMMAND` header. */
186
+ function parseTopMemory(output) {
187
+ const rows = [];
188
+ let header = false;
189
+ for (const line of output.split("\n")) {
190
+ if (!header) {
191
+ header = /^\s*PID\s+MEM\s+COMMAND\b/.test(line);
192
+ continue;
193
+ }
194
+ const match = /^\s*(\d+)\s+(\d+(?:\.\d+)?)([BKMGT])[+-]?\s+(\S.*?)\s*$/.exec(line);
195
+ if (match) rows.push({
196
+ pid: Number(match[1]),
197
+ bytes: Math.round(Number(match[2]) * UNITS[match[3]]),
198
+ name: match[4]
199
+ });
200
+ }
201
+ return rows;
202
+ }
203
+ function findMemoryCulprits(processes, totalBytes, commandLines = /* @__PURE__ */ new Map()) {
204
+ const general = Math.max(GENERAL_FLOOR_BYTES, totalBytes * GENERAL_SHARE_OF_RAM);
205
+ const culprits = [];
206
+ for (const row of processes) {
207
+ const known = RESTARTABLE.find((entry) => entry.matches(row, commandLines.get(row.pid)));
208
+ if (row.bytes < Math.min(general, known?.bytes ?? general)) continue;
209
+ culprits.push({
210
+ pid: row.pid,
211
+ name: known?.name ?? row.name,
212
+ bytes: row.bytes,
213
+ command: known?.command ?? null,
214
+ note: known?.note ?? null
215
+ });
216
+ }
217
+ return culprits.toSorted((a, b) => b.bytes - a.bytes);
218
+ }
219
+ function memoryCulpritAdvice(culprits) {
220
+ if (!culprits?.length) return null;
221
+ return culprits.map((culprit) => {
222
+ const uses = `${culprit.name} (pid ${culprit.pid}) uses ${formatBytes(culprit.bytes)} of memory`;
223
+ return culprit.command ? `${uses}; run \`${culprit.command}\` to free it: ${culprit.note}` : `${uses}; Stim knows no safe restart for it, so ask before quitting it.`;
224
+ }).join(" ");
225
+ }
226
+ /**
227
+ * The abnormal processes by footprint, from the setuid `top`: unlike `proc_pid_rusage` without root, it reads
228
+ * root-owned daemons such as fseventsd, and unlike `ps` RSS it counts compressed and swapped memory. Null off macOS
229
+ * or when `top` fails.
230
+ */
231
+ function readMemoryCulprits(exec = getExecutor(), platform = process.platform, totalBytes = totalmem()) {
232
+ if (platform !== "darwin") return null;
233
+ const output = exec.runFileQuiet("/usr/bin/top", [
234
+ "-l",
235
+ "1",
236
+ "-o",
237
+ "mem",
238
+ "-n",
239
+ String(TOP_ROWS),
240
+ "-stats",
241
+ "pid,mem,command"
242
+ ], { timeoutMs: 1e4 });
243
+ if (output === null) return null;
244
+ const processes = parseTopMemory(output);
245
+ const java = processes.filter((entry) => entry.name === "java").map((entry) => entry.pid);
246
+ const commandLines = /* @__PURE__ */ new Map();
247
+ if (java.length) {
248
+ const listed = exec.runFileQuiet("/bin/ps", [
249
+ "-ww",
250
+ "-o",
251
+ "pid=,command=",
252
+ "-p",
253
+ java.join(",")
254
+ ], { timeoutMs: 5e3 });
255
+ for (const line of listed?.split("\n") ?? []) {
256
+ const match = /^\s*(\d+)\s+(.*)$/.exec(line);
257
+ if (match) commandLines.set(Number(match[1]), match[2]);
258
+ }
259
+ }
260
+ return findMemoryCulprits(processes, totalBytes, commandLines);
261
+ }
262
+ function memoryCulpritFindings(culprits) {
263
+ return (culprits ?? []).filter((culprit) => culprit.name !== "Watchman").map((culprit) => ({
264
+ code: "memory-culprit",
265
+ level: "cost",
266
+ title: `${culprit.name} uses ${formatBytes(culprit.bytes)} of memory`,
267
+ detail: memoryCulpritAdvice([culprit]),
268
+ fix: culprit.command ? `Run \`${culprit.command}\`. ${culprit.note}` : "Stim knows no safe restart for this process. Ask before quitting it."
269
+ }));
270
+ }
271
+ //#endregion
142
272
  //#region src/host-memory.ts
143
273
  function readHostMemoryPressure(exec = getExecutor(), platform = process.platform) {
144
274
  if (platform !== "darwin") return null;
@@ -153,9 +283,13 @@ function readHostMemoryPressure(exec = getExecutor(), platform = process.platfor
153
283
  return null;
154
284
  }
155
285
  }
156
- function hostMemoryPressureAdvice(pressure) {
286
+ function memoryCulpritsUnder(pressure, exec = getExecutor()) {
287
+ return pressure === "warning" || pressure === "critical" ? readMemoryCulprits(exec) : null;
288
+ }
289
+ function hostMemoryPressureAdvice(pressure, culprits = null) {
157
290
  if (pressure === null || pressure === "normal") return null;
158
- return `macOS reports ${pressure} host memory pressure. Simulator processes can stall even when the device is Booted. Free memory before retrying: use \`stim stop\` only in workspaces you own, and ask before closing other apps or devices. For parallel iOS work, consider a reviewed SimSlim profile (\`stim guide lifecycle simslim\`). This observation does not establish an OOM crash.`;
291
+ const named = memoryCulpritAdvice(culprits);
292
+ return `macOS reports ${pressure} host memory pressure.${named ? ` ${named}` : ""} Simulator processes can stall even when the device is Booted. Free memory before retrying: use \`stim stop\` only in workspaces you own, and ask before closing other apps or devices. For parallel iOS work, consider a reviewed SimSlim profile (\`stim guide lifecycle simslim\`). This observation does not establish an OOM crash.`;
159
293
  }
160
294
  //#endregion
161
295
  //#region src/devices/ios-simulator-viewer.ts
@@ -291,7 +425,8 @@ const BOOTSTATUS_ATTEMPT_MS = 24e4;
291
425
  const BOOTSTATUS_ATTEMPT_FLOOR_MS = 1e3;
292
426
  const BOOT_STATE_LIST_TIMEOUT_MS = 3e4;
293
427
  function iosSimulatorFailureAdvice(exec = getExecutor()) {
294
- return hostMemoryPressureAdvice(readHostMemoryPressure(exec)) ?? "The simulator may be unresponsive. Check Activity Monitor for memory pressure and free host memory before retrying.";
428
+ const pressure = readHostMemoryPressure(exec);
429
+ return hostMemoryPressureAdvice(pressure, memoryCulpritsUnder(pressure, exec)) ?? "The simulator may be unresponsive. Check Activity Monitor for memory pressure and free host memory before retrying.";
295
430
  }
296
431
  function bootstatusTimeout(command) {
297
432
  const e = /* @__PURE__ */ new Error(`${command} timed out`);
@@ -418,15 +553,19 @@ async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = B
418
553
  if (deadline - Date.now() <= 0) throw new Error(`Simulator ${udid} did not finish booting within ${Math.round(timeoutMs / 1e3)}s.`);
419
554
  }
420
555
  } catch (error) {
421
- sample();
422
- throw new Error(`${error?.message || error} Last boot output: ${phase}. Highest observed memory pressure: ${worst ?? "unknown"}; unavailable samples: ${unknown}.${coverage()} ${recovery} These observations do not establish an OOM crash.`, { cause: error });
556
+ const named = memoryCulpritAdvice(memoryCulpritsUnder(sample(), exec));
557
+ throw new Error(`${error?.message || error} Last boot output: ${phase}. Highest observed memory pressure: ${worst ?? "unknown"}; unavailable samples: ${unknown}.${coverage()}${named ? ` ${named}` : ""} ${recovery} These observations do not establish an OOM crash.`, { cause: error });
423
558
  } finally {
424
559
  clearInterval(monitor);
425
560
  }
426
561
  if (openViewer) viewer.open(udid);
427
562
  }
428
563
  function shutdownIosSim(udid) {
429
- getExecutor().runQuiet(`xcrun simctl shutdown ${udid}`, SIMCTL_OPTIONS);
564
+ getExecutor().runFileQuiet("xcrun", [
565
+ "simctl",
566
+ "shutdown",
567
+ udid
568
+ ], SIMCTL_OPTIONS);
430
569
  }
431
570
  function listIosDeviceTypes() {
432
571
  const out = getExecutor().runFile("xcrun", [
@@ -531,7 +670,13 @@ function createOwnedIosSim(label, { deviceType, runtime, suffix = "" } = {}, cho
531
670
  model: choice.deviceType,
532
671
  runtime: choice.runtime
533
672
  }, suffix);
534
- const udid = getExecutor().run(`xcrun simctl create "${name}" "${choice.deviceTypeId}" "${choice.runtimeId}"`, {
673
+ const udid = getExecutor().runFile("xcrun", [
674
+ "simctl",
675
+ "create",
676
+ name,
677
+ choice.deviceTypeId,
678
+ choice.runtimeId
679
+ ], {
535
680
  timeoutMs: SIMCTL_CREATE_TIMEOUT_MS,
536
681
  killSignal: "SIGKILL"
537
682
  }).trim();
@@ -690,7 +835,11 @@ function deleteIosSim(udid) {
690
835
  const result = resolveOwnedIosSim(udid);
691
836
  if (result.missing) return;
692
837
  if (result.notOwned) throw new Error(`Refusing to delete simulator "${result.notOwned}" (${udid}): not a Stim-owned sim; Stim has no record of creating it.`);
693
- getExecutor().run(`xcrun simctl delete ${udid}`, SIMCTL_OPTIONS);
838
+ getExecutor().runFile("xcrun", [
839
+ "simctl",
840
+ "delete",
841
+ udid
842
+ ], SIMCTL_OPTIONS);
694
843
  forgetCreatedDevice("ios", udid);
695
844
  }
696
845
  const PARKED_DELETE_TIMEOUT_MS = 3e4;
@@ -708,16 +857,23 @@ function deleteParkedIosSim(udid) {
708
857
  ], { timeoutMs: PARKED_DELETE_TIMEOUT_MS });
709
858
  forgetCreatedDevice("ios", udid);
710
859
  }
860
+ const LIST_RUNTIMES_ARGS = [
861
+ "simctl",
862
+ "list",
863
+ "runtimes",
864
+ "--json"
865
+ ];
866
+ const LIST_RUNTIMES_OPTIONS = {
867
+ timeoutMs: 3e4,
868
+ killSignal: "SIGKILL"
869
+ };
711
870
  function listIosRuntimes() {
712
- const out = getExecutor().runFile("xcrun", [
713
- "simctl",
714
- "list",
715
- "runtimes",
716
- "--json"
717
- ], {
718
- timeoutMs: 3e4,
719
- killSignal: "SIGKILL"
720
- });
871
+ return parseIosRuntimes(getExecutor().runFile("xcrun", LIST_RUNTIMES_ARGS, LIST_RUNTIMES_OPTIONS));
872
+ }
873
+ async function listIosRuntimesAsync() {
874
+ return parseIosRuntimes(await getExecutor().runFileAsync("xcrun", LIST_RUNTIMES_ARGS, LIST_RUNTIMES_OPTIONS));
875
+ }
876
+ function parseIosRuntimes(out) {
721
877
  return (JSON.parse(out).runtimes || []).filter((r) => r.isAvailable && r.platform === "iOS").map((r) => ({
722
878
  identifier: r.identifier,
723
879
  name: r.name,
@@ -729,4 +885,4 @@ function listIosRuntimes() {
729
885
  }));
730
886
  }
731
887
  //#endregion
732
- export { parseIosSimulatorApp as A, resetIosPrivacy as C, shutdownIosSim as D, sanitizeDeviceLabel as E, readHostMemoryPressure as M, deviceHoldsApk as N, uninstallIosApp as O, deviceHoldsBundle as P, resetIosKeychain as S, resolveOwnedIosSim as T, parkedSimName as _, createOwnedIosSim as a, pickDefaultIosCreation as b, eraseIosSim as c, listAllIosSims as d, listAllIosSimsAsync as f, ownedSimName as g, listUserApps as h, createIosSimSnapshot as i, hostMemoryPressureAdvice as j, configuredIosSimulatorViewer as k, iosRuntimeMatches as l, listIosRuntimes as m, bootIosSim as n, deleteIosSim as o, listIosDeviceTypes as p, clearIosAppData as r, deleteParkedIosSim as s, IOS_BOOT_TIMEOUT_MS as t, iosSimulatorFailureAdvice as u, parseRuntimeVersion as v, resolveIosCreation as w, renameIosSim as x, parseSimctlList as y };
888
+ export { configuredIosSimulatorViewer as A, resetIosKeychain as C, sanitizeDeviceLabel as D, resolveOwnedIosSim as E, memoryCulpritAdvice as F, memoryCulpritFindings as I, readMemoryCulprits as L, hostMemoryPressureAdvice as M, memoryCulpritsUnder as N, shutdownIosSim as O, readHostMemoryPressure as P, deviceHoldsApk as R, renameIosSim as S, resolveIosCreation as T, ownedSimName as _, createOwnedIosSim as a, parseSimctlList as b, eraseIosSim as c, listAllIosSims as d, listAllIosSimsAsync as f, listUserApps as g, listIosRuntimesAsync as h, createIosSimSnapshot as i, parseIosSimulatorApp as j, uninstallIosApp as k, iosRuntimeMatches as l, listIosRuntimes as m, bootIosSim as n, deleteIosSim as o, listIosDeviceTypes as p, clearIosAppData as r, deleteParkedIosSim as s, IOS_BOOT_TIMEOUT_MS as t, iosSimulatorFailureAdvice as u, parkedSimName as v, resetIosPrivacy as w, pickDefaultIosCreation as x, parseRuntimeVersion as y, deviceHoldsBundle as z };