stim 1.20.2 → 1.22.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 (231) hide show
  1. package/README.md +141 -8
  2. package/dist/acquire-artifact-Co2k4f7O.mjs +171 -0
  3. package/dist/act-DsuqEkiM.mjs +2801 -0
  4. package/dist/activity-CMLmzp7o.mjs +1397 -0
  5. package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-DUFaTMdd.mjs} +23 -67
  6. package/dist/{android-DCKZrNvV.mjs → android-ByRMUoiJ.mjs} +157 -93
  7. package/dist/{android-Mz_Inn3w.mjs → android-C7sVmyI9.mjs} +299 -116
  8. package/dist/{android-Dlzxshgp.mjs → android-DGkNqa_c.mjs} +5 -5
  9. package/dist/{android-HqP1_vB_.mjs → android-DR5lZ2Az.mjs} +2 -2
  10. package/dist/android-cas-compiler.mjs +2 -2
  11. package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-ngferVq2.mjs} +7 -6
  12. package/dist/android-project-BCAAmMwz.mjs +12 -0
  13. package/dist/android-project-DVWyCbWU.d.mts +391 -0
  14. package/dist/api.d.mts +810 -64
  15. package/dist/api.mjs +782 -1
  16. package/dist/{artifact-HSwkIWEQ.mjs → artifact-8EY8SAPw.mjs} +240 -213
  17. package/dist/{artifact-D3czlUvT.mjs → artifact-DJPy518Y.mjs} +203 -164
  18. package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
  19. package/dist/{browser-web-CA-F1GQo.mjs → browser-web-Bcv99PBM.mjs} +194 -64
  20. package/dist/budget-Cvwn54qV.mjs +9285 -0
  21. package/dist/{build-DYDbfkk5.mjs → build-CabC3G23.mjs} +153 -98
  22. package/dist/build-cache-Dv7RN200.mjs +602 -0
  23. package/dist/build-plan-DUC8Ka9y.mjs +248 -0
  24. package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DSeQjt-Q.mjs} +2 -2
  25. package/dist/cache-manifest.mjs +1 -1
  26. package/dist/{ccache-zdKiYQ3E.mjs → ccache-Btwc36-I.mjs} +10 -9
  27. package/dist/{cdp-Dq_ypAlJ.mjs → cdp-3fwICjzi.mjs} +18 -5
  28. package/dist/{chrome-BnzZMqsR.mjs → chrome-Bbw689-6.mjs} +7 -4
  29. package/dist/{cli-CLP3diBm.mjs → cli-CHZa9Lvk.mjs} +20 -20
  30. package/dist/cli.mjs +1 -1
  31. package/dist/client-OyRoEuSr.mjs +1577 -0
  32. package/dist/collector-run.d.mts +4 -40
  33. package/dist/collector-run.mjs +9 -8
  34. package/dist/{command-output-BTy8hZ0F.mjs → command-output-gwpm28fu.mjs} +1 -1
  35. package/dist/config-DlrsduwG.mjs +955 -0
  36. package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-x9rN6bhs.mjs} +14 -4
  37. package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-1I9KZT1Y.mjs} +20 -5
  38. package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
  39. package/dist/{dev-client-DAWVIGBu.mjs → dev-client-BSDR5h3F.mjs} +2 -2
  40. package/dist/{device-BECOiufl.mjs → device-B-L3Fbxy.mjs} +91 -34
  41. package/dist/device-DklWZLqb.mjs +1068 -0
  42. package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-DK5_EwRS.mjs} +42 -13
  43. package/dist/device-host-worker.mjs +76 -79
  44. package/dist/{device-ios-COSi6oS1.mjs → device-ios-DoB6KFCO.mjs} +77 -51
  45. package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-xJPQ_QQG.mjs} +14 -26
  46. package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-BMkdsefq.mjs} +5 -5
  47. package/dist/{doctor-kfMBnUw6.mjs → doctor-Bo7BXLux.mjs} +271 -320
  48. package/dist/{doctor-CB8oZKCk.mjs → doctor-D5_EzwfA.mjs} +186 -91
  49. package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
  50. package/dist/doctor-fingerprint.mjs +19 -0
  51. package/dist/doctor-thjWAV0z.mjs +2 -0
  52. package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-N2wDotwQ.mjs} +40 -21
  53. package/dist/{eas-build-JyfqyHfC.mjs → eas-build-CwknaQYj.mjs} +53 -20
  54. package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-CSgAulr5.mjs} +41 -214
  55. package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-DlY_serQ.mjs} +230 -11
  56. package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-DBWO2rxE.mjs} +172 -82
  57. package/dist/exec-DEoAhcze.mjs +858 -0
  58. package/dist/exec-DnYc4HGH.d.mts +78 -0
  59. package/dist/{gc-qWOMdnER.mjs → gc-CXxN-4SE.mjs} +1091 -1029
  60. package/dist/gc-DnNDQyaP.mjs +3 -0
  61. package/dist/{guide-G9cAbVAc.mjs → guide-Br0LEfKy.mjs} +1165 -297
  62. package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-B-9f-jkd.mjs} +10 -8
  63. package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DZAPrcro.mjs} +34 -19
  64. package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CsCS21hn.mjs} +1 -1
  65. package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-FIRx9X2f.mjs} +77 -43
  66. package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-_awYSpfv.mjs} +35 -22
  67. package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-BdzE668-.mjs} +49 -27
  68. package/dist/idle-C4cZ757K.d.mts +24 -0
  69. package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DDg3SdvY.mjs} +11 -10
  70. package/dist/ios-CDvlmUs7.d.mts +24 -0
  71. package/dist/{ios-BwVCF7oA.mjs → ios-Ds1clbIt.mjs} +8 -8
  72. package/dist/{ios-device-D7pi2Sca.mjs → ios-device--h_-8ENa.mjs} +51 -26
  73. package/dist/{ios-device-B5veSDDQ.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
  74. package/dist/{ios-RkW4pnQf.mjs → ios-hcBpnEGk.mjs} +200 -93
  75. package/dist/{ios-Ce7bc7br.mjs → ios-pm4nL6By.mjs} +160 -108
  76. package/dist/{ios-project-K9hY_Jab.mjs → ios-project-CZhKODF3.mjs} +13 -13
  77. package/dist/ios-signing-BtAffm0A.mjs +489 -0
  78. package/dist/{ios-state-CBLe1xYw.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
  79. package/dist/{ios-nOLJGVdy.mjs → ios-xtlRHaeB.mjs} +1 -1
  80. package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Bwhh4S7V.mjs} +30 -25
  81. package/dist/{launch-C3qJ6Agb.mjs → launch-BjxemNpK.mjs} +85 -543
  82. package/dist/{launch-F4sOqAhB.mjs → launch-CCzXlc8r.mjs} +91 -90
  83. package/dist/logs-BfwwadsZ.mjs +479 -0
  84. package/dist/logs-jTS_lHSo.mjs +248 -0
  85. package/dist/{macos-D7uDvO-z.mjs → macos-DVlSSyUg.mjs} +1 -1
  86. package/dist/macos-NfV2D7dO.mjs +694 -0
  87. package/dist/macos-run.mjs +1 -1
  88. package/dist/maintenance-run.mjs +123 -248
  89. package/dist/{metro-DnCEjCxs.mjs → metro-DiXtA3Ty.mjs} +107 -30
  90. package/dist/metro-gateway-CKZqKqx7.mjs +209 -0
  91. package/dist/{named-ports-4WopRPg-.mjs → named-ports-DkEzOfzO.mjs} +42 -90
  92. package/dist/native-android-CqgnOgsT.mjs +645 -0
  93. package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
  94. package/dist/native-gradle-inputs-Dnh84Zbd.mjs +211 -0
  95. package/dist/native-inputs-TRTTTRxt.mjs +91 -0
  96. package/dist/native-run-NwUuxbkg.mjs +276 -0
  97. package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-B7KIafpM.mjs} +11 -9
  98. package/dist/native-source-Y0yLhFyQ.mjs +133 -0
  99. package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-D_VOfFL7.mjs} +26 -18
  100. package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-BYDOHWLN.mjs} +104 -60
  101. package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
  102. package/dist/offload-worker.d.mts +59 -41
  103. package/dist/offload-worker.mjs +478 -115
  104. package/dist/operation-exec-BW0em61G.mjs +171 -0
  105. package/dist/{ownership-DCtw_2IA.mjs → ownership-C5fo5Edb.mjs} +3 -3
  106. package/dist/{page-DRHy329N.mjs → page-DBL2PiUU.mjs} +12 -5
  107. package/dist/paths-BsJMoPP2.mjs +12 -0
  108. package/dist/paths-DQtTgsBf.mjs +42 -0
  109. package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BnGgJRRZ.mjs} +5 -5
  110. package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-DIsMtN-d.mjs} +15 -11
  111. package/dist/{ports-DdSUicVo.mjs → ports-Cy1RkmuQ.mjs} +3 -3
  112. package/dist/prebuild-D4JoEAEs.mjs +484 -0
  113. package/dist/{project-_phNIJfs.mjs → project-wM_XFTvE.mjs} +65 -37
  114. package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-W1IuLXDt.mjs} +102 -20
  115. package/dist/pull-request-eODyIqZF.d.mts +124 -0
  116. package/dist/pull-requests.d.mts +2 -120
  117. package/dist/pull-requests.mjs +2 -2
  118. package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-6OZ7MSM7.mjs} +121 -72
  119. package/dist/{gradle-DSrXb6lG.mjs → react-native-build-Dvd8hC21.mjs} +292 -15
  120. package/dist/react-native-doctor-DsoSF1Y9.mjs +234 -0
  121. package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-4u1Rn-GR.mjs} +71 -39
  122. package/dist/{recordings-D0d5aQt0.mjs → recordings-CQmfzAh7.mjs} +12 -9
  123. package/dist/registration-BcRgF6Ox.mjs +51 -0
  124. package/dist/{reload-C8JhxjSh.mjs → reload-BzkYabB-.mjs} +94 -47
  125. package/dist/reload-D7AVlb8N.mjs +2 -0
  126. package/dist/{remote-BiR6aYjy.mjs → remote-DjGDmlTZ.mjs} +26 -18
  127. package/dist/result-D2Ykz_iD.mjs +435 -0
  128. package/dist/{run-BtPgpKks.mjs → run-DidHghD1.mjs} +5 -5
  129. package/dist/selection-DSMbWEX2.mjs +620 -0
  130. package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CafzuyFB.mjs} +3 -4
  131. package/dist/{server-command-CTtCkmcQ.mjs → server-command-C6QjeupS.mjs} +14 -7
  132. package/dist/{server-expo-DsguMGUF.mjs → server-expo-CrjB29pq.mjs} +54 -11
  133. package/dist/server-expo-D58c9L0M.mjs +2 -0
  134. package/dist/{settings-B717odTD.mjs → settings-C7O8A6ZI.mjs} +309 -119
  135. package/dist/settings-DpR-1Wnn.mjs +114 -0
  136. package/dist/settings-write-CzD60rOD.mjs +360 -0
  137. package/dist/settings.schema.json +176 -16
  138. package/dist/{simslim-CCr3rE-A.mjs → simslim-BNckWpXi.mjs} +14 -12
  139. package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-CbfmNgM6.mjs} +15 -20
  140. package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
  141. package/dist/stage-Bps5oius.mjs +200 -0
  142. package/dist/{start-TXeMmmO2.mjs → start-Br-oxqMD.mjs} +1 -1
  143. package/dist/start-EojN4WFz.mjs +1364 -0
  144. package/dist/{state-D1Icyjlu.mjs → state--smjFSTL.mjs} +55 -13
  145. package/dist/{state-CG_OFoaA.mjs → state-08I3hw3_.mjs} +3 -2
  146. package/dist/{stats-BoY5sEPU.mjs → stats-D3GerlFW.mjs} +7 -13
  147. package/dist/stats-report-BzaPrRm6.mjs +16 -0
  148. package/dist/{status-BTA7kKiQ.mjs → status-BRROykC8.mjs} +7 -5
  149. package/dist/status-EvrK72L2.mjs +2 -0
  150. package/dist/{status-WgFbkRzj.mjs → status-WBDajew2.mjs} +554 -452
  151. package/dist/{status-watch-C23ILtf9.mjs → status-watch-Bg_u-pwR.mjs} +222 -25
  152. package/dist/status-worker.d.mts +1 -0
  153. package/dist/status-worker.mjs +19 -0
  154. package/dist/stim-desktop-D5OGpYZM.mjs +112 -0
  155. package/dist/{stop-DR6VoDIk.mjs → stop-DTZ9uTw3.mjs} +2 -2
  156. package/dist/{stop-DPEhunlw.mjs → stop-Dky10AEJ.mjs} +33 -23
  157. package/dist/{stop-BNmBMi1F.mjs → stop-Mv6W9FAk.mjs} +137 -98
  158. package/dist/supervisor-run.d.mts +8 -17
  159. package/dist/supervisor-run.mjs +56 -28
  160. package/dist/{support-CwjbFs9H.mjs → support-CNioewsd.mjs} +14 -14
  161. package/dist/{support-DMTqj3Hm.mjs → support-yUiOjnVY.mjs} +20 -13
  162. package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
  163. package/dist/swiftpm-macos-BIak-Rxv.mjs +532 -0
  164. package/dist/toolchain-BY8X8HXx.mjs +2 -0
  165. package/dist/toolchain-DpJMHq0n.mjs +876 -0
  166. package/dist/{trigger-CigAYjeL.mjs → trigger-Cbyc41d_.mjs} +21 -6
  167. package/dist/trigger-yb_nFzPF.mjs +2 -0
  168. package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-CA3TgT3-.mjs} +263 -156
  169. package/dist/web-CZ07gd77.mjs +2 -0
  170. package/dist/{web-BDBMxDpx.mjs → web-DKx6yoFA.mjs} +20 -14
  171. package/dist/web-run.mjs +13 -12
  172. package/dist/windows-report.d.mts +1 -0
  173. package/dist/windows-report.mjs +18 -0
  174. package/dist/windows-report.ps1 +43 -0
  175. package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-U08dEzhG.mjs} +62 -58
  176. package/dist/{workspaces-C36s2jb9.mjs → workspaces-CpANmBlq.mjs} +1723 -1286
  177. package/dist/{worktree-CgvJYJ-Q.mjs → worktree-CHecZ4Oq.mjs} +1097 -547
  178. package/dist/worktree-ZqZVjD9K.mjs +2 -0
  179. package/dist/xcode-BXn9-xYx.mjs +896 -0
  180. package/package.json +7 -5
  181. package/shim/android-audio/Main.java +24 -0
  182. package/shim/android-audio/README.md +17 -0
  183. package/shim/android-audio.jar +0 -0
  184. package/shim/android-optimizations.gradle +7 -5
  185. package/dist/activity-BSV745Kz.mjs +0 -629
  186. package/dist/api-qvOzWyfO.mjs +0 -154
  187. package/dist/api-run.mjs +0 -294
  188. package/dist/app-install-BIKtMfPq.mjs +0 -896
  189. package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
  190. package/dist/budget-f7516Zk0.mjs +0 -4106
  191. package/dist/build-facts-DcLv2HSd.d.mts +0 -111
  192. package/dist/cancellation-C_22VQTH.mjs +0 -24
  193. package/dist/client-qQAaXSUs.mjs +0 -1771
  194. package/dist/config-BYDxlMY3.mjs +0 -562
  195. package/dist/device-DuiPJQSn.mjs +0 -290
  196. package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
  197. package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
  198. package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
  199. package/dist/exec-DqKo9GKJ.mjs +0 -268
  200. package/dist/git-DDfFzkMm.mjs +0 -45
  201. package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
  202. package/dist/logs-BGrEUaEs.mjs +0 -383
  203. package/dist/macos-Ch5VJmcS.mjs +0 -584
  204. package/dist/metro-gateway-CX9Xlkq2.mjs +0 -103
  205. package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
  206. package/dist/native-android-D5qc3-_v.mjs +0 -226
  207. package/dist/native-gradle-inputs-BsLRrl7u.mjs +0 -349
  208. package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
  209. package/dist/plan-C4TjdPsR.mjs +0 -260
  210. package/dist/prebuild-DYbucPXy.mjs +0 -212
  211. package/dist/preview-78a9kR_-.mjs +0 -1011
  212. package/dist/react-native-build-CtCccJtb.mjs +0 -239
  213. package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
  214. package/dist/remote-cache-OyOyVIS3.mjs +0 -526
  215. package/dist/result-CaJg5Iat.mjs +0 -186
  216. package/dist/server-expo-Bigriskl.mjs +0 -2
  217. package/dist/settings-BORNaaCO.mjs +0 -402
  218. package/dist/settings-vk3mJGSm.d.mts +0 -13
  219. package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
  220. package/dist/stage-KNTQopqv.mjs +0 -157
  221. package/dist/start-BWqzODpb.mjs +0 -1116
  222. package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
  223. package/dist/swiftpm-macos-DRNVJWlb.mjs +0 -119
  224. package/dist/tailnet-Dh-qiYzG.mjs +0 -265
  225. package/dist/toolchain-BFkAcstd.mjs +0 -2
  226. package/dist/toolchain-DxSsNssu.mjs +0 -1657
  227. package/dist/trigger-9_USgmxz.mjs +0 -2
  228. package/dist/web-Dq-i3wzJ.mjs +0 -2
  229. package/dist/worktree-DpLdCHga.mjs +0 -2
  230. package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
  231. package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
