stim 1.20.2 → 1.21.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 (217) hide show
  1. package/README.md +88 -8
  2. package/dist/acquire-artifact-CD4lbiWE.mjs +153 -0
  3. package/dist/act-DHAw2A2S.mjs +2667 -0
  4. package/dist/activity-BzVfHSrY.mjs +1376 -0
  5. package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-zh1vhbLp.mjs} +21 -65
  6. package/dist/{android-HqP1_vB_.mjs → android-BEJ8Jpl7.mjs} +2 -2
  7. package/dist/{android-DCKZrNvV.mjs → android-BLgbNqox.mjs} +128 -78
  8. package/dist/{android-Dlzxshgp.mjs → android-CV_GCELZ.mjs} +5 -5
  9. package/dist/{android-Mz_Inn3w.mjs → android-DUYkNF4u.mjs} +184 -102
  10. package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-Ct5b1xCK.mjs} +7 -6
  11. package/dist/android-cas-compiler.mjs +2 -2
  12. package/dist/android-project-BCAAmMwz.mjs +12 -0
  13. package/dist/api.d.mts +740 -8
  14. package/dist/api.mjs +585 -1
  15. package/dist/{artifact-HSwkIWEQ.mjs → artifact-B8T3S5gi.mjs} +223 -201
  16. package/dist/{artifact-D3czlUvT.mjs → artifact-DAuZ-FNU.mjs} +158 -148
  17. package/dist/{browser-web-CA-F1GQo.mjs → browser-web-QQzVjz3O.mjs} +26 -24
  18. package/dist/budget-Bs6SxxzO.mjs +9154 -0
  19. package/dist/{build-DYDbfkk5.mjs → build-CoPzQRNw.mjs} +144 -96
  20. package/dist/build-cache-DmyR9Zzc.mjs +602 -0
  21. package/dist/build-plan-CaFskB7_.mjs +188 -0
  22. package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DkkqguoK.mjs} +2 -2
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/{ccache-zdKiYQ3E.mjs → ccache-BJRZ9pG3.mjs} +10 -9
  25. package/dist/{cdp-Dq_ypAlJ.mjs → cdp-CWmIUMbw.mjs} +18 -5
  26. package/dist/{chrome-BnzZMqsR.mjs → chrome-B6tfCta1.mjs} +7 -4
  27. package/dist/{cli-CLP3diBm.mjs → cli-0DYf8QhQ.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/client-B7QVOlCr.d.mts +253 -0
  30. package/dist/client-UXD70ZbM.mjs +1406 -0
  31. package/dist/collector-run.d.mts +4 -40
  32. package/dist/collector-run.mjs +9 -8
  33. package/dist/{command-output-BTy8hZ0F.mjs → command-output-B1UrjZHL.mjs} +1 -1
  34. package/dist/config-CYcBF478.mjs +949 -0
  35. package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-CqeBlrEn.mjs} +3 -3
  36. package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-BbKQW83h.mjs} +20 -5
  37. package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-DFRyG1_o.mjs} +1 -1
  38. package/dist/{dev-client-DAWVIGBu.mjs → dev-client-UOeESKm6.mjs} +2 -2
  39. package/dist/device-DCxH7_By.mjs +1068 -0
  40. package/dist/{device-BECOiufl.mjs → device-ExJq8Ei7.mjs} +35 -35
  41. package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-CMlqEcvw.mjs} +43 -13
  42. package/dist/device-host-worker.mjs +65 -61
  43. package/dist/{device-ios-COSi6oS1.mjs → device-ios-DRUeKaFV.mjs} +48 -45
  44. package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-C8raGFoP.mjs} +14 -26
  45. package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-DMRpVX9a.mjs} +5 -5
  46. package/dist/doctor-BLHCYxzi.mjs +2 -0
  47. package/dist/{doctor-kfMBnUw6.mjs → doctor-DTvaDOda.mjs} +281 -317
  48. package/dist/{doctor-CB8oZKCk.mjs → doctor-Dhqebm0q.mjs} +183 -91
  49. package/dist/doctor-fingerprint.mjs +19 -0
  50. package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-Cv1F10Kj.mjs} +40 -21
  51. package/dist/{eas-build-JyfqyHfC.mjs → eas-build-BomfRnFT.mjs} +53 -20
  52. package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-DJwZpy0c.mjs} +26 -208
  53. package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-op6A54yi.mjs} +229 -11
  54. package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-Bf0rZvG9.mjs} +172 -82
  55. package/dist/exec-H20xSg2T.d.mts +65 -0
  56. package/dist/exec-_UbtCQcG.mjs +750 -0
  57. package/dist/gc-C-WwL0yi.mjs +3 -0
  58. package/dist/{gc-qWOMdnER.mjs → gc-_-dCXdyL.mjs} +584 -796
  59. package/dist/git-C3iTsJaZ.mjs +73 -0
  60. package/dist/{guide-G9cAbVAc.mjs → guide-Yqwt2bd6.mjs} +941 -269
  61. package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-Bw-honsd.mjs} +8 -6
  62. package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DB_gBPfY.mjs} +34 -19
  63. package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CUvOf4Vr.mjs} +1 -1
  64. package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-DL_P5AdN.mjs} +77 -43
  65. package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-QI141yKk.mjs} +21 -17
  66. package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-Ksyjgzq-.mjs} +30 -21
  67. package/dist/idle-BVeRGroT.d.mts +24 -0
  68. package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DaKmZi0z.mjs} +11 -10
  69. package/dist/{ios-BwVCF7oA.mjs → ios-CQ68hG9s.mjs} +8 -8
  70. package/dist/{ios-RkW4pnQf.mjs → ios-CpByZy12.mjs} +140 -80
  71. package/dist/{ios-device-B5veSDDQ.mjs → ios-device-CXGP1bsD.mjs} +1 -1
  72. package/dist/{ios-device-D7pi2Sca.mjs → ios-device-CwFMehUS.mjs} +51 -26
  73. package/dist/{ios-project-K9hY_Jab.mjs → ios-project-WuwwBdvW.mjs} +13 -13
  74. package/dist/{ios-nOLJGVdy.mjs → ios-qNJt4dFm.mjs} +1 -1
  75. package/dist/ios-signing-DTTIChGs.mjs +489 -0
  76. package/dist/{ios-state-CBLe1xYw.mjs → ios-state-DvFX-K_l.mjs} +1 -1
  77. package/dist/{ios-Ce7bc7br.mjs → ios-ubFsBzwq.mjs} +129 -86
  78. package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Cc1dttps.mjs} +53 -26
  79. package/dist/{launch-F4sOqAhB.mjs → launch-CD1yVc7U.mjs} +91 -90
  80. package/dist/{launch-C3qJ6Agb.mjs → launch-Zq2mOSDy.mjs} +82 -541
  81. package/dist/logs-BS00Anxf.mjs +352 -0
  82. package/dist/logs-CMm05HxN.mjs +255 -0
  83. package/dist/{macos-D7uDvO-z.mjs → macos-B65--pPd.mjs} +1 -1
  84. package/dist/{macos-Ch5VJmcS.mjs → macos-C-0qJ6zq.mjs} +225 -212
  85. package/dist/macos-run.mjs +1 -1
  86. package/dist/maintenance-run.mjs +122 -247
  87. package/dist/{metro-DnCEjCxs.mjs → metro-DEXpIhHC.mjs} +67 -12
  88. package/dist/{metro-gateway-CX9Xlkq2.mjs → metro-gateway-BMJNlj3E.mjs} +20 -12
  89. package/dist/{named-ports-4WopRPg-.mjs → named-ports-BWTzt6mu.mjs} +8 -63
  90. package/dist/native-android-JACyjTZs.mjs +844 -0
  91. package/dist/{native-gradle-inputs-BsLRrl7u.mjs → native-gradle-inputs-Bep9JcSF.mjs} +128 -140
  92. package/dist/native-inputs-TRTTTRxt.mjs +91 -0
  93. package/dist/native-run-DY_RLx3C.mjs +277 -0
  94. package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-Dg1Q7tfF.mjs} +9 -8
  95. package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-CB2iQeWq.mjs} +27 -18
  96. package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-CXX39F7o.mjs} +96 -47
  97. package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
  98. package/dist/offload-worker.d.mts +1 -46
  99. package/dist/offload-worker.mjs +197 -66
  100. package/dist/{ownership-DCtw_2IA.mjs → ownership-DEmM5vhh.mjs} +3 -3
  101. package/dist/{page-DRHy329N.mjs → page-CPaHeYqj.mjs} +7 -4
  102. package/dist/paths-BsJMoPP2.mjs +12 -0
  103. package/dist/paths-DQtTgsBf.mjs +42 -0
  104. package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BqGbTa61.mjs} +5 -5
  105. package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-Bwj-IjY1.mjs} +6 -6
  106. package/dist/{ports-DdSUicVo.mjs → ports-D-MmCTdv.mjs} +3 -3
  107. package/dist/prebuild-uD_ipCxF.mjs +449 -0
  108. package/dist/{project-_phNIJfs.mjs → project-BZNjmW_8.mjs} +65 -37
  109. package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-Lfetn8Kr.mjs} +2 -2
  110. package/dist/pull-request-zjCSAryH.d.mts +120 -0
  111. package/dist/pull-requests.d.mts +1 -119
  112. package/dist/pull-requests.mjs +1 -1
  113. package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-DuzH0cn3.mjs} +74 -48
  114. package/dist/{gradle-DSrXb6lG.mjs → react-native-build-rhk4smwQ.mjs} +292 -15
  115. package/dist/react-native-doctor-CQpuIMso.mjs +234 -0
  116. package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-Bhq1rJeV.mjs} +46 -28
  117. package/dist/{recordings-D0d5aQt0.mjs → recordings-DYteQSu4.mjs} +12 -9
  118. package/dist/{reload-C8JhxjSh.mjs → reload-CmTRFJaX.mjs} +93 -47
  119. package/dist/reload-DzjSl5P_.mjs +2 -0
  120. package/dist/{remote-BiR6aYjy.mjs → remote-ByYkXdGD.mjs} +15 -10
  121. package/dist/result-DNiS-tTP.mjs +434 -0
  122. package/dist/{run-BtPgpKks.mjs → run-D23HmJMs.mjs} +4 -5
  123. package/dist/selection-CSl9i5qU.mjs +619 -0
  124. package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CxTrvDg8.mjs} +3 -4
  125. package/dist/{server-command-CTtCkmcQ.mjs → server-command-CtzloH3v.mjs} +14 -7
  126. package/dist/server-expo-C-90EhcG.mjs +2 -0
  127. package/dist/{server-expo-DsguMGUF.mjs → server-expo-DT_F_uVI.mjs} +50 -9
  128. package/dist/{settings-B717odTD.mjs → settings-CsJDEXgK.mjs} +234 -24
  129. package/dist/{settings-vk3mJGSm.d.mts → settings-DkdmlelE.d.mts} +6 -4
  130. package/dist/settings-T1gtc3bf.mjs +114 -0
  131. package/dist/settings-write-HyVZ8eQ8.mjs +359 -0
  132. package/dist/settings.schema.json +163 -16
  133. package/dist/{simslim-CCr3rE-A.mjs → simslim-Cgk17SXV.mjs} +14 -12
  134. package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-DF8VfT64.mjs} +15 -20
  135. package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
  136. package/dist/stage-BIS0ydsV.mjs +183 -0
  137. package/dist/{start-BWqzODpb.mjs → start-7lpH7hmN.mjs} +63 -44
  138. package/dist/{start-TXeMmmO2.mjs → start-RChynRDp.mjs} +1 -1
  139. package/dist/{state-D1Icyjlu.mjs → state-C4ZtUisW.mjs} +40 -13
  140. package/dist/{state-CG_OFoaA.mjs → state-XMziexv2.mjs} +3 -2
  141. package/dist/{stats-BoY5sEPU.mjs → stats-53T7OTb9.mjs} +7 -13
  142. package/dist/stats-report-BFfMpWWF.mjs +16 -0
  143. package/dist/{status-WgFbkRzj.mjs → status-BL7jVyAB.mjs} +535 -447
  144. package/dist/status-CSi6tlRq.mjs +2 -0
  145. package/dist/{status-BTA7kKiQ.mjs → status-DqEUSSxs.mjs} +6 -4
  146. package/dist/{status-watch-C23ILtf9.mjs → status-watch-GDCfqpTE.mjs} +187 -22
  147. package/dist/status-worker.d.mts +1 -0
  148. package/dist/status-worker.mjs +19 -0
  149. package/dist/stim-desktop-C12we7lz.mjs +112 -0
  150. package/dist/{stop-DR6VoDIk.mjs → stop-Bk_1qiV6.mjs} +2 -2
  151. package/dist/{stop-BNmBMi1F.mjs → stop-CPzlM1L-.mjs} +138 -98
  152. package/dist/{stop-DPEhunlw.mjs → stop-D7h6jAXQ.mjs} +11 -10
  153. package/dist/supervisor-run.d.mts +8 -17
  154. package/dist/supervisor-run.mjs +63 -27
  155. package/dist/{support-DMTqj3Hm.mjs → support-67vraa1Q.mjs} +18 -11
  156. package/dist/{support-CwjbFs9H.mjs → support-Dlu37g6H.mjs} +12 -12
  157. package/dist/{swiftpm-macos-DRNVJWlb.mjs → swiftpm-macos-p8WZbxKU.mjs} +35 -24
  158. package/dist/toolchain-DhKwp9iI.mjs +2 -0
  159. package/dist/toolchain-Hp9sCpK4.mjs +873 -0
  160. package/dist/{trigger-CigAYjeL.mjs → trigger-BAahxUPq.mjs} +20 -5
  161. package/dist/trigger-Bf3uDcpv.mjs +2 -0
  162. package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-BHX5r0Ei.mjs} +250 -156
  163. package/dist/{web-BDBMxDpx.mjs → web-CJmIj6AI.mjs} +18 -13
  164. package/dist/web-DknQETPs.mjs +2 -0
  165. package/dist/web-run.mjs +11 -12
  166. package/dist/windows-report.d.mts +1 -0
  167. package/dist/windows-report.mjs +18 -0
  168. package/dist/windows-report.ps1 +43 -0
  169. package/dist/workspace-process-lock-1_1OoVW5.mjs +57 -0
  170. package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-Cjuigeeu.mjs} +62 -58
  171. package/dist/{workspaces-C36s2jb9.mjs → workspaces-BccMFmGQ.mjs} +1188 -1079
  172. package/dist/worktree-CK2MpJW5.mjs +2 -0
  173. package/dist/{worktree-CgvJYJ-Q.mjs → worktree-DQ6Zi2Mv.mjs} +304 -53
  174. package/dist/xcode-Zlx3qjEs.mjs +896 -0
  175. package/package.json +7 -5
  176. package/shim/android-optimizations.gradle +7 -5
  177. package/dist/activity-BSV745Kz.mjs +0 -629
  178. package/dist/api-qvOzWyfO.mjs +0 -154
  179. package/dist/api-run.mjs +0 -294
  180. package/dist/app-install-BIKtMfPq.mjs +0 -896
  181. package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
  182. package/dist/budget-f7516Zk0.mjs +0 -4106
  183. package/dist/build-facts-DcLv2HSd.d.mts +0 -111
  184. package/dist/cancellation-C_22VQTH.mjs +0 -24
  185. package/dist/client-qQAaXSUs.mjs +0 -1771
  186. package/dist/config-BYDxlMY3.mjs +0 -562
  187. package/dist/device-DuiPJQSn.mjs +0 -290
  188. package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
  189. package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
  190. package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
  191. package/dist/exec-DqKo9GKJ.mjs +0 -268
  192. package/dist/git-DDfFzkMm.mjs +0 -45
  193. package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
  194. package/dist/logs-BGrEUaEs.mjs +0 -383
  195. package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
  196. package/dist/native-android-D5qc3-_v.mjs +0 -226
  197. package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
  198. package/dist/plan-C4TjdPsR.mjs +0 -260
  199. package/dist/prebuild-DYbucPXy.mjs +0 -212
  200. package/dist/preview-78a9kR_-.mjs +0 -1011
  201. package/dist/react-native-build-CtCccJtb.mjs +0 -239
  202. package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
  203. package/dist/remote-cache-OyOyVIS3.mjs +0 -526
  204. package/dist/result-CaJg5Iat.mjs +0 -186
  205. package/dist/server-expo-Bigriskl.mjs +0 -2
  206. package/dist/settings-BORNaaCO.mjs +0 -402
  207. package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
  208. package/dist/stage-KNTQopqv.mjs +0 -157
  209. package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
  210. package/dist/tailnet-Dh-qiYzG.mjs +0 -265
  211. package/dist/toolchain-BFkAcstd.mjs +0 -2
  212. package/dist/toolchain-DxSsNssu.mjs +0 -1657
  213. package/dist/trigger-9_USgmxz.mjs +0 -2
  214. package/dist/web-Dq-i3wzJ.mjs +0 -2
  215. package/dist/worktree-DpLdCHga.mjs +0 -2
  216. package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
  217. package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
