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
@@ -287,7 +287,7 @@
287
287
  }
288
288
  },
289
289
  "remote": {
290
- "description": "Default iOS remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this Mac is full or busy; local runs here, overriding a lower layer",
290
+ "description": "Default iOS remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer",
291
291
  "type": "string",
292
292
  "pattern": "^[A-Za-z0-9][A-Za-z0-9.-]*(?::(?!0+$)(?:[0-5]?[0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$",
293
293
  "x-stim": {
@@ -490,6 +490,19 @@
490
490
  ]
491
491
  }
492
492
  },
493
+ "artifactInputs": {
494
+ "description": "Complete repeatable native Gradle inputs for local APK caching, including declared local files and environment names",
495
+ "type": "object",
496
+ "x-stim": {
497
+ "key": "android.artifactInputs",
498
+ "kind": "object",
499
+ "scopes": [
500
+ "workspace",
501
+ "repo",
502
+ "committed"
503
+ ]
504
+ }
505
+ },
493
506
  "offloadInputs": {
494
507
  "description": "Native Gradle source sufficiency, exact ignored inputs and generated output directories for build workers",
495
508
  "type": "object",
@@ -532,7 +545,7 @@
532
545
  }
533
546
  },
534
547
  "remote": {
535
- "description": "Default Android remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this Mac is full or busy; local runs here, overriding a lower layer",
548
+ "description": "Default Android remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer",
536
549
  "type": "string",
537
550
  "pattern": "^[A-Za-z0-9][A-Za-z0-9.-]*(?::(?!0+$)(?:[0-5]?[0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$",
538
551
  "x-stim": {
@@ -750,6 +763,19 @@
750
763
  "relative": true
751
764
  }
752
765
  },
766
+ "artifactInputs": {
767
+ "description": "Complete pinned, repeatable SwiftPM inputs producing a relocatable app for completed artifact caching.",
768
+ "type": "object",
769
+ "x-stim": {
770
+ "key": "macos.artifactInputs",
771
+ "kind": "object",
772
+ "scopes": [
773
+ "workspace",
774
+ "repo",
775
+ "committed"
776
+ ]
777
+ }
778
+ },
753
779
  "arguments": {
754
780
  "description": "Arguments passed directly to the owned macOS development executable.",
755
781
  "type": "array",
@@ -941,7 +967,7 @@
941
967
  "type": "object",
942
968
  "properties": {
943
969
  "keep": {
944
- "description": "Pin this workspace: automatic maintenance never clears its build outputs or removes its worktree",
970
+ "description": "Pin this workspace: automatic maintenance never clears its build outputs, deletes its owned devices or removes its worktree",
945
971
  "type": "boolean",
946
972
  "default": false,
947
973
  "x-stim": {
@@ -961,7 +987,7 @@
961
987
  "type": "object",
962
988
  "properties": {
963
989
  "easFallback": {
964
- "description": "When ios.remote or android.remote is auto, this Mac is at its concurrency.maxDevices cap and no Mac in remote.machines takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can",
990
+ "description": "When ios.remote or android.remote is auto, this machine is at its concurrency.maxDevices cap and no remote.machines entry takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can",
965
991
  "type": "boolean",
966
992
  "default": false,
967
993
  "x-stim": {
@@ -1243,7 +1269,7 @@
1243
1269
  }
1244
1270
  },
1245
1271
  "remote": {
1246
- "description": "Default iOS remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this Mac is full or busy; local runs here, overriding a lower layer",
1272
+ "description": "Default iOS remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer",
1247
1273
  "type": "string",
1248
1274
  "pattern": "^[A-Za-z0-9][A-Za-z0-9.-]*(?::(?!0+$)(?:[0-5]?[0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$",
1249
1275
  "x-stim": {
@@ -1256,6 +1282,46 @@
1256
1282
  "committed"
1257
1283
  ]
1258
1284
  }
1285
+ },
1286
+ "appStoreConnectKeyPath": {
1287
+ "description": "App Store Connect API key (.p8) that `stim device provision ios` authenticates with",
1288
+ "type": "string",
1289
+ "x-stim": {
1290
+ "key": "ios.appStoreConnectKeyPath",
1291
+ "kind": "path",
1292
+ "scopes": [
1293
+ "machine"
1294
+ ],
1295
+ "absolute": true,
1296
+ "env": "STIM_ASC_KEY_PATH",
1297
+ "sensitive": true
1298
+ }
1299
+ },
1300
+ "appStoreConnectKeyId": {
1301
+ "description": "Key ID of ios.appStoreConnectKeyPath",
1302
+ "type": "string",
1303
+ "pattern": "^[A-Za-z0-9]+$",
1304
+ "x-stim": {
1305
+ "key": "ios.appStoreConnectKeyId",
1306
+ "kind": "string",
1307
+ "scopes": [
1308
+ "machine"
1309
+ ],
1310
+ "env": "STIM_ASC_KEY_ID"
1311
+ }
1312
+ },
1313
+ "appStoreConnectIssuerId": {
1314
+ "description": "Issuer ID of ios.appStoreConnectKeyPath",
1315
+ "type": "string",
1316
+ "pattern": "^[A-Za-z0-9-]+$",
1317
+ "x-stim": {
1318
+ "key": "ios.appStoreConnectIssuerId",
1319
+ "kind": "string",
1320
+ "scopes": [
1321
+ "machine"
1322
+ ],
1323
+ "env": "STIM_ASC_ISSUER_ID"
1324
+ }
1259
1325
  }
1260
1326
  },
1261
1327
  "additionalProperties": false
@@ -1294,7 +1360,7 @@
1294
1360
  }
1295
1361
  },
1296
1362
  "remote": {
1297
- "description": "Default Android remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this Mac is full or busy; local runs here, overriding a lower layer",
1363
+ "description": "Default Android remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer",
1298
1364
  "type": "string",
1299
1365
  "pattern": "^[A-Za-z0-9][A-Za-z0-9.-]*(?::(?!0+$)(?:[0-5]?[0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$",
1300
1366
  "x-stim": {
@@ -1855,6 +1921,20 @@
1855
1921
  "env": "STIM_MAINTENANCE_OLDER_THAN_DAYS"
1856
1922
  }
1857
1923
  },
1924
+ "deviceIdleDays": {
1925
+ "description": "Days a workspace stays idle before the age sweep deletes its owned simulators and emulators; 0 turns that off",
1926
+ "type": "integer",
1927
+ "minimum": 0,
1928
+ "default": 3,
1929
+ "x-stim": {
1930
+ "key": "maintenance.deviceIdleDays",
1931
+ "kind": "number",
1932
+ "scopes": [
1933
+ "machine"
1934
+ ],
1935
+ "env": "STIM_MAINTENANCE_DEVICE_IDLE_DAYS"
1936
+ }
1937
+ },
1858
1938
  "protectRecentHours": {
1859
1939
  "description": "Cache entries used within this many hours are never evicted",
1860
1940
  "type": "integer",
@@ -1869,8 +1949,64 @@
1869
1949
  "env": "STIM_MAINTENANCE_PROTECT_RECENT_HOURS"
1870
1950
  }
1871
1951
  },