@@ -1,13 +1,17 @@
1
- import { t as getExecutor } from "./exec-DqKo9GKJ.mjs";
2
- import { d as androidToolPath } from "./android-Mz_Inn3w.mjs";
3
- import { b as parseSimctlList } from "./ios-RkW4pnQf.mjs";
4
- import { n as easMachineStateRoot } from "./eas-session-ledger-Cm0Gwq2F.mjs";
5
- import { readdirSync, watch } from "node:fs";
6
- import { join } from "node:path";
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { c as pidExists } from "./metro-DiXtA3Ty.mjs";
3
+ import { n as easMachineStateRoot } from "./eas-session-ledger-DlY_serQ.mjs";
4
+ import { d as androidToolPath } from "./android-C7sVmyI9.mjs";
5
+ import { b as parseSimctlList } from "./ios-hcBpnEGk.mjs";
6
+ import { existsSync, readdirSync, statSync, watch } from "node:fs";
7
+ import { basename, dirname, join } from "node:path";
7
8
  //#region src/status-watch.ts
8
9
  const WATCH_FALLBACK_MS = 3e4;
9
- const WATCH_LIGHT_INTERVAL_MS = 15e3;
10
- const WATCH_SIMCTL_INTERVAL_MS = 5e3;
10
+ const WATCH_LIGHT_INTERVAL_MS = 1e3;
11
+ const WATCH_TABLES_INTERVAL_MS = 5e3;
12
+ const WATCH_MACHINE_INTERVAL_MS = 15e3;
13
+ const WATCH_PROCESS_INTERVAL_MS = 2e3;
14
+ const WATCH_SIMCTL_INTERVAL_MS = 3e4;
11
15
  const ADB_RESTART_MIN_MS = 1e3;