@@ -1,236 +1,19 @@
1
- import { F as listMountedVolumes, N as formatBytes, P as isOnMountedVolume, _ as loadConfig$1 } from "./config-BYDxlMY3.mjs";
2
- import { a as unregister, n as readManifest } from "./cache-manifest-XH-fvDUj.mjs";
3
- import { T as canonicalPath, a as collectWorkspaceOutputs, i as collectOrphanedWorkspaces, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs, w as takeGcResults } from "./workspaces-C36s2jb9.mjs";
4
- import { N as emptyCaches, at as discoverCaches, l as resolveBudget, ot as pruneCache, r as cacheLabel, z as planCacheEmptying } from "./budget-f7516Zk0.mjs";
5
- import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
6
- import { t as relaunchWithLogFile } from "./detached-entry-B9C_zeQC.mjs";
7
- import { F as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-RkW4pnQf.mjs";
1
+ import { P as formatBytes } from "./config-CYcBF478.mjs";
2
+ import { Tt as deviceSweepIsScoped, u as resolveBudget } from "./budget-Bs6SxxzO.mjs";
3
+ import { I as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-CpByZy12.mjs";
4
+ import { h as maintenanceLogger } from "./client-UXD70ZbM.mjs";
8
5
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
6
+ import { A as lowestFree, C as measurePressure, D as diskPressureLevel, E as sizeScanDeferred, O as levelFloors, S as measureDisk, T as measureSizes, k as levelStillShort } from "./worktree-DQ6Zi2Mv.mjs";
7
+ import { i as plannedMaintenance, m as measureOwnedDevices, n as diskRecovered, o as triggeringRoot, r as executeAction } from "./act-DHAw2A2S.mjs";
8
+ import { t as relaunchWithLogFile } from "./detached-entry-DFRyG1_o.mjs";
9
9
  import { r as due, t as capChildLog } from "./attempt-DW-mQqM7.mjs";
10
- import { a as maintenancePinned, c as removeWorktrees, d as cacheBlocked, f as measureDisk, h as sizeScanDeferred, i as cacheEntryProtection, m as measureSizes, o as recentUse, p as measurePressure, r as triggeringRoot, t as plannedMaintenance } from "./preview-78a9kR_-.mjs";
11
- import { appendFileSync, existsSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
- import { basename, join, resolve, sep } from "node:path";
13
- import { MAINTENANCE_LOG_NAME, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState, sharedCompilationCache, workspaceLogsDir } from "@stim-cli/core/state";
10
+ import { randomBytes } from "node:crypto";
11
+ import { appendFileSync, mkdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
+ import { basename, join, resolve } from "node:path";
13
+ import { withDirLock } from "@stim-cli/core";
14
+ import { maintenanceChildLogFile, maintenanceDir, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState } from "@stim-cli/core/state";
14
15
  import { fileURLToPath } from "node:url";
15
- import { LOG_ROTATE_BYTES, buildCacheRoot, metroCacheRoot, rotatedLogPath, withDirLock } from "@stim-cli/core";
16
16
  import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
17
- //#region src/maintenance/act.ts
18
- const kept = (detail) => ({
19
- status: "kept",
20
- bytes: 0,
21
- detail
22
- });
23
- async function quietly(run) {
24
- const { log, error } = {
25
- log: console.log,
26
- error: console.error
27
- };
28
- const exitCode = process.exitCode;
29
- takeGcResults();
30
- console.log = () => {};
31
- console.error = () => {};
32
- try {
33
- return {
34
- value: await run(),
35
- results: takeGcResults()
36
- };
37
- } finally {
38
- console.log = log;
39
- console.error = error;
40
- process.exitCode = exitCode;
41
- takeGcResults();
42
- }
43
- }
44
- function outcomeOf(results, fallbackBytes) {
45
- const failed = results.find((result) => result.status === "failed");
46
- if (failed) return {
47
- status: "failed",
48
- bytes: 0,
49
- detail: failed.detail ?? `could not process ${failed.label}`
50
- };
51
- const done = results.filter((result) => result.status === "done");
52
- if (done.length) return {
53
- status: "done",
54
- bytes: done.reduce((sum, result) => sum + (result.bytes ?? 0), 0) || fallbackBytes,
55
- detail: done.map((result) => result.label).join(", ")
56
- };
57
- return kept(results.find((result) => result.detail)?.detail ?? "nothing was eligible when the action ran");
58
- }
59
- function rootCache(dir) {
60
- const name = canonicalPath(dir) === canonicalPath(buildCacheRoot()) ? "Build cache" : canonicalPath(dir) === canonicalPath(metroCacheRoot()) ? "Metro transform caches" : null;
61
- return name ? {
62
- name,
63
- dir,
64
- prune: "entries",
65
- entriesDepth: name === "Build cache" ? 2 : 3,
66
- note: ""
67
- } : null;
68
- }
69
- function cacheOf(action) {
70
- const discovered = discoverCaches();
71
- if (action.dir) {
72
- const dir = canonicalPath(action.dir);
73
- return discovered.find((cache) => canonicalPath(cache.dir) === dir) ?? rootCache(action.dir);
74
- }
75
- return discovered.find((cache) => cacheLabel(cache) === action.target) ?? null;
76
- }
77
- function trimCache(action, context) {
78
- const cache = cacheOf(action);
79
- if (!cache) return kept("it is no longer a cache Stim may trim");
80
- const [planned] = planCacheEmptying([cache], false);
81
- if (!planned || planned.machineGlobal) return kept(planned?.machineGlobal ?? "it is no longer a cache Stim may trim");
82
- const aged = action.olderThanDays !== void 0;
83
- const result = pruneCache(cache, {
84
- olderThanDays: Math.max(action.olderThanDays ?? 0, context.settings.protectRecentHours / 24),
85
- byMtime: true,
86
- protect: context.protect ??= cacheEntryProtection(),
87
- ...aged ? {} : { evictBytes: action.bytes }
88
- });
89
- if (result.skipped) return kept(result.skipped);
90
- if (result.failed) return {
91
- status: "failed",
92
- bytes: result.bytes,
93
- detail: `${result.failed} entries could not be removed`
94
- };
95
- const protectedNote = result.protectedEntries ? `; ${result.protectedEntries} protected entries kept` : "";
96
- if (result.removed === 0) return kept(`no unprotected entry was old enough${protectedNote}`);
97
- return {
98
- status: "done",
99
- bytes: result.bytes,
100
- detail: `${result.removed} entries${protectedNote}`,
101
- ...!aged && result.bytes < action.bytes ? { shortfall: `${action.target} reached ${result.bytes} of ${action.bytes} bytes${protectedNote}` } : {}
102
- };
103
- }
104
- async function emptyCompilationCache(action, context) {
105
- if (!measureDisk().some((disk) => disk.freeMb < context.budget.hardFloorDiskMb)) return kept("free disk is above budget.hardFloorDiskGb, and this cache can only be emptied whole");
106
- const dir = sharedCompilationCache();
107
- const blocked = cacheBlocked({
108
- name: "Swift compilation cache",
109
- dir,
110
- category: "compilation-cache"
111
- });
112
- if (blocked) return kept(blocked);
113
- const cache = discoverCaches().find((candidate) => canonicalPath(candidate.dir) === canonicalPath(dir));
114
- if (cache?.prune !== "atomic") return kept("it is not a registered cache Stim empties whole");
115
- const [planned] = planCacheEmptying([{
116
- ...cache,
117
- bytes: action.bytes
118
- }], true);
119
- const { results } = await quietly(() => emptyCaches(planned ? [planned] : []));
120
- return outcomeOf(results, action.bytes);
121
- }
122
- async function clearOutputs(action, context) {
123
- const root = action.workspace;
124
- if (!root) return kept("the action names no workspace");
125
- if (root === context.protectedRoot) return kept("the command that started this pass runs in it");
126
- if (maintenancePinned(root)) return kept("pinned by maintenance.keep");
127
- const recent = recentUse(root, context.settings);
128
- if (recent) return kept(recent);
129
- const olderThan = action.olderThanDays ?? null;
130
- const now = Date.now();
131
- const report = collectWorkspaceOutputs({
132
- olderThan,
133
- now,
134
- measure: false
135
- });
136
- const entry = report.workspaces.find((candidate) => candidate.projectRoot && canonicalPath(candidate.projectRoot) === root);
137
- if (!entry) return kept("it has no build outputs any more");
138
- const { results } = await quietly(() => clearWorkspaceOutputs({
139
- ...report,
140
- workspaces: [entry]
141
- }, {
142
- olderThan,
143
- now
144
- }));
145
- return outcomeOf(results, action.bytes);
146
- }
147
- async function removeWorktree(action, context) {
148
- const sweep = context.worktreeSweep;
149
- const worktree = sweep?.worktrees.find((candidate) => candidate.path === action.target);
150
- if (!sweep || !worktree) return kept("it is not in this pass's worktree check");
151
- const path = canonicalPath(worktree.path);
152
- if (context.protectedRoot === path || context.protectedRoot.startsWith(`${path}${sep}`)) return kept("the command that started this pass runs inside it");
153
- if (worktree.keys.some(maintenancePinned)) return kept("pinned by maintenance.keep");
154
- const { results } = await quietly(() => removeWorktrees({
155
- ...sweep,
156
- worktrees: [worktree]
157
- }));
158
- return outcomeOf(results, 0);
159
- }
160
- async function removeOrphan(action) {
161
- const orphan = collectOrphanedWorkspaces(Object.keys(loadConfig$1()?.projects ?? {}), listMountedVolumes()).orphaned.find((candidate) => candidate.dir === action.target);
162
- if (!orphan) return kept("it is no longer an orphaned workspace directory");
163
- const { results } = await quietly(() => deleteOrphanedWorkspaces([orphan]));
164
- return outcomeOf(results, orphan.bytes ?? 0);
165
- }
166
- function unregisterCache(action) {
167
- const dir = action.dir ?? action.target;
168
- if (existsSync(dir) || !isOnMountedVolume(dir, listMountedVolumes()) || !readManifest().caches.some((c) => c.dir === dir)) return kept("it can no longer be shown to be a stale registration");
169
- return unregister(dir) ? {
170
- status: "done",
171
- bytes: 0,
172
- detail: dir
173
- } : kept("it was already unregistered");
174
- }
175
- async function executeAction(action, context) {
176
- switch (action.kind) {
177
- case "would-clear-outputs": return clearOutputs(action, context);
178
- case "would-trim-cache": return trimCache(action, context);
179
- case "would-empty-cache": return emptyCompilationCache(action, context);
180
- case "would-remove-worktree": return removeWorktree(action, context);
181
- case "would-remove-orphan": return removeOrphan(action);
182
- case "would-unregister-cache": return unregisterCache(action);
183
- default: return kept("automatic maintenance does not stop devices or dev servers yet");
184
- }
185
- }
186
- function diskRecovered(budget) {
187
- const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
188
- return measureDisk().every((disk) => disk.freeMb >= floor);
189
- }
190
- //#endregion
191
- //#region src/maintenance/log.ts
192
- function maintenanceLogger(settings, pass, trigger) {
193
- const file = maintenanceNdjsonFile();
194
- const rotated = rotatedLogPath(file);
195
- withDirLock(`${file}.lock`, () => {
196
- try {
197
- if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
198
- } catch {}
199
- });
200
- const writer = createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
201
- return {
202
- write(event, level, msg, fields = {}) {
203
- if (level === "debug" && !settings.logChecks) return null;
204
- const record = {
205
- ...fields,
206
- ts: Date.now(),
207
- src: "maintenance",
208
- level,
209
- msg,
210
- event,
211
- pass,
212
- trigger,
213
- mode: settings.mode === "on" ? "on" : "report"
214
- };
215
- if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
216
- if (typeof fields.workspace === "string" && [
217
- "maintenance_action",
218
- "maintenance_failure",
219
- "maintenance_skip"
220
- ].includes(event)) {
221
- const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
222
- try {
223
- if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
224
- } finally {
225
- workspace.close();
226
- }
227
- }
228
- return record;
229
- },
230
- close: () => writer.close()
231
- };
232
- }
233
- //#endregion
234
17
  //#region src/maintenance/run.ts
235
18
  function writeState(state) {
236
19
  mkdirSync(maintenanceDir(), { recursive: true });
@@ -247,14 +30,65 @@ function writeState(state) {
247
30
  }
248
31
  });
249
32
  }
33
+ const RESERVE_BYTES = 1048576;
34
+ const reserveFile = () => join(maintenanceDir(), "disk-reserve");
35
+ function releaseReserve() {
36
+ try {
37
+ const bytes = statSync(reserveFile()).size;
38
+ rmSync(reserveFile());
39
+ return bytes > 0;
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+ function keepReserve() {
45
+ try {
46
+ if (statSync(reserveFile()).size === RESERVE_BYTES) return;
47
+ } catch {}
48
+ try {
49
+ mkdirSync(maintenanceDir(), { recursive: true });
50
+ writeFileSync(reserveFile(), randomBytes(RESERVE_BYTES));
51
+ } catch {
52
+ try {
53
+ rmSync(reserveFile(), { force: true });
54
+ } catch {}
55
+ }
56
+ }
57
+ function claimPass(trigger) {
58
+ const take = () => {
59
+ const attempt = tryAcquireClaim({
60
+ root: maintenanceRunClaims(),
61
+ mode: "exclusive",
62
+ label: "maintenance",
63
+ details: { trigger }
64
+ });
65
+ if (attempt.pending) releaseClaim(attempt.pending);
66
+ return attempt.acquired;
67
+ };
68
+ try {
69
+ return take();
70
+ } catch (error) {
71
+ if (!(error instanceof Error && "code" in error && (error.code === "ENOSPC" || error.code === "EDQUOT")) || !releaseReserve()) throw error;
72
+ return take();
73
+ }
74
+ }
250
75
  const EXECUTION_ORDER = {
251
76
  "would-unregister-cache": 0,
252
77
  "would-remove-orphan": 0,
253
78
  "would-clear-outputs": 1,
79
+ "would-delete-parked-device": 2,
80
+ "would-delete-temp-leftovers": 2,
254
81
  "would-trim-cache": 2,
82
+ "would-clear-build-dirs": 3,
255
83
  "would-empty-cache": 3,
256
- "would-remove-worktree": 4
84
+ "would-remove-worktree": 4,
85
+ "would-stop-workspace": 5,
86
+ "would-delete-devices": 5,
87
+ "would-delete-dependencies": 6,
88
+ "would-stop-gradle-daemons": 7,
89
+ "would-delete-gradle-version": 8
257
90
  };
91
+ const executionRank = (action) => (action.level ?? 1) * 10 + (EXECUTION_ORDER[action.kind] ?? 9);
258
92
  function shrinkSizes(state, action, outcome) {
259
93
  state.sizes = state.sizes.flatMap((size) => {
260
94
  if (action.kind === "would-clear-outputs" && size.category === "workspace-outputs" && size.workspace === action.workspace) return [];
@@ -263,6 +97,7 @@ function shrinkSizes(state, action, outcome) {
263
97
  bytes: Math.max(0, size.bytes - outcome.bytes)
264
98
  }];
265
99
  if (action.kind === "would-empty-cache" && size.dir === action.target) return [];
100
+ if (action.kind === "would-delete-devices" && outcome.status === "done" && size.category === "owned-devices" && size.workspace === action.workspace) return [];
266
101
  return [size];
267
102
  });
268
103
  }
@@ -275,6 +110,14 @@ function describeDone(action) {
275
110
  case "would-empty-cache": return `Emptied ${action.target}`;
276
111
  case "would-remove-worktree": return `Removed the worktree ${action.target}`;
277
112
  case "would-remove-orphan": return `Removed the orphaned workspace directory ${action.target}`;
113
+ case "would-delete-parked-device": return `Deleted the parked device ${action.target}`;
114
+ case "would-delete-temp-leftovers": return `Deleted the recognized leftovers in ${action.target}`;
115
+ case "would-delete-devices": return `Deleted the owned devices of ${name}`;
116
+ case "would-clear-build-dirs": return `Cleared the build directory ${action.target}`;
117
+ case "would-delete-dependencies": return `Deleted the installed dependencies ${action.target}`;
118
+ case "would-stop-gradle-daemons": return "Stopped idle Gradle and Kotlin daemons";
119
+ case "would-delete-gradle-version": return `Deleted the unpinned Gradle ${action.target} caches and distributions`;
120
+ case "would-stop-workspace": return `Stopped ${name} and deleted its owned devices`;
278
121
  default: return `Unregistered the stale cache ${action.target}`;
279
122
  }
280
123
  }
@@ -285,14 +128,7 @@ async function runMaintenance(trigger) {
285
128
  const startedAt = Date.now();
286
129
  let claim;
287
130
  try {
288
- const attempt = tryAcquireClaim({
289
- root: maintenanceRunClaims(),
290
- mode: "exclusive",
291
- label: "maintenance",
292
- details: { trigger }
293
- });
294
- if (attempt.pending) releaseClaim(attempt.pending);
295
- claim = attempt.acquired;
131
+ claim = claimPass(trigger);
296
132
  } catch (error) {
297
133
  crashLine(error);
298
134
  return;
@@ -313,9 +149,29 @@ async function runMaintenance(trigger) {
313
149
  };
314
150
  const checks = due(state, settings, startedAt);
315
151
  if (checks.length === 0) return;
316
- logger = maintenanceLogger(settings, `p-${claim.claimId}`, trigger);
152
+ let writeError = null;
153
+ const noteWriteError = (error) => {
154
+ writeError ??= error instanceof Error ? error.message : String(error);
155
+ };
156
+ const keepState = () => {
157
+ try {
158
+ writeState(state);
159
+ } catch (error) {
160
+ noteWriteError(error);
161
+ }
162
+ };
163
+ try {
164
+ logger = maintenanceLogger(settings, `p-${claim.claimId}`, trigger);
165
+ } catch (error) {
166
+ noteWriteError(error);
167
+ }
317
168
  const record = (event, level, msg, fields = {}) => {
318
- const entry = logger.write(event, level, msg, fields);
169
+ let entry = null;
170
+ try {
171
+ entry = logger?.write(event, level, msg, fields) ?? null;
172
+ } catch (error) {
173
+ noteWriteError(error);
174
+ }
319
175
  if (entry && (event === "maintenance_action" || event === "maintenance_failure" || Array.isArray(fields.blocked) && fields.blocked.length > 0)) state.recent = [...state.recent, entry].slice(-20);
320
176
  };
321
177
  const failures = [];
@@ -332,17 +188,18 @@ async function runMaintenance(trigger) {
332
188
  ...state.deferredAt,
333
189
  [check]: Date.now()
334
190
  };
335
- writeState(state);
191
+ keepState();
336
192
  continue;
337
193
  }
338
194
  state.lastAt[check] = Date.now();
339
195
  ran.add(check);
340
196
  delete state.deferredAt?.[check];
341
- writeState(state);
197
+ keepState();
342
198
  try {
343
199
  if (check === "worktree" || check === "sweep") continue;
344
200
  if (check === "pressure") {
345
201
  state.pressure = measurePressure(settings, state.pressure, state.lastAt[check]);
202
+ state.pressure.diskLevel = diskPressureLevel(lowestFree(state.pressure.disk), budget, settings);
346
203
  const culprits = settings.memoryPressureLevel === "off" ? null : memoryCulpritsUnder(state.pressure.memory.level);
347
204
  if (culprits) state.pressure.memory.culprits = culprits;
348
205
  const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
@@ -361,14 +218,15 @@ async function runMaintenance(trigger) {
361
218
  for (const culprit of state.pressure.memory.culprits ?? []) record("maintenance_check", "info", memoryCulpritAdvice([culprit]), { culprit });
362
219
  } else {
363
220
  measuredSizes = true;
364
- state.sizes = measureSizes(state.lastAt[check], (target, workspace) => {
221
+ const measureFailed = (target, workspace) => {
365
222
  failures.push(`Could not measure ${target}`);
366
223
  record("maintenance_failure", "error", `Could not measure ${target}`, {
367
224
  target,
368
225
  error: "du failed or timed out",
369
226
  ...workspace ? { workspace } : {}
370
227
  });
371
- });
228
+ };
229
+ state.sizes = [...await measureSizes(state.lastAt[check], measureFailed), ...deviceSweepIsScoped() ? [] : await measureOwnedDevices(state.lastAt[check], measureFailed)];
372
230
  for (const size of state.sizes) record("maintenance_check", "debug", `${size.name}: ${formatBytes(size.bytes)}`, {
373
231
  check: {
374
232
  kind: `size:${size.category}`,
@@ -412,10 +270,11 @@ async function runMaintenance(trigger) {
412
270
  settings,
413
271
  budget,
414
272
  protectedRoot: triggeringRoot(),
415
- worktreeSweep: result.worktreeSweep
273
+ worktreeSweep: result.worktreeSweep,
274
+ pressureSweep: result.pressureSweep
416
275
  };
417
276
  const results = [];
418
- const ordered = actions.toSorted((a, b) => (EXECUTION_ORDER[a.kind] ?? 9) - (EXECUTION_ORDER[b.kind] ?? 9));
277
+ const ordered = actions.toSorted((a, b) => executionRank(a) - executionRank(b));
419
278
  for (const action of ordered) {
420
279
  const began = Date.now();
421
280
  let outcome;
@@ -424,6 +283,10 @@ async function runMaintenance(trigger) {
424
283
  status: "kept",
425
284
  bytes: 0,
426
285
  detail: "free disk recovered before this action"
286
+ } : action.level !== void 0 && !levelStillShort(action, lowestFree(measureDisk()), budget, settings) ? {
287
+ status: "kept",
288
+ bytes: 0,
289
+ detail: `free disk is back above the level ${action.level} floor`
427
290
  } : await executeAction(action, context);
428
291
  } catch (error) {
429
292
  outcome = {
@@ -474,8 +337,15 @@ async function runMaintenance(trigger) {
474
337
  loggedSkips.add(skip.target);
475
338
  record("maintenance_skip", "info", `Kept ${skip.target}: ${skip.reason}`, skip);
476
339
  }
340
+ if (writeError) failures.push(`Could not write the maintenance state or log: ${writeError}`);
341
+ if (settings.mode !== "on" && state.pressure?.diskLevel === 3) failures.push(criticalLine(state.pressure.disk, budget, settings));
477
342
  if (settings.mode === "on") {
478
343
  const outcomes = await executePlan(result.actions);
344
+ if (state.pressure) {
345
+ state.pressure.disk = measureDisk();
346
+ state.pressure.diskLevel = diskPressureLevel(lowestFree(state.pressure.disk), budget, settings);
347
+ if (state.pressure.diskLevel === 3) failures.push(criticalLine(state.pressure.disk, budget, settings));
348
+ }
479
349
  const blockedNow = [
480
350
  ...result.blocked,
481
351
  ...failures,
@@ -498,7 +368,7 @@ async function runMaintenance(trigger) {
498
368
  blocked: blockedNow
499
369
  };
500
370
  const blockedChanged = !sameSet(new Set((previousBlocked ?? []).map(stableText)), new Set(state.lastPass.blocked.map(stableText)));
501
- if (done.length || measuredSizes || blockedChanged) record("maintenance_pass", state.lastPass.blocked.length ? "warn" : "info", `Pass: ${done.length} actions, ${formatBytes(freedBytes)} freed${state.lastPass.blocked.length ? `; ${state.lastPass.blocked.join("; ")}` : ""}`, { ...state.lastPass });
371
+ if (done.length || measuredSizes || blockedChanged || (state.pressure?.diskLevel ?? 0) > 0) record("maintenance_pass", state.lastPass.blocked.length ? "warn" : "info", `Pass: ${done.length} actions, ${formatBytes(freedBytes)} freed${state.lastPass.blocked.length ? `; ${state.lastPass.blocked.join("; ")}` : ""}`, { ...state.lastPass });
502
372
  } else {
503
373
  const blocked = [...result.blocked, ...failures];
504
374
  const planned = [...result.actions, ...retained];
@@ -541,9 +411,14 @@ async function runMaintenance(trigger) {
541
411
  crashLine(error);
542
412
  } finally {
543
413
  logger?.close();
414
+ keepReserve();
544
415
  releaseClaim(claim);
545
416
  }
546
417
  }
418
+ function criticalLine(disk, budget, settings) {
419
+ const floor = levelFloors(budget, settings)[3];
420
+ return `disk pressure level 3: ${disk.filter((volume) => volume.freeMb < floor).map((volume) => `${(volume.freeMb / 1024).toFixed(1)}G free on ${volume.volume}`).join(", ")} after this pass, under the ${(floor / 1024).toFixed(1)}G critical floor; builds refuse below budget.hardFloorDiskGb`;
421
+ }
547
422
  function crashLine(error) {
548
423
  try {
549
424
  mkdirSync(maintenanceDir(), { recursive: true });
@@ -1,6 +1,6 @@
1
- import { F as listMountedVolumes, P as isOnMountedVolume, _ as loadConfig, k as process_identity_exports, n as allMetroPorts, r as claimMetroPort, x as releaseMetroPort } from "./config-BYDxlMY3.mjs";
2
- import { t as getExecutor } from "./exec-DqKo9GKJ.mjs";
3
- import { r as readWorkspaceState } from "./workspace-state-DJt_MMvf.mjs";
1
+ import { p as process_identity_exports, t as getExecutor } from "./exec-_UbtCQcG.mjs";
2
+ import { F as isOnMountedVolume, I as listMountedVolumes, _ as loadConfig, n as allMetroPorts, r as claimMetroPort, x as releaseMetroPort } from "./config-CYcBF478.mjs";
3
+ import { r as readWorkspaceState } from "./workspace-state-Cjuigeeu.mjs";
4
4
  import { sep } from "path";
5
5
  import { existsSync, readlinkSync, realpathSync } from "fs";
6
6
  import { readFile } from "node:fs/promises";
@@ -192,25 +192,34 @@ function createPortProbe() {
192
192
  throw new PortInspectionError(`Cannot tell whether TCP port ${port} is free: the TCP listener table failed (${listening.message.replace(/\s+/g, " ").trim()}), lsof could not list listeners, and a loopback connect failed.`);
193
193
  };
194
194
  }
195
- function isMetroRunning(port) {
195
+ function isMetroRunning(port, signal) {
196
196
  return new Promise((resolve) => {
197
197
  const req = request({
198
198
  hostname: "localhost",
199
199
  port,
200
200
  path: "/status",
201
- timeout: 2e3
201
+ timeout: 2e3,
202
+ signal
202
203
  }, (res) => {
203
204
  let data = "";
205
+ let bytes = 0;
204
206
  res.on("data", (chunk) => {
207
+ bytes += Buffer.byteLength(chunk);
208
+ if (bytes > 65536) return finish(false);
205
209
  data += chunk;
206
210
  });
207
- res.on("end", () => resolve(data.includes("packager-status:running")));
211
+ res.on("end", () => finish(data.includes("packager-status:running")));
212
+ res.on("error", () => finish(false));
213
+ res.on("aborted", () => finish(false));
208
214
  });
209
- req.on("error", () => resolve(false));
210
- req.on("timeout", () => {
215
+ const deadline = setTimeout(() => finish(false), 2e3);
216
+ const finish = (running) => {
217
+ clearTimeout(deadline);
211
218
  req.destroy();
212
- resolve(false);
213
- });
219
+ resolve(running);
220
+ };
221
+ req.on("error", () => finish(false));
222
+ req.on("timeout", () => finish(false));
214
223
  req.end();
215
224
  });
216
225
  }
@@ -305,6 +314,23 @@ function listeningPids(port, platform = process.platform) {
305
314
  if (pids.length > 0 || platform !== "win32") return pids;
306
315
  return parseNetstatPids(getExecutor().runQuiet("netstat -ano", { timeoutMs: 1e4 }), port);
307
316
  }
317
+ /** Reads listener pids without blocking on lsof or netstat. */
318
+ async function listeningPidsAsync(port, platform = process.platform) {
319
+ const pids = parseLsofPids(await getExecutor().runFileQuietAsync("lsof", [
320
+ "-nP",
321
+ `-iTCP:${port}`,
322
+ "-sTCP:LISTEN",
323
+ "-t"
324
+ ], {
325
+ timeoutMs: 1e4,
326
+ killSignal: "SIGKILL"
327
+ }));
328
+ if (pids.length > 0 || platform !== "win32") return pids;
329
+ return parseNetstatPids(await getExecutor().runFileQuietAsync("netstat", ["-ano"], {
330
+ timeoutMs: 1e4,
331
+ killSignal: "SIGKILL"
332
+ }), port);
333
+ }
308
334
  function parseLsofCwd(out) {
309
335
  if (!out) return null;
310
336
  const lines = String(out).split("\n");
@@ -314,7 +340,10 @@ function parseLsofCwd(out) {
314
340
  return nLine ? nLine.slice(1) : null;
315
341
  }
316
342
  function lsofOutput(args) {
317
- return getExecutor().runFileAsync("lsof", args, { timeoutMs: 1e4 }).catch((error) => typeof error?.stdout === "string" ? error.stdout : null);
343
+ return getExecutor().runFileAsync("lsof", args, {
344
+ timeoutMs: 1e4,
345
+ killSignal: "SIGKILL"
346
+ }).catch((error) => typeof error?.stdout === "string" ? error.stdout : null);
318
347
  }
319
348
  /**
320
349
  * `listeningPids` for several ports with one lsof call. A port lsof could not be asked about is
@@ -470,5 +499,31 @@ function killMetroTree(leader, processToken) {
470
499
  return false;
471
500
  }
472
501
  }
502
+ /** Signals a process tree without blocking on Windows taskkill. */
503
+ async function signalProcessTreeAsync(pid, signal = "SIGTERM", options = {}) {
504
+ if (!Number.isSafeInteger(pid) || pid <= 1) throw new Error(`Refusing to signal pid ${pid}.`);
505
+ if ((options.platform ?? process.platform) !== "win32") return signalProcessTree(pid, signal, options);
506
+ return await getExecutor().runFileQuietAsync("taskkill", [
507
+ "/PID",
508
+ String(pid),
509
+ "/T",
510
+ "/F"
511
+ ], {
512
+ timeoutMs: 3e4,
513
+ killSignal: "SIGKILL"
514
+ }) !== null;
515
+ }
516
+ /** Stops the verified Metro process tree without blocking on Windows taskkill. */
517
+ async function killMetroTreeAsync(leader, processToken) {
518
+ if (!leader || leader === process.pid || (0, process_identity_exports.inspectProcessIdentity)({
519
+ pid: leader,
520
+ processToken
521
+ }) !== "same") return false;
522
+ try {
523
+ return await signalProcessTreeAsync(leader, "SIGTERM", { group: true });
524
+ } catch {
525
+ return false;
526
+ }
527
+ }
473
528
  //#endregion
474
- export { listeningPidsByPort as a, processCwd as c, signalProcessTree as d, createPortProbe as f, PortInspectionError as g, PORT_INSPECTION_REMEDY as h, listeningPids as i, processCwds as l, reserveMetroPort as m, isInsideProject as n, parseNetstatPids as o, isMetroRunning as p, killMetroTree as r, pidExists as s, NOT_OURS_FOREIGN_CWD as t, resolveProjectMetro as u };
529
+ export { reserveMetroPort as _, listeningPids as a, parseNetstatPids as c, processCwds as d, resolveProjectMetro as f, isMetroRunning as g, createPortProbe as h, killMetroTreeAsync as i, pidExists as l, signalProcessTreeAsync as m, isInsideProject as n, listeningPidsAsync as o, signalProcessTree as p, killMetroTree as r, listeningPidsByPort as s, NOT_OURS_FOREIGN_CWD as t, processCwd as u, PORT_INSPECTION_REMEDY as v, PortInspectionError as y };