1952
+ "urgentFreeDiskGb": {
1953
+ "description": "Free disk, in GB, below which automatic maintenance reports disk pressure level 2; 0 turns that threshold off",
1954
+ "type": "number",
1955
+ "minimum": 0,
1956
+ "default": 12,
1957
+ "x-stim": {
1958
+ "key": "maintenance.urgentFreeDiskGb",
1959
+ "kind": "number",
1960
+ "scopes": [
1961
+ "machine"
1962
+ ],
1963
+ "env": "STIM_MAINTENANCE_URGENT_FREE_DISK_GB"
1964
+ }
1965
+ },
1966
+ "criticalFreeDiskGb": {
1967
+ "description": "Free disk, in GB, below which automatic maintenance enters disk pressure level 3, also at or below budget.hardFloorDiskGb; 0 leaves only the hard floor",
1968
+ "type": "number",
1969
+ "minimum": 0,
1970
+ "default": 6,
1971
+ "x-stim": {
1972
+ "key": "maintenance.criticalFreeDiskGb",
1973
+ "kind": "number",
1974
+ "scopes": [
1975
+ "machine"
1976
+ ],
1977
+ "env": "STIM_MAINTENANCE_CRITICAL_FREE_DISK_GB"
1978
+ }
1979
+ },
1980
+ "pressureProtectMinutes": {
1981
+ "description": "Protection window, in minutes, that replaces maintenance.protectRecentHours at disk pressure levels 2 and 3",
1982
+ "type": "integer",
1983
+ "minimum": 0,
1984
+ "default": 10,
1985
+ "x-stim": {
1986
+ "key": "maintenance.pressureProtectMinutes",
1987
+ "kind": "number",
1988
+ "scopes": [
1989
+ "machine"
1990
+ ],
1991
+ "env": "STIM_MAINTENANCE_PRESSURE_PROTECT_MINUTES"
1992
+ }
1993
+ },
1994
+ "gradleVersionIdleDays": {
1995
+ "description": "At disk pressure level 3, stop idle Gradle and Kotlin daemons, then delete the Gradle version caches and wrapper distributions no registered project pins once their directories are unmodified this many days; 0 turns this off",
1996
+ "type": "integer",
1997
+ "minimum": 0,
1998
+ "default": 7,
1999
+ "x-stim": {
2000
+ "key": "maintenance.gradleVersionIdleDays",
2001
+ "kind": "number",
2002
+ "scopes": [
2003
+ "machine"
2004
+ ],
2005
+ "env": "STIM_MAINTENANCE_GRADLE_VERSION_IDLE_DAYS"
2006
+ }
2007
+ },
1872
2008
  "removeFinishedWorktrees": {
1873
- "description": "Remove clean linked worktrees whose branch or pull request finished, under gc.worktreeGraceMinutes",
2009
+ "description": "Remove clean linked worktrees whose branch or pull request finished, under gc.worktreeGraceMinutes, and at disk pressure level 3 clean, pushed ones with no commits of their own",
1874
2010
  "type": "boolean",
1875
2011
  "default": true,
1876
2012
  "x-stim": {
@@ -2045,7 +2181,7 @@
2045
2181
  "type": "object",
2046
2182
  "properties": {
2047
2183
  "logs": {
2048
- "description": "Debug-level logging. While on, the CLI records its commands, child processes and requests to other Macs, and stim-server records every request with its timings, under STIM_HOME/logs/debug/ with rotation. Nothing is sent anywhere, and records never carry arguments, tokens or tickets",
2184
+ "description": "Debug-level logging. While on, the CLI records its commands, child processes and requests to other machines, and stim-server records every request with its timings, under STIM_HOME/logs/debug/ with rotation. Nothing is sent anywhere, and records never carry arguments, tokens or tickets",
2049
2185
  "type": "boolean",
2050
2186
  "default": false,
2051
2187
  "x-stim": {
@@ -2085,8 +2221,32 @@
2085
2221
  "server": {
2086
2222
  "type": "object",
2087
2223
  "properties": {
2224
+ "buildsPaused": {
2225
+ "description": "Temporarily refuse new incoming builds without interrupting running builds, serving cached artifacts, or changing client approvals; local CLI builds remain available",
2226
+ "type": "boolean",
2227
+ "default": false,
2228
+ "x-stim": {
2229
+ "key": "server.buildsPaused",
2230
+ "kind": "boolean",
2231
+ "scopes": [
2232
+ "machine"
2233
+ ]
2234
+ }
2235
+ },
2236
+ "devicesPaused": {
2237
+ "description": "Temporarily refuse new hosted iOS, Android and macOS sessions without interrupting existing sessions or changing client approvals; local CLI devices remain available",
2238
+ "type": "boolean",
2239
+ "default": false,
2240
+ "x-stim": {
2241
+ "key": "server.devicesPaused",
2242
+ "kind": "boolean",
2243
+ "scopes": [
2244
+ "machine"
2245
+ ]
2246
+ }
2247
+ },
2088
2248
  "acceptClientBuilds": {
2089
- "description": "Whether a Mac approved for builds or device hosting here may update this Mac's stim-server service to that Mac's own stim-server build; releases from npm need no setting",
2249
+ "description": "Whether a machine approved for builds or device hosting here may update this machine's stim-server service to that machine's own stim-server build; releases from npm need no setting",
2090
2250
  "type": "boolean",
2091
2251
  "default": false,
2092
2252
  "x-stim": {
@@ -2098,7 +2258,7 @@
2098
2258
  }
2099
2259
  },
2100
2260
  "maxLoadPerCore": {
2101
- "description": "Load per core (5-minute load average divided by the CPU count) at which this Mac counts as saturated: it declines builds other Macs send it, automatic build placement stops preferring it, and automatic iOS and Android device placement treats it as busy",
2261
+ "description": "Load per core (5-minute load average divided by the CPU count) at which this machine counts as saturated: it declines builds other machines send it, automatic build placement stops preferring it, and automatic iOS and Android device placement treats it as busy",
2102
2262
  "type": "number",
2103
2263
  "minimum": 0.1,
2104
2264
  "default": 2,
@@ -2111,7 +2271,7 @@
2111
2271
  }
2112
2272
  },
2113
2273
  "workerRoot": {
2114
- "description": "Directory where stim-server keeps the checkouts, dependencies and build state of the Macs that build here; default $STIM_HOME/build-worker",
2274
+ "description": "Directory where stim-server keeps the checkouts, dependencies and build state of the machines that build here; default $STIM_HOME/build-worker",
2115
2275
  "type": "string",
2116
2276
  "x-stim": {
2117
2277
  "key": "server.workerRoot",
@@ -2123,7 +2283,7 @@
2123
2283
  }
2124
2284
  },
2125
2285
  "gradleDaemonIdleMinutes": {
2126
- "description": "Minutes the Gradle daemon of an Android build another Mac sent here stays warm after the build; 0 stops it when the build ends",
2286
+ "description": "Minutes the Gradle daemon of an Android build another machine sent here stays warm after the build; 0 stops it when the build ends",
2127
2287
  "type": "integer",
2128
2288
  "minimum": 0,
2129
2289
  "maximum": 35791,
@@ -2143,7 +2303,7 @@
2143
2303
  "type": "object",
2144
2304
  "properties": {
2145
2305
  "machines": {
2146
- "description": "Tailscale names of the remote Macs this Mac may build on and host owned simulators on, each optionally with :<port> of its tailscale serve route (default 7443); what each is used for follows the build and device-host approvals it grants, which doctor --fix asks for separately",
2306
+ "description": "Tailscale names of the remote machines this machine may build on and host owned simulators on, each optionally with :<port> of its tailscale serve route (default 7443); what each is used for follows the build and device-host approvals it grants, which doctor --fix asks for separately",
2147
2307
  "type": "array",
2148
2308
  "items": {
2149
2309
  "type": "string"
@@ -2187,7 +2347,7 @@
2187
2347
  }
2188
2348
  },
2189
2349
  "easFallback": {
2190
- "description": "When ios.remote or android.remote is auto, this Mac is at its concurrency.maxDevices cap and no Mac in remote.machines takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can",
2350
+ "description": "When ios.remote or android.remote is auto, this machine is at its concurrency.maxDevices cap and no remote.machines entry takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can",
2191
2351
  "type": "boolean",
2192
2352
  "default": false,
2193
2353
  "x-stim": {
@@ -2202,7 +2362,7 @@
2202
2362
  }
2203
2363
  },
2204
2364
  "build": {
2205
- "description": "Build placement: auto follows remote.buildMode within enabled automatic pool members; local always builds here; a name in remote.machines requires that remote Mac without fallback. The ios, android and macos --remote-build flag overrides this setting and its environment override",
2365
+ "description": "Build placement: auto follows remote.buildMode within enabled automatic pool members; local always builds here; a name in remote.machines requires that remote machine without fallback. The ios, android and macos --remote-build flag overrides this setting and its environment override",
2206
2366
  "type": "string",
2207
2367
  "pattern": "^[A-Za-z0-9][A-Za-z0-9.-]*(?::(?!0+$)(?:[0-5]?[0-9]{1,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$",
2208
2368
  "default": "auto",
@@ -2216,7 +2376,7 @@
2216
2376
  }
2217
2377
  },
2218
2378
  "buildMode": {
2219
- "description": "When remote.build is auto, where iOS simulator Debug, Android emulator debug and macOS SwiftPM Debug builds run: auto builds here while this Mac has a free concurrency.maxBuilds slot and its load is under server.maxLoadPerCore, and otherwise builds on a less loaded Mac in remote.machines; force builds on an enabled remote Mac whenever one can take the build; off builds here when local is enabled in remote.buildPoolDisabled",
2379
+ "description": "When remote.build is auto, where iOS simulator Debug, Android emulator debug and macOS SwiftPM Debug builds run: auto builds here while this machine has a free concurrency.maxBuilds slot and its load is under server.maxLoadPerCore, and otherwise builds on a less loaded machine in remote.machines; force builds on an enabled remote machine whenever one can take the build; off builds here when local is enabled in remote.buildPoolDisabled",
2220
2380
  "type": "string",
2221
2381
  "enum": [
2222
2382
  "auto",
@@ -1,9 +1,9 @@
1
- import { d as getConfigDir, j as ownership_claim_exports, k as process_identity_exports } from "./config-BYDxlMY3.mjs";
2
- import { t as getExecutor } from "./exec-DqKo9GKJ.mjs";
1
+ import { g as process_identity_exports, m as operationState, p as isTermination, t as getExecutor, x as ownership_claim_exports } from "./exec-DEoAhcze.mjs";
2
+ import { d as getConfigDir } from "./config-DlrsduwG.mjs";
3
3
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
4
  import { join } from "node:path";
5
5
  //#region src/engine/simslim.ts
6
- async function reconcileSimSlim({ udid, profile, previouslyManaged = false, out = () => {}, spawn, timeoutMs = 72e4, cleanupMs = 1e4 }) {
6
+ async function reconcileSimSlim({ udid, profile, previouslyManaged = false, out = () => {}, spawn, timeoutMs = 72e4, cleanupMs = 1e4, context }) {
7
7
  if (!profile && !previouslyManaged) return {
8
8
  managed: false,
9
9
  profile: null
@@ -53,8 +53,12 @@ async function reconcileSimSlim({ udid, profile, previouslyManaged = false, out
53
53
  cancellation ??= signal;
54
54
  stopGroup();
55
55
  };
56
- const onInterrupt = () => cancel("SIGINT");
57
- const onTerminate = () => cancel("SIGTERM");
56
+ const state = operationState(context);
57
+ const onAbort = () => {
58
+ state.handled = true;
59
+ state.draining = true;
60
+ cancel(isTermination(context?.signal.reason) ? "SIGTERM" : "SIGINT");
61
+ };
58
62
  const groupAlive = () => child?.pid !== void 0 && (0, ownership_claim_exports.processGroupAlive)(child.pid);
59
63
  const settled = () => result !== void 0 && !groupAlive();
60
64
  const waitUntil = async (deadline, cancellable = false) => {
@@ -64,10 +68,10 @@ async function reconcileSimSlim({ udid, profile, previouslyManaged = false, out
64
68
  }
65
69
  return settled();
66
70
  };
67
- process.on("SIGINT", onInterrupt);
68
- process.on("SIGTERM", onTerminate);
69
- process.on("exit", stopGroup);
71
+ context?.signal.addEventListener("abort", onAbort);
72
+ state.exitCleanups.add(stopGroup);
70
73
  try {
74
+ if (context?.signal.aborted) onAbort();
71
75
  (0, ownership_claim_exports.markClaimChildPending)(claim);
72
76
  try {
73
77
  child = (spawn ?? ((cmd, childArgs, opts) => getExecutor().spawn(cmd, childArgs, opts)))("simslim", args, {
@@ -115,10 +119,8 @@ async function reconcileSimSlim({ udid, profile, previouslyManaged = false, out
115
119
  child.stderr?.destroy?.();
116
120
  child.unref();
117
121
  }
118
- process.off("SIGINT", onInterrupt);
119
- process.off("SIGTERM", onTerminate);
120
- process.off("exit", stopGroup);
121
- if (cancellation) process.exit(cancellation === "SIGINT" ? 130 : 143);
122
+ context?.signal.removeEventListener("abort", onAbort);
123
+ state.exitCleanups.delete(stopGroup);
122
124
  }
123
125
  stdout.flush();
124
126
  stderr.flush();
@@ -1,9 +1,9 @@
1
- import { H as parseDeviceSlotKey, W as projectDeviceSlots, p as getProject } from "./config-BYDxlMY3.mjs";
2
- import { n as fileLeaseIo } from "./device-lease-BX1sJQ2E.mjs";
3
- import { r as readWorkspaceState$1 } from "./workspace-state-DJt_MMvf.mjs";
4
- import { E as getAvdNameForSerial, O as listAdbDevices } from "./android-Mz_Inn3w.mjs";
5
- import { d as listAllIosSims } from "./ios-RkW4pnQf.mjs";
6
- import { p as deviceShellArg } from "./app-install-BIKtMfPq.mjs";
1
+ import { G as projectDeviceSlots, U as parseDeviceSlotKey, p as getProject } from "./config-DlrsduwG.mjs";
2
+ import { r as readWorkspaceState$1 } from "./workspace-state-U08dEzhG.mjs";
3
+ import { gn as deviceShellArg } from "./budget-Cvwn54qV.mjs";
4
+ import { y as fileLeaseIo } from "./activity-CMLmzp7o.mjs";
5
+ import { O as getAvdNameForSerialAsync, j as listAdbDevicesAsync } from "./android-C7sVmyI9.mjs";
6
+ import { f as listAllIosSimsAsync } from "./ios-hcBpnEGk.mjs";
7
7
  import { hostedNativeRecords } from "@stim-cli/core/state";
8
8
  //#region src/engine/slot-launch.ts
9
9
  function launchSlotScope(root, slot = "default") {
@@ -19,31 +19,26 @@ function launchSlotScope(root, slot = "default") {
19
19
  const DEVICE_LISTING_TIMEOUT_MS = 5e3;
20
20
  function ownedDeviceRunning(platform) {
21
21
  let listing = null;
22
- const list = () => {
22
+ const list = async () => {
23
23
  if (platform === "android") {
24
- const { emulators, unhealthy } = listAdbDevices({ timeoutMs: DEVICE_LISTING_TIMEOUT_MS });
24
+ const { emulators, unhealthy } = await listAdbDevicesAsync({ timeoutMs: DEVICE_LISTING_TIMEOUT_MS });
25
25
  const names = [];
26
26
  for (const entry of [...emulators, ...unhealthy.filter((candidate) => candidate.kind === "emulator")]) {
27
- const name = getAvdNameForSerial(entry.serial, { timeoutMs: DEVICE_LISTING_TIMEOUT_MS });
27
+ const name = await getAvdNameForSerialAsync(entry.serial, { timeoutMs: DEVICE_LISTING_TIMEOUT_MS });
28
28
  if (name === null) return () => true;
29
29
  names.push(name);
30
30
  }
31
31
  return (device) => typeof device.avdName === "string" && names.includes(device.avdName);
32
32
  }
33
- const booted = new Set(listAllIosSims({ timeoutMs: DEVICE_LISTING_TIMEOUT_MS }).filter((sim) => sim.state === "Booted").map((sim) => sim.udid));
33
+ const booted = new Set((await listAllIosSimsAsync({ timeoutMs: DEVICE_LISTING_TIMEOUT_MS })).filter((sim) => sim.state === "Booted").map((sim) => sim.udid));
34
34
  return (device) => typeof device.deviceUdid === "string" && booted.has(device.deviceUdid);
35
35
  };
36
- return (device) => {
37
- try {
38
- listing ??= list();
39
- return listing(device);
40
- } catch {
41
- listing = () => true;
42
- return true;
43
- }
36
+ return async (device) => {
37
+ listing ??= list().catch(() => () => true);
38
+ return (await listing)(device);
44
39
  };
45
40
  }
46
- function siblingPlatformSlots(root, platform, slot = "default", { deviceRunning = ownedDeviceRunning(platform) } = {}) {
41
+ async function siblingPlatformSlots(root, platform, slot = "default", { deviceRunning = ownedDeviceRunning(platform) } = {}) {
47
42
  const slots = /* @__PURE__ */ new Set();
48
43
  const state = readWorkspaceState$1(root);
49
44
  for (const hosted of Object.keys(hostedNativeRecords(state, platform))) slots.add(hosted);
@@ -56,7 +51,7 @@ function siblingPlatformSlots(root, platform, slot = "default", { deviceRunning
56
51
  }
57
52
  for (const { slot: other, platforms } of projectDeviceSlots(getProject(root))) {
58
53
  const device = platforms[platform];
59
- if (other !== slot && !slots.has(other) && device && deviceRunning(device)) slots.add(other);
54
+ if (other !== slot && !slots.has(other) && device && await deviceRunning(device)) slots.add(other);
60
55
  }
61
56
  slots.delete(slot);
62
57
  return [...slots].toSorted();
@@ -2,7 +2,6 @@ import { basename, dirname, join } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  //#region src/spawn-entry.ts
4
4
  const DEV_ENTRIES = {
5
- "api-run": "./api-run.ts",
6
5
  "supervisor-run": "./supervisor/run.ts",
7
6
  "collector-run": "./collector/run.ts",
8
7
  "web-run": "./web/run.ts",
@@ -0,0 +1,200 @@
1
+ import { h as withDrainingCancellation, t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { f as throwIfCancelled } from "./operation-exec-BW0em61G.mjs";
3
+ import { d as runCancellationSignal } from "./native-run-NwUuxbkg.mjs";
4
+ import { existsSync, lstatSync, promises, readdirSync, realpathSync, statSync } from "node:fs";
5
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { validMacosResourceDestination } from "@stim-cli/core";
7
+ //#region src/macos/stage.ts
8
+ async function validateInfoPlist(context, root, product, infoPlist) {
9
+ const source = resolve(root, infoPlist);
10
+ const inside = relative(realpathSync(root), realpathSync(source));
11
+ if (!lstatSync(source).isFile() || inside === ".." || inside.startsWith(`..${sep}`) || isAbsolute(inside)) throw new Error("macos.infoPlist must be a regular file inside the project, not a symbolic link. See stim guide macos.");
12
+ const plist = JSON.parse(await tool(context, "plutil", [
13
+ "-convert",
14
+ "json",
15
+ "-o",
16
+ "-",
17
+ source
18
+ ], { timeoutMs: 1e4 }));
19
+ if (typeof plist.CFBundleIdentifier !== "string" || plist.CFBundleExecutable !== product) throw new Error("macos.infoPlist must name a CFBundleIdentifier and the selected product as CFBundleExecutable.");
20
+ if (plist.CFBundleURLTypes || plist.SUFeedURL) throw new Error("Use a development Info.plist without shared URL schemes or an update feed.");
21
+ if (plist.LSMinimumSystemVersion !== void 0 && typeof plist.LSMinimumSystemVersion !== "string") throw new Error("macos.infoPlist LSMinimumSystemVersion must be a string. See stim guide macos.");
22
+ return {
23
+ bundleId: plist.CFBundleIdentifier,
24
+ minimumSystemVersion: plist.LSMinimumSystemVersion
25
+ };
26
+ }
27
+ async function setBundleName(context, plistPath, name) {
28
+ for (const key of ["CFBundleDisplayName", "CFBundleName"]) await tool(context, "plutil", [
29
+ "-replace",
30
+ key,
31
+ "-string",
32
+ name,
33
+ plistPath
34
+ ], { timeoutMs: 1e4 });
35
+ }
36
+ async function reidentifyBundle(context, bundle, id, name) {
37
+ const plist = join(bundle, "Contents", "Info.plist");
38
+ await tool(context, "plutil", [
39
+ "-replace",
40
+ "CFBundleIdentifier",
41
+ "-string",
42
+ id,
43
+ plist
44
+ ], { timeoutMs: 1e4 });
45
+ if (name !== void 0) await setBundleName(context, plist, name);
46
+ await tool(context, "codesign", [
47
+ "--force",
48
+ "--sign",
49
+ "-",
50
+ bundle
51
+ ], { timeoutMs: "unbounded" });
52
+ }
53
+ function resourceError(key, entry, reason) {
54
+ throw new Error(`${key} entry ${JSON.stringify(entry)}: ${reason}. See stim guide macos.`);
55
+ }
56
+ function containsSymlink(dir) {
57
+ return readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isSymbolicLink() || entry.isDirectory() && containsSymlink(join(dir, entry.name)));
58
+ }
59
+ function overlaps(a, b) {
60
+ a = a.normalize("NFC").toLowerCase();
61
+ b = b.normalize("NFC").toLowerCase();
62
+ return a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
63
+ }
64
+ function resolveBundleExtras(root, repository, resources = {}, assetCatalog) {
65
+ const boundary = realpathSync(repository);
66
+ const sourcePath = (key, entry) => {
67
+ if (typeof entry !== "string" || !entry || isAbsolute(entry) || entry.includes("\0")) resourceError(key, entry, "source must be a non-empty relative path");
68
+ let source;
69
+ try {
70
+ source = realpathSync(resolve(root, entry));
71
+ } catch {
72
+ resourceError(key, entry, "source does not exist");
73
+ }
74
+ const path = relative(boundary, source);
75
+ if (path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path)) resourceError(key, entry, "source leaves the repository");
76
+ if (path === "") resourceError(key, entry, "source is the repository root");
77
+ const stat = statSync(source);
78
+ if (!stat.isFile() && !stat.isDirectory()) resourceError(key, entry, "source must be a regular file or directory");
79
+ if (stat.isDirectory() && containsSymlink(source)) resourceError(key, entry, "source directory contains a symbolic link");
80
+ return source;
81
+ };
82
+ let catalog;
83
+ if (assetCatalog !== void 0 && assetCatalog !== null) {
84
+ catalog = sourcePath("macos.assetCatalog", assetCatalog);
85
+ if (!catalog.endsWith(".xcassets") || !statSync(catalog).isDirectory()) resourceError("macos.assetCatalog", assetCatalog, "catalog must be a .xcassets directory");
86
+ }
87
+ if (!resources || typeof resources !== "object" || Array.isArray(resources)) resourceError("macos.resources", resources, "expected an object");
88
+ const entries = Object.entries(resources);
89
+ if (entries.length > 256) {
90
+ const [destination, source] = entries[256];
91
+ resourceError(`macos.resources[${JSON.stringify(destination)}]`, source, "at most 256 entries are allowed");
92
+ }
93
+ const reserved = catalog ? ["Assets.car"] : [];
94
+ const resolved = [];
95
+ for (const [destination, source] of entries) {
96
+ const key = `macos.resources[${JSON.stringify(destination)}]`;
97
+ if (!validMacosResourceDestination(destination)) resourceError(key, source, "invalid destination");
98
+ if (reserved.some((other) => overlaps(destination, other))) resourceError(key, source, "destination collides with another resource");
99
+ reserved.push(destination);
100
+ resolved.push([destination, sourcePath(key, source)]);
101
+ }
102
+ return {
103
+ resources: Object.fromEntries(resolved),
104
+ assetCatalog: catalog
105
+ };
106
+ }
107
+ async function stageBundle(context, root, product, infoPlist, bin, bundle, bundleId, extras = { resources: {} }, displayName) {
108
+ const signal = runCancellationSignal(context) ?? context.signal;
109
+ await withDrainingCancellation(context, signal, async () => {
110
+ throwIfCancelled(signal, "macOS bundle staging");
111
+ const { minimumSystemVersion } = await validateInfoPlist(context, root, product, infoPlist);
112
+ for (const entry of readdirSync(bin).filter((name) => name.endsWith(".bundle"))) for (const [destination, source] of Object.entries(extras.resources)) if (overlaps(destination, entry)) resourceError(`macos.resources[${JSON.stringify(destination)}]`, source, `destination collides with ${entry}`);
113
+ await promises.rm(bundle, {
114
+ recursive: true,
115
+ force: true
116
+ });
117
+ const contents = join(bundle, "Contents");
118
+ await promises.mkdir(join(contents, "MacOS"), { recursive: true });
119
+ await promises.mkdir(join(contents, "Resources"), { recursive: true });
120
+ await promises.mkdir(join(contents, "Frameworks"), { recursive: true });
121
+ const executable = join(contents, "MacOS", product);
122
+ await copy(context, join(bin, product), executable);
123
+ await copy(context, resolve(root, infoPlist), join(contents, "Info.plist"));
124
+ await tool(context, "/usr/libexec/PlistBuddy", [
125
+ "-c",
126
+ `Set :CFBundleIdentifier ${bundleId}`,
127
+ join(contents, "Info.plist")
128
+ ], { timeoutMs: 1e4 });
129
+ if (displayName !== void 0) await setBundleName(context, join(contents, "Info.plist"), displayName);
130
+ for (const entry of readdirSync(bin)) if (entry.endsWith(".framework")) {
131
+ const target = join(contents, "Frameworks", entry);
132
+ await copy(context, join(bin, entry), target, {
133
+ recursive: true,
134
+ dereference: false,
135
+ verbatimSymlinks: true
136
+ });
137
+ await tool(context, "codesign", [
138
+ "--force",
139
+ "--sign",
140
+ "-",
141
+ target
142
+ ], { timeoutMs: "unbounded" });
143
+ } else if (entry.endsWith(".bundle")) await copy(context, join(bin, entry), join(contents, "Resources", entry), { recursive: true });
144
+ const frameworkPath = "@executable_path/../Frameworks";
145
+ if (!(await tool(context, "otool", ["-l", executable], { timeoutMs: 3e4 })).includes(frameworkPath)) await tool(context, "install_name_tool", [
146
+ "-add_rpath",
147
+ frameworkPath,
148
+ executable
149
+ ], { timeoutMs: 3e4 });
150
+ for (const [destination, source] of Object.entries(extras.resources)) {
151
+ const target = join(contents, "Resources", destination);
152
+ await promises.mkdir(dirname(target), { recursive: true });
153
+ await copy(context, source, target, { recursive: true });
154
+ }
155
+ if (extras.assetCatalog) {
156
+ await tool(context, "xcrun", [
157
+ "actool",
158
+ extras.assetCatalog,
159
+ "--compile",
160
+ join(contents, "Resources"),
161
+ "--platform",
162
+ "macosx",
163
+ ...minimumSystemVersion === void 0 ? [] : ["--minimum-deployment-target", minimumSystemVersion],
164
+ "--output-partial-info-plist",
165
+ "/dev/null"
166
+ ], { timeoutMs: "unbounded" });
167
+ if (!existsSync(join(contents, "Resources", "Assets.car"))) resourceError("macos.assetCatalog", extras.assetCatalog, "actool did not produce Assets.car");
168
+ }
169
+ await tool(context, "codesign", [
170
+ "--force",
171
+ "--sign",
172
+ "-",
173
+ bundle
174
+ ], { timeoutMs: "unbounded" });
175
+ });
176
+ }
177
+ async function tool(context, file, args, options) {
178
+ const signal = runCancellationSignal(context) ?? context.signal;
179
+ throwIfCancelled(signal, "macOS bundle staging");
180
+ const result = await getExecutor().runFileAsync(file, args, {
181
+ ...options,
182
+ declareFor: context
183
+ });
184
+ throwIfCancelled(signal, "macOS bundle staging");
185
+ return result;
186
+ }
187
+ async function copy(context, source, target, options = {}) {
188
+ const signal = runCancellationSignal(context) ?? context.signal;
189
+ throwIfCancelled(signal, "macOS bundle staging");
190
+ await promises.cp(source, target, {
191
+ ...options,
192
+ filter: () => {
193
+ throwIfCancelled(signal, "macOS bundle staging");
194
+ return true;
195
+ }
196
+ });
197
+ throwIfCancelled(signal, "macOS bundle staging");
198
+ }
199
+ //#endregion
200
+ export { validateInfoPlist as a, stageBundle as i, resolveBundleExtras as n, setBundleName as r, reidentifyBundle as t };