12
16
  const ADB_RESTART_MAX_MS = 6e4;
13
17
  const SIMCTL_TIMEOUT_MS = 1e4;
@@ -86,6 +90,16 @@ function statusChange(dir, name) {
86
90
  default: return "full";
87
91
  }
88
92
  }
93
+ /**
94
+ * Whether a change to `name`, relative to a repository's git common directory, can change a worktree's git summary:
95
+ * its HEAD, index or a ref, in the main worktree or a linked one. Objects, logs and lock files cannot on their own.
96
+ */
97
+ function gitChange(name) {
98
+ if (name === null) return true;
99
+ const path = name.replaceAll("\\", "/");
100
+ if (path.endsWith(".lock")) return false;
101
+ return /^(HEAD|index|packed-refs|FETCH_HEAD)$/.test(path) || path.startsWith("refs/") || /^worktrees\/[^/]+(\/(HEAD|index))?$/.test(path) || path === "worktrees";
102
+ }
89
103
  /** A stable summary of every simulator's state, or null when the listing is unreadable. */
90
104
  function simulatorSignature(simctlJson) {
91
105
  try {
@@ -94,12 +108,18 @@ function simulatorSignature(simctlJson) {
94
108
  return null;
95
109
  }
96
110
  }
111
+ const SIMULATOR_DIR = /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
97
112
  /**
98
113
  * Calls `onChange` when anything `stim status` reports may have changed:
99
- * `$STIM_HOME` files, adb device arrivals and departures, and simulator
100
- * state. simctl has no push API reachable from Node, so it is polled.
114
+ * `$STIM_HOME` files, git HEADs, indexes and refs of the watched repositories,
115
+ * exits of the watched processes, adb device arrivals and departures, and
116
+ * simulator state. Process liveness is polled with a signal 0 that spawns
117
+ * nothing. simctl has no push API reachable from Node, so a simulator change is
118
+ * a write CoreSimulator makes in `deviceSet`: to `device_set.plist`, a device
119
+ * directory, or a device's `device.plist`, which carries its state. A slow
120
+ * simctl poll covers events FSEvents drops and a device set that cannot be watched.
101
121
  */
102
- function watchStatusSources({ home, onChange, platform = process.platform, simctlIntervalMs = WATCH_SIMCTL_INTERVAL_MS }) {
122
+ function watchStatusSources({ home, deviceSet, onChange, platform = process.platform, simctlIntervalMs = WATCH_SIMCTL_INTERVAL_MS }) {
103
123
  let stopped = false;
104
124
  const watchers = /* @__PURE__ */ new Map();
105
125
  const desiredDirs = () => {
@@ -111,6 +131,7 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
111
131
  [join(home, "device-locks"), "leases"],
112
132
  [easMachineStateRoot(), "eas"]
113
133
  ]);
134
+ if (platform === "darwin") return dirs;
114
135
  let names = [];
115
136
  try {
116
137
  names = readdirSync(join(home, "workspaces"));
@@ -132,11 +153,26 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
132
153
  for (const [dir, kind] of desired) {
133
154
  if (watchers.has(dir)) continue;
134
155
  try {
135
- const watcher = watch(dir, (_event, name) => {
136
- const change = statusChange(kind, name === null ? null : String(name));
156
+ const recursive = platform === "darwin" && kind === "workspaces";
157
+ const watcher = watch(dir, { recursive }, (_event, name) => {
158
+ let source = kind;
159
+ let filename = name === null ? null : String(name);
160
+ if (recursive && filename !== null) {
161
+ const [, entry, child, ...nested] = filename.split("/");
162
+ if (entry !== void 0) {
163
+ if (entry === "logs" && child !== void 0 && nested.length === 0) {
164
+ source = "logs";
165
+ filename = child;
166
+ } else if (child === void 0) {
167
+ source = "workspace";
168
+ filename = entry;
169
+ } else return;
170
+ }
171
+ }
172
+ const change = statusChange(source, filename);
137
173
  if (!change) return;
138
- if (kind === "home" || kind === "workspaces" || kind === "workspace") {
139
- listingStaleBefore = Date.now();
174
+ if (source === "home" || source === "workspaces" || source === "workspace") {
175
+ listingVersion++;
140
176
  reconcile();
141
177
  }
142
178
  onChange(change);
@@ -149,16 +185,114 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
149
185
  } catch {}
150
186
  }
151
187
  };
188
+ const repositories = /* @__PURE__ */ new Map();
189
+ const watchRepositories = (commonDirs) => {
190
+ if (stopped) return;
191
+ const wanted = new Set(commonDirs);
192
+ for (const [dir, watcher] of repositories) {
193
+ if (wanted.has(dir)) continue;
194
+ watcher.close();
195
+ repositories.delete(dir);
196
+ }
197
+ for (const dir of wanted) {
198
+ if (repositories.has(dir)) continue;
199
+ try {
200
+ const watcher = watch(dir, { recursive: true }, (_event, name) => {
201
+ if (gitChange(name === null ? null : String(name))) onChange("full");
202
+ });
203
+ watcher.on("error", () => {
204
+ watcher.close();
205
+ repositories.delete(dir);
206
+ });
207
+ repositories.set(dir, watcher);
208
+ } catch {}
209
+ }
210
+ };
211
+ let processes = [];
212
+ const processTimer = setInterval(() => {
213
+ if (processes.some((pid) => !pidExists(pid))) {
214
+ processes = [];
215
+ onChange("full");
216
+ }
217
+ }, WATCH_PROCESS_INTERVAL_MS);
218
+ processTimer.unref();
152
219
  const adb = trackAdbDevices(() => onChange("full"));
153
220
  let simctl = null;
154
221
  let listing = null;
155
- let listingStaleBefore = 0;
222
+ let listingVersion = 0;
156
223
  let simTimer = null;
157
- if (platform === "darwin") {
224
+ const deviceWatchers = /* @__PURE__ */ new Map();
225
+ if (platform === "darwin" && deviceSet) {
226
+ const changed = () => {
227
+ listingVersion++;
228
+ check();
229
+ onChange("full");
230
+ };
231
+ const watchDir = (dir, listener) => {
232
+ try {
233
+ const ino = statSync(dir, { bigint: true }).ino;
234
+ const current = deviceWatchers.get(dir);
235
+ if (current?.ino === ino) return;
236
+ current?.watcher.close();
237
+ deviceWatchers.delete(dir);
238
+ const watcher = watch(dir, (_event, name) => {
239
+ if (!stopped && deviceWatchers.get(dir)?.watcher === watcher) listener(name === null ? null : String(name));
240
+ });
241
+ watcher.on("error", () => {
242
+ if (deviceWatchers.get(dir)?.watcher !== watcher) return;
243
+ watcher.close();
244
+ deviceWatchers.delete(dir);
245
+ });
246
+ deviceWatchers.set(dir, {
247
+ watcher,
248
+ ino
249
+ });
250
+ } catch {}
251
+ };
252
+ const watchDeviceSet = () => {
253
+ if (stopped) return;
254
+ let names = null;
255
+ try {
256
+ names = readdirSync(deviceSet);
257
+ } catch {}
258
+ const wanted = /* @__PURE__ */ new Set();
259
+ if (names) {
260
+ wanted.add(deviceSet);
261
+ for (const name of names) {
262
+ if (!SIMULATOR_DIR.test(name)) continue;
263
+ const dir = join(deviceSet, name);
264
+ const plist = join(dir, "device.plist");
265
+ wanted.add(existsSync(plist) ? plist : dir);
266
+ }
267
+ } else {
268
+ let dir = dirname(deviceSet);
269
+ while (dirname(dir) !== dir && !isDirectory(dir)) dir = dirname(dir);
270
+ wanted.add(dir);
271
+ }
272
+ for (const [dir, { watcher }] of deviceWatchers) {
273
+ if (wanted.has(dir)) continue;
274
+ watcher.close();
275
+ deviceWatchers.delete(dir);
276
+ }
277
+ for (const dir of wanted) if (dir === deviceSet) watchDir(dir, () => {
278
+ watchDeviceSet();
279
+ changed();
280
+ });
281
+ else if (basename(dir) === "device.plist") watchDir(dir, changed);
282
+ else if (dirname(dir) === deviceSet) watchDir(dir, (name) => {
283
+ if (name === null || name === "device.plist") changed();
284
+ });
285
+ else watchDir(dir, () => {
286
+ watchDeviceSet();
287
+ if (deviceWatchers.has(deviceSet)) changed();
288
+ });
289
+ };
158
290
  let last = null;
159
291
  const check = () => {
292
+ watchDeviceSet();
160
293
  if (simctl || stopped) return;
161
294
  const startedAt = Date.now();
295
+ const version = listingVersion;
162
296
  let out = "";
163
297
  const child = getExecutor().spawn("xcrun", [
164
298
  "simctl",
@@ -176,18 +310,23 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
176
310
  });
177
311
  simctl = child;
178
312
  child.stdout?.on("data", (chunk) => out += chunk.toString());
179
- child.on("error", () => {
180
- simctl = null;
181
- });
313
+ child.on("error", () => {});
182
314
  child.on("close", () => {
183
315
  simctl = null;
316
+ if (stopped) return;
317
+ if (version !== listingVersion) {
318
+ check();
319
+ return;
320
+ }
184
321
  const signature = simulatorSignature(out);
185
- if (signature === null || stopped) return;
322
+ if (signature === null) return;
323
+ const wasStale = listing?.version !== version;
186
324
  listing = {
187
325
  at: startedAt,
326
+ version,
188
327
  json: out
189
328
  };
190
- if (last !== null && signature !== last) onChange("full");
329
+ if (last !== null && (signature !== last || wasStale)) onChange("full");
191
330
  last = signature;
192
331
  });
193
332
  };
@@ -197,12 +336,21 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
197
336
  reconcile();
198
337
  return {
199
338
  reconcile,
200
- simulatorListing: () => listing && listing.at > listingStaleBefore && Date.now() - listing.at <= 2 * simctlIntervalMs ? listing.json : null,
339
+ watchRepositories,
340
+ watchProcesses(pids) {
341
+ processes = [...new Set(pids)];
342
+ },
343
+ simulatorListing: () => listing && listing.version === listingVersion && Date.now() - listing.at <= 2 * simctlIntervalMs ? listing.json : null,
201
344
  stop() {
202
345
  stopped = true;
203
346
  for (const watcher of watchers.values()) watcher.close();
204
347
  watchers.clear();
348
+ for (const watcher of repositories.values()) watcher.close();
349
+ repositories.clear();
350
+ clearInterval(processTimer);
205
351
  if (simTimer) clearInterval(simTimer);
352
+ for (const { watcher } of deviceWatchers.values()) watcher.close();
353
+ deviceWatchers.clear();
206
354
  simctl?.kill("SIGKILL");
207
355
  adb.stop();
208
356
  }
@@ -249,6 +397,13 @@ function trackAdbDevices(onChange) {
249
397
  child?.kill("SIGTERM");
250
398
  } };
251
399
  }
400
+ function isDirectory(path) {
401
+ try {
402
+ return statSync(path).isDirectory();
403
+ } catch {
404
+ return false;
405
+ }
406
+ }
252
407
  function ownerKey(owner) {
253
408
  return JSON.stringify([
254
409
  owner.kind,
@@ -265,7 +420,7 @@ function ownerSteady(before, after) {
265
420
  /**
266
421
  * The payload `status --watch --json` prints. A usage figure keeps its value from the `previous` printed payload until it moves by a step: an owner's `cpuPercent`
267
422
  * and `memoryMb`, an environment's `memoryMb` and `capacity.committedMb`. An owner's row is kept whole, `residentMb`
268
- * and `processes` included, until one of its two figures moves, so a Mac whose processes only jitter prints no new line.
423
+ * and `processes` included, until one of its two figures moves, so a machine whose processes only jitter prints no new line.
269
424
  */
270
425
  function watchPayload(previous, next) {
271
426
  const payload = { ...next };
@@ -292,5 +447,47 @@ function watchPayload(previous, next) {
292
447
  if (capacity.overCapacity === next.capacity.overCapacity && capacity.liveCount === next.capacity.liveCount && capacity.totalMemoryMb === next.capacity.totalMemoryMb && Math.abs(next.capacity.committedMb - capacity.committedMb) < 16) payload.capacity = capacity;
293
448
  return payload;
294
449
  }
450
+ const holdPullRequest = (worktree) => worktree.pullRequest ? {
451
+ ...worktree,
452
+ pullRequest: {
453
+ ...worktree.pullRequest,
454
+ checkedAt: ""
455
+ }
456
+ } : worktree;
457
+ /**
458
+ * The string `status --watch --json` compares to decide whether a line is new. It is the payload with the bookkeeping
459
+ * timestamps masked: each `pullRequest.checkedAt`, `maintenance.lastChecks`, `maintenance.lastPass.startedAt` and
460
+ * `durationMs`, and `maintenance.running.startedAt`. A change in only those fields prints no line; any printed line
461
+ * carries the current values.
462
+ */
463
+ function watchChangeKey(payload) {
464
+ const { maintenance } = payload;
465
+ return JSON.stringify({
466
+ ...payload,
467
+ environments: payload.environments.map((env) => env.worktree ? {
468
+ ...env,
469
+ worktree: holdPullRequest(env.worktree)
470
+ } : env),
471
+ unprovisionedWorktrees: payload.unprovisionedWorktrees.map(holdPullRequest),
472
+ maintenance: maintenance && {
473
+ ...maintenance,
474
+ lastChecks: {
475
+ pressure: null,
476
+ size: null,
477
+ worktree: null,
478
+ sweep: null
479
+ },
480
+ lastPass: maintenance.lastPass && {
481
+ ...maintenance.lastPass,
482
+ startedAt: 0,
483
+ durationMs: 0
484
+ },
485
+ running: maintenance.running && {
486
+ ...maintenance.running,
487
+ startedAt: ""
488
+ }
489
+ }
490
+ });
491
+ }
295
492
  //#endregion
296
- export { watchStatusSources as a, watchPayload as i, WATCH_LIGHT_INTERVAL_MS as n, createRefreshScheduler as r, WATCH_FALLBACK_MS as t };
493
+ export { createRefreshScheduler as a, watchStatusSources as c, WATCH_TABLES_INTERVAL_MS as i, WATCH_LIGHT_INTERVAL_MS as n, watchChangeKey as o, WATCH_MACHINE_INTERVAL_MS as r, watchPayload as s, WATCH_FALLBACK_MS as t };
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,19 @@
1
+ import { n as runStatusWatch } from "./status-WBDajew2.mjs";
2
+ import { parentPort, workerData } from "node:worker_threads";
3
+ //#region src/status-worker.ts
4
+ const STOP_EXIT_MS = 500;
5
+ const cwd = workerData?.cwd;
6
+ const watch = runStatusWatch({
7
+ json: true,
8
+ ...typeof cwd === "string" ? { cwd } : {},
9
+ emit: (line) => parentPort?.postMessage({ line }),
10
+ failed: (message) => parentPort?.postMessage({ failed: message })
11
+ });
12
+ parentPort?.on("message", (message) => {
13
+ if (message !== "stop") return;
14
+ watch.stop();
15
+ parentPort?.close();
16
+ setTimeout(() => process.exit(0), STOP_EXIT_MS);
17
+ });
18
+ //#endregion
19
+ export {};
@@ -0,0 +1,112 @@
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { C as saveConfig, c as ensureConfig } from "./config-DlrsduwG.mjs";
3
+ import { randomUUID } from "node:crypto";
4
+ import { workspaceId } from "@stim-cli/core";
5
+ import { readHomeIdentity, withConfigLockAsync } from "@stim-cli/core/state";
6
+ import { realpath } from "node:fs/promises";
7
+ import { sharedWorkspaceURL } from "@stim-cli/core/workspace-link";
8
+ //#region src/workspace/home-identity.ts
9
+ function ensureHomeIdentity(signal) {
10
+ return withConfigLockAsync(() => {
11
+ signal?.throwIfAborted();
12
+ const config = ensureConfig();
13
+ const existing = readHomeIdentity(config);
14
+ if (existing) return existing;
15
+ const id = randomUUID();
16
+ config.homeId = id;
17
+ saveConfig(config);
18
+ return id;
19
+ });
20
+ }
21
+ //#endregion
22
+ //#region src/devices/stim-desktop.ts
23
+ const LAUNCH_SERVICES_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationWithBundleIdentifier('dev.stim.desktop'); url.isNil() ? '' : url.path.js`;
24
+ const SCHEME_HANDLER_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationToOpenURL($.NSURL.URLWithString('stim-desktop://workspace')); url.isNil() ? '' : url.path.js`;
25
+ const STIM_DESKTOP_INSTALLED = "Stim Desktop installed";
26
+ /**
27
+ * macOS `open` passes its environment to an app it launches, so Stim Desktop
28
+ * started by a command run under a scoped `STIM_HOME` would serve that home.
29
+ */
30
+ const STIM_DESKTOP_OPEN_OPTIONS = {
31
+ timeoutMs: 5e3,
32
+ killSignal: "SIGKILL",
33
+ omitEnv: ["STIM_HOME"]
34
+ };
35
+ /** Stim Desktop sets `STIM_DESKTOP_APP` to its bundle path for every command it runs; a non-empty value means Desktop is installed. */
36
+ function stimDesktopInstalled(platform = process.platform, env = process.env) {
37
+ if (platform !== "darwin") return false;
38
+ if (env.STIM_DESKTOP_APP) return true;
39
+ return launchServicesFinds(LAUNCH_SERVICES_LOOKUP);
40
+ }
41
+ /** `stimDesktopInstalled` without blocking the event loop. */
42
+ async function stimDesktopInstalledAsync(platform = process.platform, env = process.env, onSpawn) {
43
+ if (platform !== "darwin") return false;
44
+ if (env.STIM_DESKTOP_APP) return true;
45
+ const found = await getExecutor().runFileAsync("osascript", [
46
+ "-l",
47
+ "JavaScript",
48
+ "-e",
49
+ LAUNCH_SERVICES_LOOKUP
50
+ ], {
51
+ timeoutMs: 5e3,
52
+ killSignal: "SIGKILL",
53
+ onSpawn
54
+ }).catch(() => "");
55
+ return Boolean(found);
56
+ }
57
+ function launchServicesFinds(script) {
58
+ return Boolean(getExecutor().runFileQuiet("osascript", [
59
+ "-l",
60
+ "JavaScript",
61
+ "-e",
62
+ script
63
+ ], {
64
+ timeoutMs: 5e3,
65
+ killSignal: "SIGKILL"
66
+ }));
67
+ }
68
+ async function stimDesktopHandlesLinks(platform = process.platform, env = process.env) {
69
+ if (platform !== "darwin") return false;
70
+ if (env.STIM_DESKTOP_APP) return true;
71
+ return Boolean(await getExecutor().runFileAsync("osascript", [
72
+ "-l",
73
+ "JavaScript",
74
+ "-e",
75
+ SCHEME_HANDLER_LOOKUP
76
+ ], {
77
+ timeoutMs: 5e3,
78
+ killSignal: "SIGKILL"
79
+ }).catch(() => ""));
80
+ }
81
+ /**
82
+ * The links that open this workspace for a human, or undefined when no app on this Mac handles
83
+ * `stim-desktop://`. `target` names the device Stim Desktop focuses when the user opens the workspace.
84
+ */
85
+ async function workspaceLinks(root, target, handlesLinks = stimDesktopHandlesLinks) {
86
+ if (!await handlesLinks()) return void 0;
87
+ return { desktop: await workspaceShareURL(root, target) };
88
+ }
89
+ /** A share URL for the canonical workspace in this Stim home, usable by its already-paired phone or Desktop. */
90
+ async function workspaceShareURL(root, target, signal) {
91
+ const canonical = await realpath(root);
92
+ return sharedWorkspaceURL({
93
+ machine: await ensureHomeIdentity(signal),
94
+ workspace: workspaceId(canonical),
95
+ ...target
96
+ });
97
+ }
98
+ function workspaceLinkLine(links) {
99
+ return `Open in Stim: ${links.desktop}`;
100
+ }
101
+ function settingDefault(setting, desktopInstalled = stimDesktopInstalled) {
102
+ if (setting.desktopDefault !== void 0 && desktopInstalled()) return {
103
+ value: setting.desktopDefault,
104
+ reason: STIM_DESKTOP_INSTALLED
105
+ };
106
+ return {
107
+ value: setting.default,
108
+ reason: null
109
+ };
110
+ }
111
+ //#endregion
112
+ export { workspaceLinkLine as a, ensureHomeIdentity as c, stimDesktopInstalledAsync as i, settingDefault as n, workspaceLinks as o, stimDesktopInstalled as r, workspaceShareURL as s, STIM_DESKTOP_OPEN_OPTIONS as t };
@@ -1,3 +1,3 @@
1
- import { P as resolveSupervisorTarget } from "./workspaces-C36s2jb9.mjs";
2
- import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-BNmBMi1F.mjs";
1
+ import { h as resolveSupervisorTarget } from "./workspaces-CpANmBlq.mjs";
2
+ import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-Mv6W9FAk.mjs";
3
3
  export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop, stopWorkspaceNow };
@@ -1,9 +1,9 @@
1
- import { j as ownership_claim_exports, k as process_identity_exports } from "./config-BYDxlMY3.mjs";
2
- import { c as writeWorkspaceState, x as workspaceDir } from "./workspace-state-DJt_MMvf.mjs";
3
- import { m as runningBundleInstances } from "./workspaces-C36s2jb9.mjs";
4
- import { a as withWorkspaceProcessLock } from "./named-ports-4WopRPg-.mjs";
5
- import { a as macosRuntimeClaim, o as requiredMacosRecord } from "./state-CG_OFoaA.mjs";
6
- import { n as stopHostedMacos } from "./hosted-macos-BACVAVqE.mjs";
1
+ import { g as process_identity_exports, i as withWorkspaceProcessLock, x as ownership_claim_exports } from "./exec-DEoAhcze.mjs";
2
+ import { d as workspaceDir } from "./paths-DQtTgsBf.mjs";
3
+ import { d as writeWorkspaceState, l as withWorkspaceStateLockAsync } from "./workspace-state-U08dEzhG.mjs";
4
+ import { a as macosRuntimeClaim, o as requiredMacosRecord } from "./state-08I3hw3_.mjs";
5
+ import { C as runningBundleInstancesAsync } from "./workspaces-CpANmBlq.mjs";
6
+ import { n as stopHostedMacos } from "./hosted-macos-_awYSpfv.mjs";
7
7
  import { readMacosRecord } from "@stim-cli/core/state";
8
8
  //#region src/macos/stop.ts
9
9
  const APP_EXIT_MS = 5e3;
@@ -15,57 +15,67 @@ function signal(pid, name) {
15
15
  if (error.code !== "ESRCH") throw error;
16
16
  }
17
17
  }
18
- async function stopProcesses(records, waitMs = APP_EXIT_MS) {
18
+ async function stopProcesses(records, waitMs = APP_EXIT_MS, operation) {
19
19
  let live = [...new Map(records.map((record) => [record.pid, record])).values()];
20
20
  for (const name of ["SIGTERM", "SIGKILL"]) {
21
+ operation?.signal.throwIfAborted();
21
22
  live = live.filter((record) => {
22
23
  const identity = (0, process_identity_exports.inspectProcessIdentity)(record);
23
24
  if (identity === "gone" || identity === "different") return false;
24
25
  if (identity !== "same") throw Object.assign(/* @__PURE__ */ new Error(`Cannot verify macOS owner pid ${record.pid}; no signal was sent.`), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
25
26
  return true;
26
27
  });
27
- for (const record of live) signal(record.pid, name);
28
- const exited = await Promise.all(live.map((record) => (0, process_identity_exports.waitForProcessExit)(record, waitMs)));
28
+ for (const record of live) {
29
+ operation?.signal.throwIfAborted();
30
+ signal(record.pid, name);
31
+ }
32
+ const exited = await Promise.all(live.map((record) => (0, process_identity_exports.waitForProcessExit)(record, waitMs, operation?.signal)));
29
33
  live = live.filter((_, index) => !exited[index]);
30
34
  if (!live.length) return;
31
35
  }
32
36
  throw new Error(`Owned macOS process ${live.map((record) => record.pid).join(", ")} did not exit.`);
33
37
  }
34
38
  /** Stops every running copy of the workspace's owned app bundle, including copies LaunchServices started. */
35
- async function stopBundleInstances(root) {
36
- const instances = runningBundleInstances(root);
37
- await stopProcesses(instances);
39
+ async function stopBundleInstances(root, operation) {
40
+ const instances = await runningBundleInstancesAsync(root, operation);
41
+ await stopProcesses(instances, void 0, operation);
38
42
  return instances.length > 0;
39
43
  }
40
- async function stopMacosAppHeld(root) {
44
+ async function stopMacosAppHeld(root, operation) {
45
+ operation?.signal.throwIfAborted();
41
46
  const record = requiredMacosRecord(root);
42
- if (record?.supervisor) await stopProcesses([record.supervisor], SUPERVISOR_EXIT_MS);
47
+ if (record?.supervisor) await stopProcesses([record.supervisor], SUPERVISOR_EXIT_MS, operation);
43
48
  const app = readMacosRecord(root)?.app ?? record?.app;
44
- if (app) await stopProcesses([app]);
45
- const instances = runningBundleInstances(root);
46
- await stopProcesses(instances);
49
+ if (app) await stopProcesses([app], void 0, operation);
50
+ const instances = await runningBundleInstancesAsync(root, operation);
51
+ await stopProcesses(instances, void 0, operation);
52
+ operation?.signal.throwIfAborted();
47
53
  if (!record) return instances.length > 0;
48
54
  const claims = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
49
55
  if (claims.unresolved.length || claims.live.length) throw Object.assign(/* @__PURE__ */ new Error("The macOS runtime claim cannot be released; inspect its recorded owner before cleanup."), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
50
56
  return true;
51
57
  }
52
58
  /** Stops the workspace's app here, or its session on the hosting Mac, which must confirm the session stopped. */
53
- function stopMacosApp(root) {
59
+ function stopMacosApp(root, operation) {
54
60
  const stop = async () => {
61
+ operation?.signal.throwIfAborted();
55
62
  const record = requiredMacosRecord(root);
56
- if (!record?.host) return stopMacosAppHeld(root);
57
- await stopHostedMacos(root, record.host);
63
+ if (!record?.host) return stopMacosAppHeld(root, operation);
64
+ await stopHostedMacos(root, record.host, operation?.signal);
65
+ operation?.signal.throwIfAborted();
58
66
  const { host: _host, hostLaunched: _launched, ...stopped } = record;
59
- writeWorkspaceState(root, { macos: {
67
+ await withWorkspaceStateLockAsync(root, () => writeWorkspaceState(root, { macos: {
60
68
  ...stopped,
61
69
  supervisor: void 0
62
- } });
70
+ } }), operation?.signal);
63
71
  return true;
64
72
  };
65
73
  return withWorkspaceProcessLock(workspaceDir(root), "macos-launch", stop, {
66
74
  external: true,
67
75
  waitMs: 0,
68
- ownerPurpose: "stop macOS app"
76
+ ownerPurpose: "stop macOS app",
77
+ signal: operation?.signal,
78
+ declareSpawnsFor: operation
69
79
  });
70
80
  }
71
81
  //#endregion