stim 1.17.2 → 1.19.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 (162) hide show
  1. package/README.md +50 -1
  2. package/dist/{activity-IRvJY_ru.mjs → activity-BSw0x84R.mjs} +4 -4
  3. package/dist/{agent-device-usage-output-BK41vnzN.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +8 -8
  4. package/dist/{android-B9yaNKwa.mjs → android-BXc6BmEi.mjs} +658 -404
  5. package/dist/{android-B_YNZy61.mjs → android-BdQC6zs1.mjs} +9 -9
  6. package/dist/android-BvV1gGdN.mjs +4 -0
  7. package/dist/{android-DE4v59Mb.mjs → android-DE5g_5gv.mjs} +2 -2
  8. package/dist/{android-cas-ZFpjJBL_.mjs → android-cas-C87geAg-.mjs} +5 -5
  9. package/dist/android-cas-compiler.mjs +2 -2
  10. package/dist/api-DIf_s86s.mjs +150 -0
  11. package/dist/api-run.d.mts +1 -0
  12. package/dist/api-run.mjs +145 -0
  13. package/dist/api.d.mts +218 -0
  14. package/dist/api.mjs +2 -0
  15. package/dist/{app-install-VPkI5WEg.mjs → app-install-CFI4ptUL.mjs} +33 -13
  16. package/dist/{attempt-Bk2ouQVL.mjs → attempt-DW-mQqM7.mjs} +14 -4
  17. package/dist/{web-Dl0KSRHf.mjs → browser-web-CDhqQxhv.mjs} +138 -176
  18. package/dist/{budget-DfcgFdQB.mjs → budget-Dz-kyXLv.mjs} +1391 -58
  19. package/dist/build-facts-B87vo-Im.d.mts +142 -0
  20. package/dist/{cache-manifest-DnUHBJaU.mjs → cache-manifest-DiwKSyv9.mjs} +3 -3
  21. package/dist/cache-manifest.mjs +1 -1
  22. package/dist/{chrome-BrcVWQyD.mjs → chrome-BTUOo8p2.mjs} +1 -1
  23. package/dist/cli-C9Zvgbdc.mjs +68 -0
  24. package/dist/cli.mjs +1 -1
  25. package/dist/{client-SvBdgObD.mjs → client-CuUo8Nvg.mjs} +381 -49
  26. package/dist/collector-run.d.mts +6 -0
  27. package/dist/collector-run.mjs +9 -9
  28. package/dist/{command-output-CDAIFD-8.mjs → command-output-Bt8ygHE7.mjs} +2 -2
  29. package/dist/{config-D0DbpZtM.mjs → config-DC5jEtd1.mjs} +9 -5
  30. package/dist/{created-devices-CpvzBL25.mjs → created-devices-D0s26Hx5.mjs} +2 -2
  31. package/dist/{dependency-state-CLcBHH2M.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
  32. package/dist/{detached-entry-CiTEgMR1.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
  33. package/dist/{dev-client-B-XC4uRH.mjs → dev-client-CDY_zAmD.mjs} +2 -2
  34. package/dist/{device-C8IOoJPv.mjs → device-BHw0WlHl.mjs} +8 -8
  35. package/dist/{device-capacity-ZC4XSZ4R.mjs → device-capacity-BoN1jQkO.mjs} +25 -14
  36. package/dist/device-host-worker.mjs +19 -19
  37. package/dist/{gradle-dJpre3Yn.mjs → device-ios-B2ruohE-.mjs} +661 -107
  38. package/dist/{device-lease-DpoS36_u.mjs → device-lease-Cu7PtQpZ.mjs} +9 -9
  39. package/dist/{device-lease-run-B8YltIH_.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
  40. package/dist/{device-pool-3o7s5lo4.mjs → device-pool-CP4rAsHx.mjs} +3 -3
  41. package/dist/{device-remote-hFSkpfQu.mjs → device-remote-B5GiUifk.mjs} +15 -16
  42. package/dist/{doctor-CFv1fCrF.mjs → doctor-PRJH94v6.mjs} +61 -34
  43. package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
  44. package/dist/{error-diagnostics-C-NMnhrk.mjs → error-diagnostics--v5HGOU0.mjs} +11 -11
  45. package/dist/{exec-CaErVv7t.mjs → exec-i8GDPwq9.mjs} +93 -6
  46. package/dist/{gc-DEmkg3Xh.mjs → gc-CyHMcKcn.mjs} +25 -471
  47. package/dist/{guide-CSmhMTf8.mjs → guide-dRaQJJk9.mjs} +681 -507
  48. package/dist/{hosted-android-E1Heoqnv.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
  49. package/dist/{hosted-client-Bp4knSwu.mjs → hosted-client-C5G4h_OJ.mjs} +2 -2
  50. package/dist/{hosted-ios-BnbeYOUD.mjs → hosted-ios-Bik035eL.mjs} +1 -1
  51. package/dist/{hosted-logs-OcgIBvCT.mjs → hosted-logs-CI9Az9a4.mjs} +9 -9
  52. package/dist/{hosted-macos-DcxKjtfH.mjs → hosted-macos-DABm3ScO.mjs} +5 -5
  53. package/dist/{hosted-native-1Ebbig4w.mjs → hosted-native-DbV2aUVw.mjs} +13 -9
  54. package/dist/{idle-shutdown-IGyNV8Cr.mjs → idle-shutdown-DYiMBn34.mjs} +7 -8
  55. package/dist/{ios-DSfnPfse.mjs → ios-BWbHFZVz.mjs} +19 -7
  56. package/dist/{ios-Cr1h5gnO.mjs → ios-DCrkgXEM.mjs} +1 -1
  57. package/dist/ios-DYUr9LGc.mjs +8 -0
  58. package/dist/ios-ITYno9rO.mjs +2241 -0
  59. package/dist/{ios-device-pAN4t54-.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
  60. package/dist/{ios-device-Ee7sDXfp.mjs → ios-device-CrW8aMb5.mjs} +1 -1
  61. package/dist/{ios-state-8L3lgum6.mjs → ios-state-By0XuLTQ.mjs} +1 -1
  62. package/dist/{launch-verify-lTnWZikR.mjs → launch-verify-DCveSE6d.mjs} +5 -5
  63. package/dist/{logs-BAaS7gS2.mjs → logs-Bao1HOMy.mjs} +13 -13
  64. package/dist/{macos-BIRQS90f.mjs → macos-ciyBdTY5.mjs} +194 -132
  65. package/dist/macos-nIOATJmR.mjs +2 -0
  66. package/dist/macos-run.mjs +1 -1
  67. package/dist/maintenance-run.mjs +349 -47
  68. package/dist/manifest-CX0d1IkZ.mjs +148 -0
  69. package/dist/{metro-g8NqiJp-.mjs → metro-DI2AjPF_.mjs} +196 -43
  70. package/dist/{metro-gateway-C-ijGI2F.mjs → metro-gateway-BxpJLIwh.mjs} +4 -4
  71. package/dist/{metro-store-CDDZHtPl.mjs → metro-store-BAHFcJm6.mjs} +16 -2
  72. package/dist/{build-plan-BDsSi09V.mjs → miss-reason-CjQCOKqq.mjs} +207 -249
  73. package/dist/{named-ports-C8m8EQs2.mjs → named-ports-B4iWH4E-.mjs} +70 -8
  74. package/dist/{native-runtime-BEK171xQ.mjs → native-runtime-BGxsbfny.mjs} +6 -6
  75. package/dist/{ndjson-PclOIwVY.mjs → ndjson-LGZAMsqa.mjs} +8 -4
  76. package/dist/offload-worker.d.mts +3 -45
  77. package/dist/offload-worker.mjs +11 -11
  78. package/dist/{ownership-DyRQru0q.mjs → ownership-EB0ySdGK.mjs} +3 -3
  79. package/dist/{page-QF_Ke10s.mjs → page-Bv9s2KwY.mjs} +1 -1
  80. package/dist/placement-log-Dxe34rJm.mjs +88 -0
  81. package/dist/plan-placement-BVY59qa8.mjs +290 -0
  82. package/dist/{ports-4nYqxPWC.mjs → ports-ByPc0_97.mjs} +3 -3
  83. package/dist/{prebuild-D7RUMkwN.mjs → prebuild-BKJ3wJI1.mjs} +5 -5
  84. package/dist/preview-BbSottmO.mjs +986 -0
  85. package/dist/{rolldown-runtime-BsOwBuO_.mjs → process-identity-Biv3arCO.mjs} +11 -1
  86. package/dist/project-B5eQ1USs.mjs +612 -0
  87. package/dist/{pull-request-pxnDCQzn.mjs → pull-request-IHNdMnG8.mjs} +1 -1
  88. package/dist/pull-requests.mjs +1 -1
  89. package/dist/react-native-ios-BMh2i25I.mjs +2 -0
  90. package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
  91. package/dist/{recordings-BNgsD1Tr.mjs → recordings-Bv8McZN4.mjs} +1 -1
  92. package/dist/{reload-DcRxj3qG.mjs → reload-rAPdqeRR.mjs} +14 -15
  93. package/dist/{remote-cache-Ci4DQYYj.mjs → remote-cache-N3hAEaAL.mjs} +5 -5
  94. package/dist/{run-CkE9y0nc.mjs → run-lAkle1-c.mjs} +5 -5
  95. package/dist/{server-bare-BkrSxSsZ.mjs → server-bare-CkIjnegq.mjs} +5 -6
  96. package/dist/server-expo-DGsdUGX2.mjs +2 -0
  97. package/dist/{server-expo-CHTyXD0G.mjs → server-expo-n3tUi3Em.mjs} +5 -6
  98. package/dist/{settings-SR9OmW9h.mjs → settings-2am7TSxp.mjs} +5 -5
  99. package/dist/{settings-Cfd-0r2d.mjs → settings-CxgngUZk.mjs} +116 -103
  100. package/dist/{settings-BBpMcDbD.mjs → settings-Djl-mpjX.mjs} +1 -1
  101. package/dist/settings.schema.json +198 -9
  102. package/dist/{simslim-BWNrc3M3.mjs → simslim-D9LkJxIO.mjs} +7 -7
  103. package/dist/{slot-launch-DmjBmpQV.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
  104. package/dist/{spawn-claims-D0XfSe8u.mjs → spawn-claims-Kqiifsk2.mjs} +1 -1
  105. package/dist/{spawn-entry-jw19m8Nl.mjs → spawn-entry-Dcb7sDUz.mjs} +1 -0
  106. package/dist/{stage-CzaiwFsI.mjs → stage-BgaZJVZY.mjs} +14 -3
  107. package/dist/{start-AlfCPRVU.mjs → start-D8NbxNBb.mjs} +1 -1
  108. package/dist/{start-DUz3mYdb.mjs → start-DtxthMfI.mjs} +34 -27
  109. package/dist/{state-PeQiJuIu.mjs → state-D2KtnALG.mjs} +4 -4
  110. package/dist/{state-DyaNTgfR.mjs → state-Tp4uImDS.mjs} +5 -3
  111. package/dist/{state-B4PQFXMW.d.mts → state-lKh8shBp.d.mts} +2 -3
  112. package/dist/{stats-Bq4fJOdB.mjs → stats-8EJ5ivFT.mjs} +6 -6
  113. package/dist/{status-DlKvVJBE.mjs → status-BEeL6IKz.mjs} +6 -4
  114. package/dist/{status-BA2pehwf.mjs → status-BOyp0CUl.mjs} +31 -34
  115. package/dist/{stim-desktop-Cnz8CPnl.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
  116. package/dist/{stim-installations-QMEI32v1.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
  117. package/dist/stop-D0UIpZuh.mjs +72 -0
  118. package/dist/{stop-zF1y04f2.mjs → stop-DRipAg-e.mjs} +2 -2
  119. package/dist/{stop-DQIasgKp.mjs → stop-zDlknFoz.mjs} +79 -33
  120. package/dist/supervisor-run.d.mts +24 -22
  121. package/dist/supervisor-run.mjs +21 -22
  122. package/dist/{support-CsJNVfOc.mjs → support-CNqYkV0y.mjs} +7 -7
  123. package/dist/{support-WvD__tSV.mjs → support-DsNaFg6D.mjs} +5 -5
  124. package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
  125. package/dist/{toolchain-DNyR3NPq.mjs → toolchain-C3xSoyUl.mjs} +475 -269
  126. package/dist/{trigger-Bemu8ytw.mjs → trigger-CAhmG-4s.mjs} +6 -6
  127. package/dist/trigger-CoalsMTV.mjs +2 -0
  128. package/dist/{warm-progress-DF4JRvYI.mjs → warm-progress-pFLB2e6P.mjs} +135 -38
  129. package/dist/{status-CzS4bPO9.mjs → watchman-BL1IdOtq.mjs} +75 -7
  130. package/dist/web-DFpFeZu5.mjs +2 -0
  131. package/dist/web-DbbrPUn0.mjs +127 -0
  132. package/dist/web-run.mjs +10 -10
  133. package/dist/{workspace-state-DqcCbpE7.mjs → workspace-state-CR9X86xJ.mjs} +3 -3
  134. package/dist/{ownership-BMLqyBgJ.mjs → workspaces-Djb2gfi9.mjs} +661 -23
  135. package/dist/{worktree-Be_7NLKy.mjs → worktree-BL4M1rhB.mjs} +252 -50
  136. package/dist/{worktree-j3IcFAI5.mjs → worktree-DV-A0LNL.mjs} +1 -1
  137. package/package.json +10 -5
  138. package/shim/bundle-response.cjs +2 -1
  139. package/shim/bundle-response.d.cts +1 -1
  140. package/shim/expo-metro-config.cjs +1 -1
  141. package/dist/build-progress-D0WkjCPd.mjs +0 -1036
  142. package/dist/build-slots-41v_d2x9.mjs +0 -142
  143. package/dist/cli-CYXb29oE.mjs +0 -51
  144. package/dist/deps-iKw0eD4P.mjs +0 -438
  145. package/dist/device-ios-C2Um-XUR.mjs +0 -412
  146. package/dist/errors-B6W7FkxQ.mjs +0 -15
  147. package/dist/guide-status-Du-ZQ3FD.mjs +0 -125
  148. package/dist/idle-BXG__1BA.mjs +0 -176
  149. package/dist/in-use-CvGOUn-x.mjs +0 -130
  150. package/dist/ios-BJ4XUSe1.mjs +0 -3867
  151. package/dist/native-run-D1Q56rAD.mjs +0 -158
  152. package/dist/preview-B-g9d7kV.mjs +0 -318
  153. package/dist/process-identity-BmRm1qV0.mjs +0 -12
  154. package/dist/project-D47Rh0ly.mjs +0 -276
  155. package/dist/server-expo-CeakhI8P.mjs +0 -2
  156. package/dist/state-BKa8wNN5.mjs +0 -148
  157. package/dist/stop-BIiM49EY.mjs +0 -48
  158. package/dist/stop-cause-rhmGfwvt.mjs +0 -97
  159. package/dist/trigger-CXts6qt1.mjs +0 -2
  160. package/dist/watchman-APYjXSQa.mjs +0 -48
  161. package/dist/workspace-process-lock-2mNzOlaB.mjs +0 -58
  162. package/dist/workspaces-Bcib97-6.mjs +0 -306
@@ -1,25 +1,193 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { D as withConfigLock, H as projectDeviceSlots, _ as loadConfig, d as getConfigDir, k as acquireAvdClaim, p as getProject, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
3
- import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
1
+ import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
4
3
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
5
- import { l as phaseLine } from "./command-output-CDAIFD-8.mjs";
6
- import { gt as repoRoot, q as resolveTailscaleBinary } from "./settings-Cfd-0r2d.mjs";
7
- import { o as pidExists, u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
8
- import { g as workspaceAgentDeviceDir, v as workspaceDir } from "./workspace-state-DqcCbpE7.mjs";
9
- import { _ as removeSingletonFiles, c as webClaimRoot, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, o as readWebRecord, t as CDP_PORT_LABEL } from "./state-PeQiJuIu.mjs";
10
- import { t as agentDeviceDaemon, u as readAgentDeviceRecords } from "./activity-IRvJY_ru.mjs";
11
- import { n as readCreatedDevices, r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-CpvzBL25.mjs";
12
- import { B as ownedAvdSystemImage, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, M as listOrphanedAvdDirectories, O as listAdbDevices, X as shutdownAndroidEmulator, Z as sleepSync, _ as avdStorageRoots, dt as parkSim, et as waitForAndroidEmulatorShutdown, f as assertOwnedAvdStopped, h as avdPathExists, it as isStimOwnedAvd, lt as eraseParkedAfter, mt as removeParkedAfter, nt as wipeAvdUserData, pt as readParked, x as deleteAvd } from "./android-B_YNZy61.mjs";
13
- import { E as shutdownIosSim, _ as parseRuntimeVersion, a as deleteIosSim, b as renameIosSim, f as listIosDeviceTypes, g as parkedSimName, o as deleteParkedIosSim, s as eraseIosSim, w as resolveOwnedIosSim } from "./ios-DSfnPfse.mjs";
14
- import { r as workspaceProcessLockPath, t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
15
- import { r as releaseBrowserPort } from "./named-ports-C8m8EQs2.mjs";
16
- import { createHash, randomUUID } from "node:crypto";
17
- import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, rmSync, unlinkSync } from "node:fs";
4
+ import { a as formatElapsed, l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
5
+ import { D as withConfigLock$1, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, P as measuredDirectorySize, _ as loadConfig$1, d as getConfigDir, g as isPathPrefix, j as formatBytes, k as acquireAvdClaim, p as getProject, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
6
+ import { S as workspaceName, g as workspaceAgentDeviceDir, r as readWorkspaceState$1, s as workspaceLastUsed, v as workspaceDir } from "./workspace-state-CR9X86xJ.mjs";
7
+ import { Y as resolveTailscaleBinary, mt as repoRoot } from "./settings-CxgngUZk.mjs";
8
+ import { d as signalProcessTree, s as pidExists } from "./metro-DI2AjPF_.mjs";
9
+ import { _ as removeSingletonFiles, c as webClaimRoot, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, o as readWebRecord, t as CDP_PORT_LABEL, u as webFacts } from "./state-D2KtnALG.mjs";
10
+ import { t as agentDeviceDaemon, u as readAgentDeviceRecords } from "./activity-BSw0x84R.mjs";
11
+ import { h as listBuildLocks } from "./device-lease-Cu7PtQpZ.mjs";
12
+ import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Kqiifsk2.mjs";
13
+ import { n as readCreatedDevices$1, r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-D0s26Hx5.mjs";
14
+ import { B as ownedAvdSystemImage, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, M as listOrphanedAvdDirectories, O as listAdbDevices, X as shutdownAndroidEmulator, Z as sleepSync, _ as avdStorageRoots, dt as parkSim, et as waitForAndroidEmulatorShutdown, f as assertOwnedAvdStopped, h as avdPathExists, it as isStimOwnedAvd, lt as eraseParkedAfter, mt as removeParkedAfter, nt as wipeAvdUserData, pt as readParked, x as deleteAvd } from "./android-BdQC6zs1.mjs";
15
+ import { D as shutdownIosSim, T as resolveOwnedIosSim, _ as parkedSimName, c as eraseIosSim, o as deleteIosSim, p as listIosDeviceTypes, s as deleteParkedIosSim, v as parseRuntimeVersion, x as renameIosSim } from "./ios-BWbHFZVz.mjs";
16
+ import { a as withWorkspaceProcessLock, o as workspaceProcessLockError, r as releaseBrowserPort, s as workspaceProcessLockPath } from "./named-ports-B4iWH4E-.mjs";
17
+ import { a as macosRuntimeClaim, n as macosDir } from "./state-Tp4uImDS.mjs";
18
+ import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync } from "node:fs";
18
19
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
20
+ import { basename as basename$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
21
+ import { buildSlotsDir, hostedNativeRecords, isJsonObject, macosAppState, parseHostedNativePlacement, readJsonFile, readMacosRecord, requireAutomaticMachine, tryAcquireBuildSlotClaim, unreadableHostedNative } from "@stim-cli/core/state";
19
22
  import { homedir } from "node:os";
23
+ import chalk from "chalk";
20
24
  import { isDeepStrictEqual } from "node:util";
25
+ import { existsSync as existsSync$1, lstatSync as lstatSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
26
+ import { createHash, randomUUID } from "node:crypto";
21
27
  import { resolve4 } from "node:dns/promises";
22
28
  import { request } from "node:https";
29
+ //#region src/commands/gc/paths.ts
30
+ function canonicalPath(p) {
31
+ try {
32
+ return realpathSync$1(p);
33
+ } catch {
34
+ return resolve$1(p);
35
+ }
36
+ }
37
+ //#endregion
38
+ //#region src/commands/gc/results.ts
39
+ const results = [];
40
+ function recordGcResult(kind, status, label, { id = null, bytes = null, detail = null } = {}) {
41
+ results.push({
42
+ kind,
43
+ status,
44
+ label,
45
+ id,
46
+ bytes,
47
+ detail
48
+ });
49
+ }
50
+ function takeGcResults() {
51
+ return results.splice(0);
52
+ }
53
+ //#endregion
54
+ //#region src/engine/build-slots.ts
55
+ const SLOT_PREFIX = "slot-";
56
+ const SLOT_POLL_MS = 1e3;
57
+ const SLOT_PROGRESS_MS = 3e4;
58
+ const SLOT_CEILING_MS = 54e5;
59
+ function sleepAsync$1(ms) {
60
+ return new Promise((resolve) => setTimeout(resolve, ms));
61
+ }
62
+ function toRecord(holder) {
63
+ const details = holder.details;
64
+ return {
65
+ pid: holder.owner.pid,
66
+ index: typeof details.index === "number" ? details.index : null,
67
+ projectRoot: typeof details.projectRoot === "string" ? details.projectRoot : null,
68
+ startedAt: holder.startedAt || null,
69
+ logFile: typeof details.logFile === "string" ? details.logFile : null
70
+ };
71
+ }
72
+ function tryAcquireBuildSlot({ max, root = null, logFile = null }) {
73
+ if (!max || max <= 0) return {
74
+ acquired: true,
75
+ unlimited: true
76
+ };
77
+ const got = tryAcquireBuildSlotClaim({
78
+ max,
79
+ details: {
80
+ projectRoot: root,
81
+ logFile
82
+ }
83
+ });
84
+ if (!got) return null;
85
+ declareSpawnsOn(got.claim);
86
+ return {
87
+ acquired: true,
88
+ path: got.path,
89
+ index: got.index,
90
+ slot: {
91
+ pid: got.claim.owner.pid,
92
+ index: got.index,
93
+ projectRoot: root,
94
+ startedAt: got.claim.startedAt,
95
+ logFile
96
+ },
97
+ claim: got.claim
98
+ };
99
+ }
100
+ function slotWaitingLine({ max, elapsedMs }) {
101
+ return `${"build".padEnd(11)} waiting for a build slot (all ${max} in use, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle concurrency`;
102
+ }
103
+ async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, waitingFor = () => {}, sleep = sleepAsync$1, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS, automatic = false }) {
104
+ if (automatic) requireAutomaticMachine("build", "local");
105
+ if (!max || max <= 0) return {
106
+ acquired: true,
107
+ unlimited: true
108
+ };
109
+ const started = now();
110
+ let lastProgress = started;
111
+ let waited = false;
112
+ try {
113
+ for (;;) {
114
+ if (automatic) requireAutomaticMachine("build", "local");
115
+ const got = tryAcquireBuildSlot({
116
+ max,
117
+ root,
118
+ logFile
119
+ });
120
+ if (got) return {
121
+ ...got,
122
+ slotWaitMs: waited ? Math.max(0, Math.round(now() - started)) : 0
123
+ };
124
+ waited = true;
125
+ waitingFor({
126
+ kind: "build-slot",
127
+ inUse: max,
128
+ max,
129
+ since: new Date(started).toISOString()
130
+ });
131
+ const elapsed = now() - started;
132
+ if (elapsed >= ceilingMs) {
133
+ const err = /* @__PURE__ */ new Error(`Waited ${formatElapsed(elapsed)} for one of ${max} build slots, and every slot is held by a process that is still running, or by a holder Stim cannot identify. Slots live under ` + buildSlotsDir() + "; remove a slot directory whose builder is not really building, or raise concurrency.maxBuilds.");
134
+ err.code = "STIM_BUILD_SLOT_TIMEOUT";
135
+ throw err;
136
+ }
137
+ if (now() - lastProgress >= progressMs) {
138
+ lastProgress = now();
139
+ out(slotWaitingLine({
140
+ max,
141
+ elapsedMs: elapsed
142
+ }));
143
+ }
144
+ await sleep(intervalMs);
145
+ }
146
+ } finally {
147
+ waitingFor(null);
148
+ }
149
+ }
150
+ function releaseBuildSlot(handle) {
151
+ if (!handle || handle.unlimited) return false;
152
+ stopDeclaringSpawnsOn(handle.claim);
153
+ return (0, ownership_claim_exports.releaseClaim)(handle.claim);
154
+ }
155
+ function listBuildSlots() {
156
+ const dir = buildSlotsDir();
157
+ let names;
158
+ try {
159
+ names = readdirSync(dir);
160
+ } catch {
161
+ return [];
162
+ }
163
+ const slots = [];
164
+ for (const name of names) {
165
+ if (!name.startsWith(SLOT_PREFIX)) continue;
166
+ const path = join(dir, name);
167
+ try {
168
+ if (!statSync(path).isDirectory()) continue;
169
+ } catch {
170
+ continue;
171
+ }
172
+ const survey = (0, ownership_claim_exports.readClaimSet)(path);
173
+ const holder = survey.live[0] ?? survey.dead[0];
174
+ const info = holder ? toRecord(holder) : null;
175
+ const index = Number(name.slice(5));
176
+ slots.push({
177
+ path,
178
+ name,
179
+ index: Number.isFinite(index) ? index : null,
180
+ pid: info?.pid ?? null,
181
+ projectRoot: info?.projectRoot ?? null,
182
+ startedAt: info?.startedAt ?? null,
183
+ logFile: info?.logFile ?? null,
184
+ alive: survey.live.length > 0,
185
+ unresolved: survey.unresolved.length > 0
186
+ });
187
+ }
188
+ return slots;
189
+ }
190
+ //#endregion
23
191
  //#region src/devices/agent-device-cleanup.ts
24
192
  function parseAgentDeviceSessions(output) {
25
193
  const result = JSON.parse(output);
@@ -392,7 +560,7 @@ function teardownOwnedIosSim(udid, { del = false, label, park, workspace, shutdo
392
560
  }
393
561
  }
394
562
  function assertAvdReferences(avdName, owner) {
395
- const config = loadConfig();
563
+ const config = loadConfig$1();
396
564
  if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
397
565
  if (owner && "projectPath" in owner && owner.expectedRecord && !isDeepStrictEqual(deviceSlotPlatforms(config.projects[owner.projectPath], owner.slot)?.android, owner.expectedRecord)) throw new Error(`AVD ${avdName} has a changed workspace record; its data was kept.`);
398
566
  for (const [projectPath, project] of Object.entries(config.projects)) for (const { slot, platforms } of projectDeviceSlots(project)) {
@@ -405,7 +573,7 @@ function removeOrphanedAvdDirectory(candidate, owner) {
405
573
  const surveyed = listOrphanedAvdDirectories(candidate.name).find((entry) => entry.directory === candidate.directory);
406
574
  if (!surveyed || surveyed.name !== candidate.name || surveyed.dev !== candidate.dev || surveyed.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
407
575
  assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
408
- const detached = withConfigLock(() => {
576
+ const detached = withConfigLock$1(() => {
409
577
  const current = lstatSync(candidate.directory);
410
578
  if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
411
579
  assertAvdReferences(candidate.name, owner);
@@ -481,7 +649,7 @@ function serialFree(serial) {
481
649
  function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, owner, workspace, orphanedDirectory, onlyIfMissing = false, onWipeStart, waitForShutdown = waitForAndroidEmulatorShutdown, assertStopped = assertOwnedAvdStopped, resolveAvd = resolveOwnedAvdSerial }) {
482
650
  let parkFallback;
483
651
  try {
484
- if (del || wipe) withConfigLock(() => assertAvdReferences(avdName, owner));
652
+ if (del || wipe) withConfigLock$1(() => assertAvdReferences(avdName, owner));
485
653
  const resolved = resolveAvd(avdName);
486
654
  if (resolved.notOwned) return {
487
655
  status: "skipped",
@@ -547,7 +715,7 @@ function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, o
547
715
  if (current.notOwned || current.missing) throw new Error(`AVD ${avdName} changed before its data was wiped.`);
548
716
  if (current.serial) throw new Error(`Owned AVD ${avdName} started again before its data was wiped.`);
549
717
  assertStopped(avdName);
550
- withConfigLock(() => assertAvdReferences(avdName, owner));
718
+ withConfigLock$1(() => assertAvdReferences(avdName, owner));
551
719
  const directory = ownedAvdDirectory(avdName);
552
720
  if (!directory) throw new Error(`The data directory of AVD ${avdName} could not be resolved.`);
553
721
  onWipeStart?.();
@@ -563,7 +731,7 @@ function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, o
563
731
  if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
564
732
  if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
565
733
  assertStopped(avdName);
566
- withConfigLock(() => assertAvdReferences(avdName, owner));
734
+ withConfigLock$1(() => assertAvdReferences(avdName, owner));
567
735
  if (park && park.max > 0) try {
568
736
  const systemImage = ownedAvdSystemImage(avdName);
569
737
  if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
@@ -720,7 +888,7 @@ async function teardownBrowserHeld(root, { deleteProfile = false } = {}) {
720
888
  }
721
889
  if (existsSync(profile)) removeSingletonFiles(profile);
722
890
  if (deleteProfile && existsSync(profile)) {
723
- if (!readCreatedDevices().web.has(profile)) return {
891
+ if (!readCreatedDevices$1().web.has(profile)) return {
724
892
  status: "skipped",
725
893
  kind: "not-owned",
726
894
  reason: `${profile} is not in Stim's ledger; it was kept`
@@ -743,6 +911,83 @@ async function teardownBrowserHeld(root, { deleteProfile = false } = {}) {
743
911
  }
744
912
  }
745
913
  //#endregion
914
+ //#region src/macos/instances.ts
915
+ const BUNDLE_EXECUTABLE = /^[^/]+\.app\/Contents\/MacOS\/[^/]+$/;
916
+ function bundleDirs(root) {
917
+ const dir = macosDir(root);
918
+ if (process.platform !== "darwin" || !existsSync(dir)) return [];
919
+ return [.../* @__PURE__ */ new Set([dir, realpathSync(dir)])];
920
+ }
921
+ function isBundleExecutable(path, dirs) {
922
+ return dirs.some((dir) => path.startsWith(`${dir}/`) && BUNDLE_EXECUTABLE.test(path.slice(dir.length + 1)));
923
+ }
924
+ /** Pids from `ps -axww -o pid=,comm=` output whose command names a bundle executable inside `dirs`. */
925
+ function bundleCandidates(psOutput, dirs) {
926
+ const pids = [];
927
+ for (const line of psOutput.split("\n")) {
928
+ const match = /^\s*(\d+)\s+(.+)$/.exec(line);
929
+ if (match && isBundleExecutable(match[2], dirs)) pids.push(Number(match[1]));
930
+ }
931
+ return pids;
932
+ }
933
+ /** Whether `lsof -Fn -d txt` output for one process names a bundle executable inside `dirs`. */
934
+ function lsofNamesBundleExecutable(lsofOutput, dirs) {
935
+ return lsofOutput.split("\n").some((line) => line.startsWith("n") && isBundleExecutable(line.slice(1), dirs));
936
+ }
937
+ function candidatePids(dirs) {
938
+ if (!dirs.length) return [];
939
+ return bundleCandidates(getExecutor().runFile("ps", [
940
+ "-axww",
941
+ "-o",
942
+ "pid=,comm="
943
+ ], { timeoutMs: 1e4 }), dirs).filter((pid) => pid !== process.pid);
944
+ }
945
+ /** Pids that claim to run an app bundle from the workspace's macOS directory. `ps` reports argv[0], so this is a lead. */
946
+ function bundleInstancePids(root) {
947
+ return candidatePids(bundleDirs(root));
948
+ }
949
+ function unverified(pid, why) {
950
+ return Object.assign(/* @__PURE__ */ new Error(`Cannot verify macOS app pid ${pid}: ${why}; no signal was sent.`), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
951
+ }
952
+ /**
953
+ * Every running process whose executable is an app bundle Stim built in the workspace's macOS directory, however it
954
+ * was launched. Each identity is captured before its executable is confirmed with lsof.
955
+ */
956
+ function runningBundleInstances(root) {
957
+ const dirs = bundleDirs(root);
958
+ const instances = [];
959
+ for (const pid of candidatePids(dirs)) {
960
+ const processToken = (0, process_identity_exports.captureProcessToken)(pid);
961
+ const start = (0, process_identity_exports.processStartMicros)(pid);
962
+ if (!processToken || start.status !== "running") {
963
+ if (start.status === "gone") continue;
964
+ throw unverified(pid, "its identity cannot be captured");
965
+ }
966
+ const record = {
967
+ pid,
968
+ processToken,
969
+ startedAtMicros: start.startedAtMicros
970
+ };
971
+ let open;
972
+ try {
973
+ open = getExecutor().runFile("lsof", [
974
+ "-a",
975
+ "-p",
976
+ String(pid),
977
+ "-d",
978
+ "txt",
979
+ "-Fn"
980
+ ], { timeoutMs: 1e4 });
981
+ } catch (error) {
982
+ if (["gone", "different"].includes((0, process_identity_exports.inspectProcessIdentity)(record))) continue;
983
+ open = String(error.stdout ?? "");
984
+ if (!open.trim()) throw unverified(pid, `lsof failed (${error.message.split("\n")[0]})`);
985
+ }
986
+ if (lsofNamesBundleExecutable(open, dirs)) instances.push(record);
987
+ }
988
+ return instances;
989
+ }
990
+ //#endregion
746
991
  //#region src/engine/public-http-probe.ts
747
992
  const DNS_TIMEOUT_MS = 5e3;
748
993
  async function resolveAddresses(hostname, signal) {
@@ -1301,4 +1546,397 @@ function numberOrNull(v) {
1301
1546
  return typeof v === "number" && Number.isSafeInteger(v) && v > 0 ? v : null;
1302
1547
  }
1303
1548
  //#endregion
1304
- export { teardownParkedAvd as _, terminateChild as a, withManagedTunnelLock as c, eraseParkedAvd as d, eraseParkedIosSim as f, teardownOwnedIosSim as g, teardownOwnedBrowser as h, stopTunnel as i, withManagedTunnelRemovalLock as l, teardownOwnedAvd as m, managedLockHolders as n, withManagedRemoteWorktreeLock as o, teardownBrowserHeld as p, startTunnelSequence as r, withManagedRemoteWorktreeRemovalLock as s, resolveSupervisorTarget as t, probePublicHttp as u, teardownParkedIosSim as v };
1549
+ //#region src/workspace/in-use.ts
1550
+ const NATIVE_RUN = "native-run";
1551
+ const NATIVE_RUN_HELD = "a stim ios, android or stop run holds its native-run.lock";
1552
+ function workspaceInUse(root, { supervisor = true, managedLocks = true, hosted = true, nativeRun = true } = {}) {
1553
+ const reasons = [];
1554
+ if (supervisor) {
1555
+ const project = getProject(root);
1556
+ const target = resolveSupervisorTarget({
1557
+ state: readWorkspaceState$1(root)?.supervisor,
1558
+ record: project?.supervisor,
1559
+ reservedPort: project?.metroPort
1560
+ });
1561
+ if (target.status === "ours") reasons.push(`its dev server supervisor (pid ${target.pid}) is running`);
1562
+ else if (target.status === "unverified") reasons.push(`its dev server supervisor cannot be verified: ${target.reason ?? "unknown identity"}`);
1563
+ const macos = macosAppState(readMacosRecord(root));
1564
+ if (macos?.host) reasons.push(`its macOS app runs on ${macos.host.machine}`);
1565
+ else if (macos?.state === "running" || macos?.state === "orphaned" || macos?.build.state === "running") reasons.push("its macOS app or build is running");
1566
+ else if (macos?.state === "unverified" || !macos && readWorkspaceState$1(root)?.macos !== void 0) reasons.push("its macOS process owner cannot be verified");
1567
+ else try {
1568
+ const pids = bundleInstancePids(root);
1569
+ if (pids.length) reasons.push(`its macOS app is running (pid ${pids.join(", ")})`);
1570
+ } catch (error) {
1571
+ reasons.push(`its running macOS apps cannot be listed: ${error.message}`);
1572
+ }
1573
+ const runtime = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
1574
+ if (runtime.live.length) reasons.push("its macOS runtime claim is held");
1575
+ else if (runtime.unresolved[0]) reasons.push(`its macOS runtime cannot be verified: ${runtime.unresolved[0].reason}`);
1576
+ const browser = webFacts(readWebRecord(root));
1577
+ if (browser?.status === "running" || browser?.status === "orphaned") reasons.push(`its owned Chrome (pid ${browser.record.chromeProcess?.pid}) is running`);
1578
+ else if (browser?.status === "unverified") reasons.push("its owned Chrome cannot be verified");
1579
+ }
1580
+ if (nativeRun) {
1581
+ const claims = (0, ownership_claim_exports.readClaimSet)(workspaceProcessLockPath(workspaceDir(root), NATIVE_RUN, true));
1582
+ if (claims.live.length) reasons.push(NATIVE_RUN_HELD);
1583
+ else if (claims.unresolved[0]) reasons.push(`its native-run.lock cannot be resolved: ${claims.unresolved[0].reason}`);
1584
+ }
1585
+ for (const platform of ["ios", "android"]) for (const [slot, record] of Object.entries(hosted ? hostedNativeRecords(readWorkspaceState$1(root), platform) : {})) {
1586
+ const placement = parseHostedNativePlacement(record, platform);
1587
+ reasons.push(placement ? `its ${platform === "ios" ? "iOS simulator" : "Android emulator"} runs on ${placement.machine}` : unreadableHostedNative(slot, platform));
1588
+ }
1589
+ const self = canonicalPath(root);
1590
+ for (const [kind, entries] of [["build lock", listBuildLocks()], ["build slot", listBuildSlots()]]) for (const entry of entries) {
1591
+ if (!entry.alive && !entry.unresolved) continue;
1592
+ if (entry.projectRoot !== null && canonicalPath(entry.projectRoot) === self) reasons.push(`a ${entry.alive ? "live" : "unresolvable"} ${kind} at ${entry.path} names it`);
1593
+ }
1594
+ if (managedLocks) reasons.push(...managedLockHolders(root));
1595
+ return reasons;
1596
+ }
1597
+ function emptyWorkspaceDir(dir) {
1598
+ if (lstatSync(dir).isSymbolicLink()) {
1599
+ unlinkSync(dir);
1600
+ return;
1601
+ }
1602
+ for (const name of readdirSync(dir)) if (name !== `${NATIVE_RUN}.lock`) rmSync(join(dir, name), {
1603
+ recursive: true,
1604
+ force: true
1605
+ });
1606
+ }
1607
+ async function withIdleWorkspace(root, fn, { purpose, ...checks }) {
1608
+ try {
1609
+ return await withWorkspaceProcessLock(workspaceDir(root), NATIVE_RUN, async () => {
1610
+ const reasons = workspaceInUse(root, {
1611
+ ...checks,
1612
+ nativeRun: false
1613
+ });
1614
+ if (reasons.length) return {
1615
+ ran: false,
1616
+ reasons
1617
+ };
1618
+ return {
1619
+ ran: true,
1620
+ value: await fn()
1621
+ };
1622
+ }, {
1623
+ external: true,
1624
+ waitMs: 0,
1625
+ ownerPurpose: purpose
1626
+ });
1627
+ } catch (error) {
1628
+ if (workspaceProcessLockError(error)) return {
1629
+ ran: false,
1630
+ reasons: [NATIVE_RUN_HELD]
1631
+ };
1632
+ if ((0, ownership_claim_exports.isClaimRefusal)(error) || (0, ownership_claim_exports.isClaimUnavailable)(error)) return {
1633
+ ran: false,
1634
+ reasons: [`its native-run.lock cannot be taken: ${error.reason}`]
1635
+ };
1636
+ throw error;
1637
+ } finally {
1638
+ try {
1639
+ const dir = workspaceDir(root);
1640
+ if (!lstatSync(dir).isSymbolicLink()) rmdirSync(dir);
1641
+ } catch {}
1642
+ }
1643
+ }
1644
+ //#endregion
1645
+ //#region src/commands/gc/workspaces.ts
1646
+ function workspacesRoot() {
1647
+ return join$1(getConfigDir(), "workspaces");
1648
+ }
1649
+ function isInsideWorkspaces(dir) {
1650
+ const rel = relative$1(canonicalPath(workspacesRoot()), canonicalPath(dir));
1651
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute$1(rel);
1652
+ }
1653
+ function readRecordedRoot(dir, name) {
1654
+ let parsed;
1655
+ try {
1656
+ parsed = readJsonFile(join$1(dir, "workspace.json"));
1657
+ } catch (error) {
1658
+ return {
1659
+ projectRoot: null,
1660
+ problem: error?.code === "ENOENT" ? "it has no workspace.json" : "its workspace.json does not parse"
1661
+ };
1662
+ }
1663
+ const projectRoot = isJsonObject(parsed) ? parsed.projectRoot : void 0;
1664
+ if (typeof projectRoot !== "string" || !isAbsolute$1(projectRoot)) return {
1665
+ projectRoot: null,
1666
+ problem: "its workspace.json records no absolute project root"
1667
+ };
1668
+ if (workspaceName(projectRoot) !== name) return {
1669
+ projectRoot: null,
1670
+ problem: `its workspace.json records ${projectRoot}, whose workspace directory has another name`
1671
+ };
1672
+ return {
1673
+ projectRoot,
1674
+ problem: null
1675
+ };
1676
+ }
1677
+ function listWorkspaceDirs() {
1678
+ const root = workspacesRoot();
1679
+ let names;
1680
+ try {
1681
+ names = readdirSync$1(root).toSorted();
1682
+ } catch {
1683
+ return [];
1684
+ }
1685
+ const entries = [];
1686
+ for (const name of names) {
1687
+ const dir = join$1(root, name);
1688
+ try {
1689
+ if (!statSync$1(dir).isDirectory()) continue;
1690
+ } catch {
1691
+ continue;
1692
+ }
1693
+ entries.push({
1694
+ dir,
1695
+ ...readRecordedRoot(dir, name)
1696
+ });
1697
+ }
1698
+ return entries;
1699
+ }
1700
+ function classifyWorkspaceDirs(entries, { registryKeys, exists, isMounted, inUse }) {
1701
+ const orphaned = [];
1702
+ const skipped = [];
1703
+ for (const { dir, projectRoot, problem } of entries) {
1704
+ if (projectRoot === null) {
1705
+ skipped.push({
1706
+ dir,
1707
+ reason: `workspace directory not resolved: ${problem ?? "unknown project root"}`
1708
+ });
1709
+ continue;
1710
+ }
1711
+ const present = exists(projectRoot);
1712
+ if (present === null) {
1713
+ skipped.push({
1714
+ dir,
1715
+ reason: `cannot tell whether its project root ${projectRoot} still exists`
1716
+ });
1717
+ continue;
1718
+ }
1719
+ if (present) continue;
1720
+ if (registryKeys.some((key) => isPathPrefix(projectRoot, key))) continue;
1721
+ if (!isMounted(projectRoot)) {
1722
+ skipped.push({
1723
+ dir,
1724
+ reason: `the volume of its project root ${projectRoot} is not mounted`
1725
+ });
1726
+ continue;
1727
+ }
1728
+ const reasons = inUse(projectRoot);
1729
+ if (reasons.length) {
1730
+ skipped.push({
1731
+ dir,
1732
+ reason: `its project root ${projectRoot} is gone, but ${reasons.join("; ")}`
1733
+ });
1734
+ continue;
1735
+ }
1736
+ orphaned.push({
1737
+ dir,
1738
+ projectRoot
1739
+ });
1740
+ }
1741
+ return {
1742
+ orphaned,
1743
+ skipped
1744
+ };
1745
+ }
1746
+ function rootPresence(path) {
1747
+ try {
1748
+ lstatSync$1(path);
1749
+ return true;
1750
+ } catch (error) {
1751
+ const code = error?.code;
1752
+ return code === "ENOENT" || code === "ENOTDIR" ? false : null;
1753
+ }
1754
+ }
1755
+ function collectOrphanedWorkspaces(registryKeys, mountedVolumes, { measure = true } = {}) {
1756
+ const classified = classifyWorkspaceDirs(listWorkspaceDirs(), {
1757
+ registryKeys,
1758
+ exists: rootPresence,
1759
+ isMounted: (path) => isOnMountedVolume(path, mountedVolumes),
1760
+ inUse: (root) => workspaceInUse(root)
1761
+ });
1762
+ return {
1763
+ orphaned: measure ? classified.orphaned.map((entry) => Object.assign({}, entry, { bytes: sizeOf(entry.dir) })) : classified.orphaned,
1764
+ skipped: classified.skipped
1765
+ };
1766
+ }
1767
+ const REBUILD_COST = "The next build of an unchanged app installs from the shared build cache; after a native change the compilation cache speeds the rebuild, but on React Native 0.86 Swift does not use it (explicit modules are off), so that build recompiles Swift. The next stim macos in a cleared workspace is a full Swift build.";
1768
+ const WORKSPACE_OUTPUT_DIRS = [
1769
+ "derived-data",
1770
+ "gradle-build",
1771
+ "android-cas",
1772
+ "cache-provider"
1773
+ ];
1774
+ const DAY_MS = 864e5;
1775
+ function planWorkspaceOutputs(entries, { olderThan, now }) {
1776
+ return entries.map(({ dir, projectRoot, problem, bytes, lastUsed, inUse }) => {
1777
+ const idleDays = Number.isFinite(lastUsed) ? Math.max(0, Math.floor((now - lastUsed) / DAY_MS)) : null;
1778
+ const [keptCode, keptReason] = projectRoot === null ? ["unresolved", `workspace directory not resolved: ${problem ?? "unknown project root"}`] : inUse.length ? ["in-use", `in use: ${inUse.join("; ")}`] : olderThan === null ? [null, null] : idleDays === null ? ["last-use-unknown", "its last use is unknown"] : idleDays < olderThan ? ["recently-used", `used ${idleDays}d ago, within --older-than ${olderThan}`] : [null, null];
1779
+ return {
1780
+ dir,
1781
+ projectRoot,
1782
+ bytes,
1783
+ idleDays,
1784
+ willClear: keptCode === null,
1785
+ keptCode,
1786
+ keptReason
1787
+ };
1788
+ });
1789
+ }
1790
+ const SIZE_TIMEOUT_MS = 6e4;
1791
+ function sizeOf(dir, timeoutMs = SIZE_TIMEOUT_MS) {
1792
+ return measuredDirectorySize(dir, { timeoutMs });
1793
+ }
1794
+ function outputPaths(dir) {
1795
+ const paths = WORKSPACE_OUTPUT_DIRS.map((name) => join$1(dir, name)).filter((path) => existsSync$1(path));
1796
+ const macos = join$1(dir, "macos");
1797
+ try {
1798
+ if (!lstatSync$1(macos).isDirectory()) return paths;
1799
+ for (const entry of readdirSync$1(macos, { withFileTypes: true })) if (entry.name === "build" || entry.name.endsWith(".app") || entry.name.startsWith("staging-") && entry.isDirectory()) paths.push(join$1(macos, entry.name));
1800
+ } catch {}
1801
+ return paths;
1802
+ }
1803
+ function outputBytes(paths, timeoutMs) {
1804
+ let total = 0;
1805
+ for (const path of paths) {
1806
+ const size = sizeOf(path, timeoutMs);
1807
+ if (size === null) return null;
1808
+ total += size;
1809
+ }
1810
+ return total;
1811
+ }
1812
+ function collectWorkspaceOutputs({ olderThan, now, exclude = [], measure = true, sizeTimeoutMs = SIZE_TIMEOUT_MS }) {
1813
+ const mountedVolumes = listMountedVolumes();
1814
+ const entries = listWorkspaceDirs().filter((entry) => !exclude.includes(entry.dir)).filter((entry) => entry.projectRoot === null || isOnMountedVolume(entry.projectRoot, mountedVolumes)).map((entry) => Object.assign({}, entry, { paths: outputPaths(entry.dir) })).filter((entry) => entry.paths.length > 0).map(({ paths, ...entry }) => Object.assign({}, entry, { bytes: measure ? outputBytes(paths, sizeTimeoutMs) : null })).map((entry) => Object.assign({}, entry, {
1815
+ lastUsed: entry.projectRoot === null ? NaN : workspaceLastUsed(entry.projectRoot),
1816
+ inUse: entry.projectRoot === null ? [] : workspaceInUse(entry.projectRoot)
1817
+ }));
1818
+ return {
1819
+ root: workspacesRoot(),
1820
+ workspaces: planWorkspaceOutputs(entries, {
1821
+ olderThan,
1822
+ now
1823
+ })
1824
+ };
1825
+ }
1826
+ async function clearWorkspaceOutputs(report, { olderThan, now = Date.now() }) {
1827
+ let failures = 0;
1828
+ let cleared = 0;
1829
+ const clearedRoots = [];
1830
+ for (const entry of report.workspaces) {
1831
+ const root = entry.projectRoot;
1832
+ if (!entry.willClear || root === null) {
1833
+ if (entry.keptReason) {
1834
+ console.log(chalk.dim(`Kept the build outputs of ${root ?? entry.dir}: ${entry.keptReason}`));
1835
+ recordGcResult("workspaceOutputs", "kept", root ?? entry.dir, {
1836
+ bytes: entry.bytes,
1837
+ detail: entry.keptReason
1838
+ });
1839
+ }
1840
+ continue;
1841
+ }
1842
+ let run;
1843
+ try {
1844
+ run = await withIdleWorkspace(root, () => {
1845
+ const [again] = planWorkspaceOutputs([{
1846
+ ...entry,
1847
+ problem: null,
1848
+ lastUsed: workspaceLastUsed(root),
1849
+ inUse: []
1850
+ }], {
1851
+ olderThan,
1852
+ now
1853
+ });
1854
+ if (again?.keptReason) return again.keptReason;
1855
+ for (const path of outputPaths(entry.dir)) rmSync$1(path, {
1856
+ recursive: true,
1857
+ force: true
1858
+ });
1859
+ return null;
1860
+ }, { purpose: "gc" });
1861
+ } catch (error) {
1862
+ failures++;
1863
+ console.log(chalk.red(`Could not clear the build outputs of ${root}: ${error?.message || String(error)}`));
1864
+ recordGcResult("workspaceOutputs", "failed", root, {
1865
+ bytes: entry.bytes,
1866
+ detail: error?.message || String(error)
1867
+ });
1868
+ continue;
1869
+ }
1870
+ const kept = run.ran ? run.value : `in use: ${run.reasons.join("; ")}`;
1871
+ if (kept) {
1872
+ console.log(chalk.yellow(`Kept the build outputs of ${root}: ${kept}`));
1873
+ recordGcResult("workspaceOutputs", "kept", root, {
1874
+ bytes: entry.bytes,
1875
+ detail: kept
1876
+ });
1877
+ continue;
1878
+ }
1879
+ cleared += entry.bytes ?? 0;
1880
+ clearedRoots.push(root);
1881
+ console.log(chalk.green(`Cleared the build outputs of ${root} (${sizeText(entry.bytes)})`));
1882
+ recordGcResult("workspaceOutputs", "done", root, { bytes: entry.bytes });
1883
+ }
1884
+ if (cleared) console.log(chalk.dim(`Cleared ${formatBytes(cleared)} of workspace build outputs. ${REBUILD_COST}`));
1885
+ return {
1886
+ failures,
1887
+ cleared: clearedRoots
1888
+ };
1889
+ }
1890
+ function stillOrphaned({ dir, projectRoot }) {
1891
+ if (readRecordedRoot(dir, basename$1(dir)).projectRoot !== projectRoot || rootPresence(projectRoot) !== false || !isOnMountedVolume(projectRoot)) return false;
1892
+ return !Object.keys(loadConfig$1()?.projects ?? {}).some((key) => isPathPrefix(projectRoot, key));
1893
+ }
1894
+ async function deleteOrphanedWorkspaces(orphaned) {
1895
+ let failures = 0;
1896
+ for (const entry of orphaned) {
1897
+ if (!existsSync$1(entry.dir)) continue;
1898
+ let run;
1899
+ try {
1900
+ run = await withIdleWorkspace(entry.projectRoot, async () => {
1901
+ if (!stillOrphaned(entry)) return false;
1902
+ const browser = await teardownOwnedBrowser(entry.projectRoot, { deleteProfile: true });
1903
+ if (browser.status === "failed" || browser.status === "skipped") throw new Error(`its owned Chrome profile was kept: ${browser.reason}`);
1904
+ emptyWorkspaceDir(entry.dir);
1905
+ return true;
1906
+ }, { purpose: "gc" });
1907
+ } catch (error) {
1908
+ failures++;
1909
+ console.log(chalk.red(`Could not remove ${entry.dir}: ${error?.message || error}`));
1910
+ recordGcResult("workspaceDirectory", "failed", entry.dir, {
1911
+ bytes: entry.bytes ?? null,
1912
+ detail: error?.message || String(error)
1913
+ });
1914
+ continue;
1915
+ }
1916
+ if (!run.ran) {
1917
+ console.log(chalk.yellow(`Kept ${entry.dir}: ${run.reasons.join("; ")}`));
1918
+ recordGcResult("workspaceDirectory", "kept", entry.dir, {
1919
+ bytes: entry.bytes ?? null,
1920
+ detail: run.reasons.join("; ")
1921
+ });
1922
+ continue;
1923
+ }
1924
+ if (!run.value) {
1925
+ console.log(chalk.yellow(`Kept ${entry.dir}: it can no longer be confirmed orphaned.`));
1926
+ recordGcResult("workspaceDirectory", "kept", entry.dir, {
1927
+ bytes: entry.bytes ?? null,
1928
+ detail: "it can no longer be confirmed orphaned"
1929
+ });
1930
+ continue;
1931
+ }
1932
+ const size = entry.bytes === void 0 ? "" : ` (${sizeText(entry.bytes)})`;
1933
+ console.log(chalk.green(`Removed the orphaned workspace directory ${entry.dir}${size}`));
1934
+ recordGcResult("workspaceDirectory", "done", entry.dir, { bytes: entry.bytes ?? null });
1935
+ }
1936
+ return failures;
1937
+ }
1938
+ function sizeText(bytes) {
1939
+ return bytes === null ? "size unknown" : formatBytes(bytes);
1940
+ }
1941
+ //#endregion
1942
+ export { teardownParkedAvd as A, runningBundleInstances as C, teardownOwnedAvd as D, teardownBrowserHeld as E, recordGcResult as F, takeGcResults as I, canonicalPath as L, acquireBuildSlot as M, listBuildSlots as N, teardownOwnedBrowser as O, releaseBuildSlot as P, probePublicHttp as S, eraseParkedIosSim as T, terminateChild as _, collectWorkspaceOutputs as a, withManagedTunnelLock as b, listWorkspaceDirs as c, emptyWorkspaceDir as d, withIdleWorkspace as f, stopTunnel as g, startTunnelSequence as h, collectOrphanedWorkspaces as i, teardownParkedIosSim as j, teardownOwnedIosSim as k, rootPresence as l, resolveSupervisorTarget as m, WORKSPACE_OUTPUT_DIRS as n, deleteOrphanedWorkspaces as o, workspaceInUse as p, clearWorkspaceOutputs as r, isInsideWorkspaces as s, REBUILD_COST as t, sizeText as u, withManagedRemoteWorktreeLock as v, eraseParkedAvd as w, withManagedTunnelRemovalLock as x, withManagedRemoteWorktreeRemovalLock as y };