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,38 +1,33 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { A as directorySize, D as withConfigLock$1, F as volumeRootFor, H as projectDeviceSlots, M as isOnMountedVolume, P as measuredDirectorySize, _ as loadConfig$1, a as clearDevice, d as getConfigDir, j as formatBytes, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
3
- import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
- import { i as registeredCaches } from "./cache-manifest-DnUHBJaU.mjs";
5
- import { l as phaseLine, o as formatLongDuration, u as plural } from "./command-output-CDAIFD-8.mjs";
6
- import { l as resolveProjectMetro, r as killMetroTree } from "./metro-g8NqiJp-.mjs";
7
- import { d as sharedBuildCache, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-DqcCbpE7.mjs";
8
- import { a as capacity, l as environmentState, u as formatSpace } from "./status-CzS4bPO9.mjs";
9
- import { i as recordGcResult, n as withIdleWorkspace, o as canonicalPath } from "./in-use-CvGOUn-x.mjs";
10
- import { i as createDeviceProcessTables, p as workspaceActivity } from "./activity-IRvJY_ru.mjs";
11
- import { h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-DpoS36_u.mjs";
12
- import { n as listBuildSlots } from "./build-slots-41v_d2x9.mjs";
13
- import { l as readPidFile, s as clearWorkspaceSupervisor } from "./state-BKa8wNN5.mjs";
14
- import { a as parseWatchmanPid, i as parseWatchmanClients, n as parseTriggerCount, r as parseWatchRoots, t as parseSubscriberNames } from "./watchman-APYjXSQa.mjs";
15
- import { A as listAvds, I as ownedAvdDirectory, at as isStimOwnedSim, ct as dropParked, it as isStimOwnedAvd, pt as readParked, z as ownedAvdSerialResolver } from "./android-B_YNZy61.mjs";
16
- import { _ as parseRuntimeVersion, f as listIosDeviceTypes, u as listAllIosSims } from "./ios-DSfnPfse.mjs";
17
- import { _ as teardownParkedAvd, d as eraseParkedAvd, f as eraseParkedIosSim, g as teardownOwnedIosSim, m as teardownOwnedAvd, t as resolveSupervisorTarget, v as teardownParkedIosSim } from "./ownership-BMLqyBgJ.mjs";
18
- import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
19
- import { i as idleShutdownCandidates, n as collectOwnedDeviceActivity, o as shutDownIdleDevices, s as workspaceBuildInProgress, t as collectIdleDevices } from "./idle-BXG__1BA.mjs";
20
- import { a as collectWorkspaceOutputs, r as clearWorkspaceOutputs } from "./workspaces-Bcib97-6.mjs";
21
- import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
22
- import { l as withdrawDevServerStopRequest, s as requestDevServerStop } from "./stop-cause-rhmGfwvt.mjs";
23
- import { existsSync, readFileSync, statSync, statfsSync } from "node:fs";
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";
3
+ import { a as formatElapsed, l as phaseLine, o as formatLongDuration, u as plural } from "./command-output-Bt8ygHE7.mjs";
4
+ import { A as directorySize, D as withConfigLock$1, F as volumeRootFor, H as projectDeviceSlots, M as isOnMountedVolume, P as measuredDirectorySize, _ as loadConfig$1, a as clearDevice, d as getConfigDir, j as formatBytes, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
5
+ import { a as updateWorkspaceState, c as writeWorkspaceState, d as sharedBuildCache, r as readWorkspaceState$1, t as clearWorkspaceStateKey, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-CR9X86xJ.mjs";
6
+ import { D as readPidFile, T as clearWorkspaceSupervisor } from "./project-B5eQ1USs.mjs";
7
+ import { r as killMetroTree, u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
8
+ import { a as parseWatchmanPid, d as capacity, g as formatSpace, h as environmentState, i as parseWatchmanClients, n as parseTriggerCount, r as parseWatchRoots, t as parseSubscriberNames } from "./watchman-BL1IdOtq.mjs";
9
+ import { i as registeredCaches } from "./cache-manifest-DiwKSyv9.mjs";
10
+ import { A as teardownParkedAvd, D as teardownOwnedAvd, F as recordGcResult, L as canonicalPath, N as listBuildSlots, T as eraseParkedIosSim, a as collectWorkspaceOutputs, f as withIdleWorkspace, j as teardownParkedIosSim, k as teardownOwnedIosSim, m as resolveSupervisorTarget, r as clearWorkspaceOutputs, w as eraseParkedAvd } from "./workspaces-Djb2gfi9.mjs";
11
+ import { i as createDeviceProcessTables, o as idleForMs, p as workspaceActivity, r as createActivityReader } from "./activity-BSw0x84R.mjs";
12
+ import { h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-Cu7PtQpZ.mjs";
13
+ import { A as listAvds, I as ownedAvdDirectory, at as isStimOwnedSim, ct as dropParked, it as isStimOwnedAvd, pt as readParked, z as ownedAvdSerialResolver } from "./android-BdQC6zs1.mjs";
14
+ import { d as listAllIosSims, p as listIosDeviceTypes, v as parseRuntimeVersion } from "./ios-BWbHFZVz.mjs";
15
+ import { a as withWorkspaceProcessLock, o as workspaceProcessLockError } from "./named-ports-B4iWH4E-.mjs";
16
+ import { c as supervisorError } from "./metro-store-BAHFcJm6.mjs";
17
+ import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
18
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, statfsSync, writeFileSync } from "node:fs";
24
19
  import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
25
- import { existsSync as existsSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
26
- import { homedir, tmpdir } from "os";
27
20
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
28
- import { METRO_NAMED_CACHE_LAYOUT, compiledHelper, configDir } from "@stim-cli/core";
29
- import { MACHINE_OWNER_KINDS, buildWorkerRoot, loadConfig, settingDefinition, settingValueError } from "@stim-cli/core/state";
21
+ import { BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, DEV_SERVER_STOP_REQUEST_KEY, LAST_BUILD_KEYS, MACHINE_OWNER_KINDS, STATS_VERSION, buildWorkerRoot, decodeStats, isJsonObject, loadConfig, parseMissReason, readDevServerStop, readDevServerStopRequest, readRunEstimates, readStats as readStats$1, settingDefinition, settingValueError, statsFile, statsProjectKey as statsProjectKey$1, trimCapacityRefusals, trimCapacityWaits, trimSamples, wholePhases, workspaceBuildDetailFile } from "@stim-cli/core/state";
30
22
  import { fileURLToPath } from "node:url";
31
- import { homedir as homedir$1, platform, totalmem as totalmem$1 } from "node:os";
23
+ import { homedir, platform, totalmem } from "node:os";
32
24
  import chalk from "chalk";
25
+ import { existsSync as existsSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
26
+ import { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, compiledHelper, configDir } from "@stim-cli/core";
27
+ import { homedir as homedir$1, tmpdir as tmpdir$1 } from "os";
33
28
  //#region src/cache/caches.ts
34
29
  function xcodeDerivedDataRoot() {
35
- return join$1(homedir(), "Library", "Developer", "Xcode", "DerivedData");
30
+ return join$1(homedir$1(), "Library", "Developer", "Xcode", "DerivedData");
36
31
  }
37
32
  function compilationCache() {
38
33
  const dir = join$1(xcodeDerivedDataRoot(), "CompilationCache.noindex");
@@ -45,7 +40,7 @@ function compilationCache() {
45
40
  };
46
41
  }
47
42
  function gradleBuildCache() {
48
- const gradleHome = process.env.GRADLE_USER_HOME || join$1(homedir(), ".gradle");
43
+ const gradleHome = process.env.GRADLE_USER_HOME || join$1(homedir$1(), ".gradle");
49
44
  const dir = resolve$1(gradleHome, "caches", "build-cache-1");
50
45
  if (!existsSync$1(dir)) return null;
51
46
  return {
@@ -56,7 +51,7 @@ function gradleBuildCache() {
56
51
  };
57
52
  }
58
53
  function metroFileMaps() {
59
- const root = tmpdir();
54
+ const root = tmpdir$1();
60
55
  if (!existsSync$1(root)) return null;
61
56
  let names;
62
57
  try {
@@ -201,7 +196,7 @@ function canonicalCacheDir(dir) {
201
196
  function sizeCaches(caches) {
202
197
  return caches.map((c) => Object.assign({}, c, { bytes: c.bytes ?? directorySize(c.dir) }));
203
198
  }
204
- function pruneCache(cache, { olderThanDays, now = Date.now() } = {}) {
199
+ function pruneCache(cache, { olderThanDays, now = Date.now(), protect, evictBytes, byMtime = false } = {}) {
205
200
  const cutoff = now - olderThanDays * 24 * 60 * 60 * 1e3;
206
201
  if (cache.prune === "report-only") return {
207
202
  removed: 0,
@@ -214,27 +209,38 @@ function pruneCache(cache, { olderThanDays, now = Date.now() } = {}) {
214
209
  skipped: "index-backed; empty it whole or not at all"
215
210
  };
216
211
  const entries = cache.files ?? entriesAtDepth(cache.dir, cache.entriesDepth ?? 1);
212
+ const candidates = [];
213
+ let protectedEntries = 0;
214
+ for (const entry of entries) try {
215
+ const st = statSync$1(entry);
216
+ const used = byMtime ? st.mtimeMs : Math.max(st.atimeMs, st.mtimeMs);
217
+ if (used >= cutoff) continue;
218
+ if (protect?.(entry)) {
219
+ protectedEntries++;
220
+ continue;
221
+ }
222
+ candidates.push({
223
+ entry,
224
+ used,
225
+ isDirectory: st.isDirectory(),
226
+ size: st.size
227
+ });
228
+ } catch {}
229
+ if (evictBytes !== void 0) candidates.sort((a, b) => a.used - b.used);
217
230
  let removed = 0;
218
231
  let bytes = 0;
219
232
  let failed = 0;
220
- for (const entry of entries) {
221
- let used;
222
- let size;
223
- try {
224
- const st = statSync$1(entry);
225
- used = Math.max(st.atimeMs, st.mtimeMs);
226
- size = st.isDirectory() ? directorySize(entry) : st.size;
227
- } catch {
228
- continue;
229
- }
230
- if (used >= cutoff) continue;
233
+ for (const { entry, isDirectory, size } of candidates) {
234
+ if (evictBytes !== void 0 && bytes >= evictBytes) break;
231
235
  try {
236
+ if (!existsSync$1(entry) || statSync$1(entry).mtimeMs >= cutoff) continue;
237
+ const entryBytes = isDirectory ? directorySize(entry) : size;
232
238
  rmSync$1(entry, {
233
239
  recursive: true,
234
240
  force: true
235
241
  });
236
242
  removed++;
237
- bytes += size;
243
+ bytes += entryBytes;
238
244
  } catch {
239
245
  failed++;
240
246
  }
@@ -243,7 +249,8 @@ function pruneCache(cache, { olderThanDays, now = Date.now() } = {}) {
243
249
  removed,
244
250
  bytes,
245
251
  failed,
246
- skipped: null
252
+ skipped: null,
253
+ protectedEntries
247
254
  };
248
255
  }
249
256
  function entriesAtDepth(dir, depth) {
@@ -1524,8 +1531,8 @@ function ownsItsDirectory(cache) {
1524
1531
  const dir = canonicalPath(cache.dir);
1525
1532
  if (dirname$1(dir) === dir) return false;
1526
1533
  return ![
1527
- homedir(),
1528
- tmpdir(),
1534
+ homedir$1(),
1535
+ tmpdir$1(),
1529
1536
  getConfigDir()
1530
1537
  ].map(canonicalPath).includes(dir);
1531
1538
  }
@@ -2112,6 +2119,1322 @@ function deleteProjectDevices(orphanedDevices, staleDevices, staleDeviceRecords)
2112
2119
  return deleteFailures;
2113
2120
  }
2114
2121
  //#endregion
2122
+ //#region src/engine/stats.ts
2123
+ const PLACEMENT_MAX_AGE_MS = 6048e5;
2124
+ function emptyStats() {
2125
+ return {
2126
+ version: STATS_VERSION,
2127
+ machine: {},
2128
+ projects: {}
2129
+ };
2130
+ }
2131
+ function updateStats(record, run, now) {
2132
+ const at = new Date(now).toISOString();
2133
+ const durationMs = wholeMs(run.durationMs);
2134
+ const phases = {
2135
+ coldBuildMs: wholeMs(run.coldBuildMs),
2136
+ podsMs: wholeMs(run.podsMs)
2137
+ };
2138
+ const projects = { ...record.projects };
2139
+ const scope = { ...projects[run.projectKey] };
2140
+ const machine = { ...record.machine };
2141
+ const before = scope[run.platform] ?? null;
2142
+ const credit = creditMs(before, run, durationMs);
2143
+ scope[run.platform] = applyRun(before, run, {
2144
+ at,
2145
+ durationMs,
2146
+ credit,
2147
+ phases
2148
+ });
2149
+ projects[run.projectKey] = scope;
2150
+ machine[run.platform] = applyRun(machine[run.platform] ?? null, run, {
2151
+ at,
2152
+ durationMs,
2153
+ credit,
2154
+ phases
2155
+ });
2156
+ const history = { ...record.history };
2157
+ if (run.phases && !run.failed && !run.waitedForBuild && !run.offloadedTo) {
2158
+ const outcome = isHit(run.cacheHit) ? "hit" : "cold";
2159
+ const project = { ...history[run.projectKey] };
2160
+ const lists = { ...project[run.platform] };
2161
+ const sample = {
2162
+ at,
2163
+ durationMs,
2164
+ phases: wholePhases(run.phases),
2165
+ ...run.deviceSetup === void 0 ? {} : { deviceSetup: run.deviceSetup }
2166
+ };
2167
+ lists[outcome] = trimSamples([...lists[outcome] ?? [], sample]);
2168
+ project[run.platform] = lists;
2169
+ history[run.projectKey] = project;
2170
+ }
2171
+ let placements = record.placements;
2172
+ let buildMachines = record.buildMachines;
2173
+ if (run.placement) {
2174
+ const placement = buildPlacement(run, before, at);
2175
+ placements = trimPlacements([...placements ?? [], placement], now);
2176
+ if (placement.machine && placement.decision !== "here") buildMachines = {
2177
+ ...buildMachines,
2178
+ [placement.machine]: applyPlacement(buildMachines?.[placement.machine], placement)
2179
+ };
2180
+ }
2181
+ const capacityRefusals = trimCapacityRefusals(record.capacityRefusals ?? [], now);
2182
+ const capacityWaits = trimCapacityWaits(record.capacityWaits ?? [], now);
2183
+ return {
2184
+ version: STATS_VERSION,
2185
+ machine,
2186
+ projects,
2187
+ ...Object.keys(history).length ? { history } : {},
2188
+ ...placements?.length ? { placements } : {},
2189
+ ...capacityRefusals.length ? { capacityRefusals } : {},
2190
+ ...capacityWaits.length ? { capacityWaits } : {},
2191
+ ...buildMachines && Object.keys(buildMachines).length ? { buildMachines } : {}
2192
+ };
2193
+ }
2194
+ function buildPlacement(run, before, at) {
2195
+ const placement = run.placement;
2196
+ const buildMs = wholeMs(placement.decision === "offloaded" ? placement.buildMs : run.coldBuildMs);
2197
+ const localEstimateMs = wholeMs(before?.lastColdBuildMs);
2198
+ const slotWaitMs = wholeMs(placement.slotWaitMs);
2199
+ const deviceSlotWaitMs = wholeMs(placement.deviceSlotWaitMs);
2200
+ return {
2201
+ at,
2202
+ project: run.projectKey,
2203
+ platform: run.platform,
2204
+ decision: placement.decision,
2205
+ reason: placement.reason,
2206
+ ...placement.machine ? { machine: placement.machine } : {},
2207
+ ...buildMs > 0 ? { buildMs } : {},
2208
+ ...slotWaitMs > 0 ? { slotWaitMs } : {},
2209
+ ...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {},
2210
+ ...localEstimateMs > 0 ? { localEstimateMs } : {},
2211
+ ...run.failed ? { failed: true } : {}
2212
+ };
2213
+ }
2214
+ function applyPlacement(totals, placement) {
2215
+ const next = totals ? { ...totals } : {
2216
+ offloaded: 0,
2217
+ offloadedMs: 0,
2218
+ savedMs: 0,
2219
+ fallbacks: 0
2220
+ };
2221
+ if (placement.decision === "fell-back") {
2222
+ next.fallbacks += 1;
2223
+ next.lastFallbackAt = placement.at;
2224
+ return next;
2225
+ }
2226
+ next.offloaded += 1;
2227
+ next.offloadedMs += placement.buildMs ?? 0;
2228
+ if (placement.localEstimateMs && placement.buildMs) next.savedMs += placement.localEstimateMs - placement.buildMs;
2229
+ next.lastOffloadAt = placement.at;
2230
+ return next;
2231
+ }
2232
+ function trimPlacements(placements, now) {
2233
+ return placements.filter((each) => now - Date.parse(each.at) <= PLACEMENT_MAX_AGE_MS).slice(-100);
2234
+ }
2235
+ function recordRunStats(run, now) {
2236
+ return withConfigLock$1(() => {
2237
+ const path = statsFile();
2238
+ const loaded = loadForUpdate(path, now);
2239
+ if (loaded.newerVersion !== null) return {
2240
+ recorded: false,
2241
+ note: `Run statistics at ${path} are version ${loaded.newerVersion}, which this Stim does not understand, so this run was not recorded.`
2242
+ };
2243
+ writeStats(path, updateStats(loaded.record, run, now));
2244
+ return {
2245
+ recorded: true,
2246
+ note: loaded.note
2247
+ };
2248
+ });
2249
+ }
2250
+ function recordCapacityRefusal(event, now) {
2251
+ try {
2252
+ withConfigLock$1(() => {
2253
+ const path = statsFile();
2254
+ const loaded = loadForUpdate(path, now, false);
2255
+ if (!loaded.record || loaded.newerVersion !== null) return;
2256
+ const capacityRefusals = trimCapacityRefusals([...loaded.record.capacityRefusals ?? [], {
2257
+ ...event,
2258
+ at: new Date(now).toISOString(),
2259
+ kind: "device"
2260
+ }], now);
2261
+ writeStats(path, {
2262
+ ...loaded.record,
2263
+ capacityRefusals
2264
+ });
2265
+ });
2266
+ } catch {}
2267
+ }
2268
+ function recordCapacityWait(event, now) {
2269
+ try {
2270
+ withConfigLock$1(() => {
2271
+ const path = statsFile();
2272
+ const loaded = loadForUpdate(path, now, false);
2273
+ if (!loaded.record || loaded.newerVersion !== null) return;
2274
+ const capacityWaits = trimCapacityWaits([...loaded.record.capacityWaits ?? [], {
2275
+ platform: event.platform,
2276
+ max: event.max,
2277
+ workspace: event.workspace,
2278
+ ms: wholeMs(event.ms),
2279
+ ...event.reclaimed && Number.isInteger(event.reclaimed) && event.reclaimed > 0 ? { reclaimed: event.reclaimed } : {},
2280
+ at: new Date(now).toISOString(),
2281
+ kind: "device-wait"
2282
+ }], now);
2283
+ writeStats(path, {
2284
+ ...loaded.record,
2285
+ capacityWaits
2286
+ });
2287
+ });
2288
+ } catch {}
2289
+ }
2290
+ function createRunRecorder({ platform, write, now, note, phases, deviceSetup }) {
2291
+ let projectKey = null;
2292
+ let cacheKey = null;
2293
+ let coldBuildMs = 0;
2294
+ let podsMs = 0;
2295
+ let placement = null;
2296
+ let deviceSlotWaitMs = 0;
2297
+ let recorded = false;
2298
+ return {
2299
+ setProject(key) {
2300
+ projectKey = key;
2301
+ },
2302
+ setCacheKey(key) {
2303
+ cacheKey = key;
2304
+ },
2305
+ setBuildMs(ms) {
2306
+ coldBuildMs = wholeMs(ms);
2307
+ },
2308
+ setPodsMs(ms) {
2309
+ podsMs = wholeMs(ms);
2310
+ },
2311
+ addDeviceSlotWaitMs(ms) {
2312
+ deviceSlotWaitMs += wholeMs(ms);
2313
+ },
2314
+ deviceSlotWaitMs() {
2315
+ return deviceSlotWaitMs || void 0;
2316
+ },
2317
+ setPlacement(next) {
2318
+ placement = next;
2319
+ },
2320
+ record({ failed, cacheHit = false, waited = null, durationMs, offloadedTo = null }) {
2321
+ if (!projectKey || !cacheKey || recorded) return;
2322
+ recorded = true;
2323
+ const ran = failed ? {} : phases?.() ?? {};
2324
+ try {
2325
+ const outcome = write({
2326
+ platform,
2327
+ projectKey,
2328
+ failed,
2329
+ cacheHit,
2330
+ waitedForBuild: Boolean(waited),
2331
+ durationMs,
2332
+ ...offloadedTo ? { offloadedTo } : {},
2333
+ ...coldBuildMs > 0 ? { coldBuildMs } : {},
2334
+ ...podsMs > 0 ? { podsMs } : {},
2335
+ ...Object.keys(ran).length ? { phases: ran } : {},
2336
+ ...failed || deviceSetup?.() === void 0 ? {} : { deviceSetup: deviceSetup() },
2337
+ ...placement ? { placement: {
2338
+ ...placement,
2339
+ ...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {}
2340
+ } } : {}
2341
+ }, now());
2342
+ if (outcome?.note) note(outcome.note);
2343
+ } catch (error) {
2344
+ note(`Run statistics could not be recorded: ${error?.message || error}`);
2345
+ }
2346
+ }
2347
+ };
2348
+ }
2349
+ function loadForUpdate(path, now, recoverCorrupt = true) {
2350
+ let text;
2351
+ try {
2352
+ text = readFileSync(path, "utf-8");
2353
+ } catch {
2354
+ return {
2355
+ record: emptyStats(),
2356
+ note: null,
2357
+ newerVersion: null
2358
+ };
2359
+ }
2360
+ const parsed = decodeStats(text);
2361
+ if (!parsed.record && parsed.newerVersion === null) {
2362
+ if (!recoverCorrupt) return {
2363
+ record: null,
2364
+ note: null,
2365
+ newerVersion: null
2366
+ };
2367
+ const aside = `${path}.corrupt-${now}`;
2368
+ renameSync(path, aside);
2369
+ return {
2370
+ record: emptyStats(),
2371
+ note: `Run statistics at ${path} could not be read, so they were moved to ${aside} and a new file was started.`,
2372
+ newerVersion: null
2373
+ };
2374
+ }
2375
+ if (parsed.newerVersion !== null) return {
2376
+ record: emptyStats(),
2377
+ note: null,
2378
+ newerVersion: parsed.newerVersion
2379
+ };
2380
+ return {
2381
+ record: parsed.record,
2382
+ note: null,
2383
+ newerVersion: null
2384
+ };
2385
+ }
2386
+ function writeStats(path, record) {
2387
+ const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
2388
+ writeFileSync(tmp, `${JSON.stringify(record)}\n`);
2389
+ try {
2390
+ renameSync(tmp, path);
2391
+ } catch (error) {
2392
+ rmSync(tmp, { force: true });
2393
+ throw error;
2394
+ }
2395
+ }
2396
+ function applyRun(bucket, run, { at, durationMs, credit, phases }) {
2397
+ const next = bucket ? { ...bucket } : {
2398
+ runs: 0,
2399
+ failed: 0,
2400
+ hits: 0,
2401
+ misses: 0,
2402
+ coldRuns: 0,
2403
+ coldRunMs: 0,
2404
+ hitRuns: 0,
2405
+ hitRunMs: 0,
2406
+ timeSavedMs: 0,
2407
+ firstRunAt: at,
2408
+ lastRunAt: at
2409
+ };
2410
+ next.runs += 1;
2411
+ next.lastRunAt = at;
2412
+ if (phases.coldBuildMs > 0) next.lastColdBuildMs = phases.coldBuildMs;
2413
+ if (phases.podsMs > 0) next.lastPodsMs = phases.podsMs;
2414
+ if (run.failed) {
2415
+ next.failed += 1;
2416
+ return next;
2417
+ }
2418
+ if (isHit(run.cacheHit)) {
2419
+ next.hits += 1;
2420
+ if (!run.waitedForBuild) {
2421
+ next.hitRuns += 1;
2422
+ next.hitRunMs += durationMs;
2423
+ next.timeSavedMs += credit;
2424
+ }
2425
+ return next;
2426
+ }
2427
+ next.misses += 1;
2428
+ if (run.offloadedTo) {
2429
+ next.offloadedRuns = (next.offloadedRuns ?? 0) + 1;
2430
+ next.offloadedRunMs = (next.offloadedRunMs ?? 0) + durationMs;
2431
+ next.lastOffloadHost = run.offloadedTo;
2432
+ return next;
2433
+ }
2434
+ next.coldRuns += 1;
2435
+ next.coldRunMs += durationMs;
2436
+ return next;
2437
+ }
2438
+ function creditMs(bucket, run, durationMs) {
2439
+ if (run.failed || !isHit(run.cacheHit) || run.waitedForBuild) return 0;
2440
+ if (!bucket || bucket.coldRuns <= 0) return 0;
2441
+ return Math.max(0, Math.round(bucket.coldRunMs / bucket.coldRuns) - durationMs);
2442
+ }
2443
+ function isHit(cacheHit) {
2444
+ return cacheHit === "local" || cacheHit === "remote";
2445
+ }
2446
+ function wholeMs(value) {
2447
+ const ms = Number(value);
2448
+ return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : 0;
2449
+ }
2450
+ //#endregion
2451
+ //#region src/engine/build-detail.ts
2452
+ const LINE_MAX = 160;
2453
+ const TARGET_GRAPH = /^note: Target dependency graph \((\d+) targets?\)/;
2454
+ const XCODE_ACTION = /^([A-Z][A-Za-z]+)\s(.*)\s\(in target '([^']+)' from project '([^']+)'\)$/;
2455
+ const XCODE_CONFIGURE = /^(ComputeTargetDependencyGraph|CreateBuildDescription|CreateBuildRequest|Resolve Package Graph|Prepare packages)$/;
2456
+ const GRADLE_TASK = /^> Task (:\S+)/;
2457
+ /**
2458
+ * xcodebuild actions that end a target's work: a clean build touches each product last, and an incremental build
2459
+ * that touches nothing still signs framework products last. Targets that end any other way are not counted.
2460
+ */
2461
+ const XCODE_TARGET_DONE = /^(Touch|RegisterExecutionPolicyException|CodeSign)$/;
2462
+ const GRADLE_CONFIGURE = /^> Configure project /;
2463
+ /**
2464
+ * SwiftPM prints `[done / total] name` once it plans the build (with U+2009 thin spaces around the slash in Swift 6.4
2465
+ * output), `[done/total] Compiling ...` in older toolchains; Swift 6.4 names the target being worked on, and
2466
+ * `<product>-product` is the link of a product.
2467
+ */
2468
+ const SWIFTPM_PROGRESS = /^\[(\d+)\s*\/\s*(\d+)\](?:\s+(.*))?$/;
2469
+ const SWIFTPM_CONFIGURE = /^(Fetching|Fetched|Computing version|Computed|Creating working copy|Working copy of)\b|^\[(Pre-planning|Planning|Using on-disk description)/;
2470
+ const XCODE_STEPS = [
2471
+ [/^(CpResource|CopyPNGFile|CopyStringsFile|CompileAssetCatalog\w*|CompileStoryboard|CompileXIB|LinkStoryboards|ProcessInfoPlistFile)$/, "resources"],
2472
+ [/^(Compile\w*|Swift\w*|ScanDependencies|Precompile\w*)$/, "compile"],
2473
+ [/^(Ld|Libtool|CreateUniversalBinary|GenerateDSYMFile)$/, "link"],
2474
+ [/^PhaseScriptExecution$/, "script"],
2475
+ [/^CodeSign$/, "sign"]
2476
+ ];
2477
+ const GRADLE_STEPS = [
2478
+ [/[Dd]ex/, "dex"],
2479
+ [/^(createBundle\w*JsAndAssets|generateCodegen\w*)$/, "script"],
2480
+ [/(Resources?|Assets|Manifest|ResValues|RFile|JavaRes)$/, "resources"],
2481
+ [/^(compile|kapt|ksp|javaPreCompile|buildCMake|configureCMake|externalNativeBuild)/, "compile"],
2482
+ [/^(package|assemble|install|zipalign|validateSigning|merge\w*NativeLibs|strip\w*Symbols)/, "package"]
2483
+ ];
2484
+ function stepOf(name, table) {
2485
+ return table.find(([pattern]) => pattern.test(name))?.[1] ?? null;
2486
+ }
2487
+ function clip(text) {
2488
+ return text.length > LINE_MAX ? `${text.slice(0, 157)}...` : text;
2489
+ }
2490
+ function unescape(token) {
2491
+ return token.replace(/\\(.)/g, "$1");
2492
+ }
2493
+ function baseName(path) {
2494
+ return path.split("/").findLast(Boolean) ?? path;
2495
+ }
2496
+ /**
2497
+ * An xcodebuild action line in short form: the action, the file it works on and its target, as in
2498
+ * `CompileC sqlite3.c (sqlite3)`. The file is the last absolute path in the arguments, which xcodebuild prints
2499
+ * as the source for compile, copy and plist steps and as the product for link and sign steps; a script phase
2500
+ * shows its name instead.
2501
+ */
2502
+ function shortXcodeAction(action, args, target) {
2503
+ const tokens = args.match(/(?:\\.|\S)+/g) ?? [];
2504
+ const subject = action === "PhaseScriptExecution" ? unescape(tokens[0] ?? "") : baseName(unescape(tokens.findLast((token) => token.startsWith("/")) ?? ""));
2505
+ return clip(`${action}${subject ? ` ${subject}` : ""} (${target})`);
2506
+ }
2507
+ function swiftpmStep(text) {
2508
+ return /^Linking\b|-product$/.test(text) ? "link" : "compile";
2509
+ }
2510
+ /** What one line of xcodebuild, Gradle or SwiftPM output says about the build's progress, or null for any other line. */
2511
+ function parseBuildToolLine(msg) {
2512
+ const counted = SWIFTPM_PROGRESS.exec(msg);
2513
+ if (counted) {
2514
+ const text = counted[3]?.trim() ?? "";
2515
+ return {
2516
+ kind: "count",
2517
+ done: Number(counted[1]),
2518
+ total: Number(counted[2]),
2519
+ step: swiftpmStep(text),
2520
+ line: text ? clip(text) : null
2521
+ };
2522
+ }
2523
+ if (SWIFTPM_CONFIGURE.test(msg)) return { kind: "configure" };
2524
+ const graph = TARGET_GRAPH.exec(msg);
2525
+ if (graph) return {
2526
+ kind: "total",
2527
+ unit: "targets",
2528
+ total: Number(graph[1])
2529
+ };
2530
+ if (XCODE_CONFIGURE.test(msg) || GRADLE_CONFIGURE.test(msg)) return { kind: "configure" };
2531
+ const action = XCODE_ACTION.exec(msg);
2532
+ if (action) {
2533
+ const [, name, args, target, project] = action;
2534
+ const step = stepOf(name, XCODE_STEPS);
2535
+ return {
2536
+ kind: "unit",
2537
+ unit: "targets",
2538
+ id: `${project}/${target}`,
2539
+ step,
2540
+ line: step ? shortXcodeAction(name, args, target) : null,
2541
+ finished: XCODE_TARGET_DONE.test(name)
2542
+ };
2543
+ }
2544
+ const task = GRADLE_TASK.exec(msg);
2545
+ if (task) {
2546
+ const path = task[1];
2547
+ return {
2548
+ kind: "unit",
2549
+ unit: "tasks",
2550
+ id: path,
2551
+ step: stepOf(path.slice(path.lastIndexOf(":") + 1), GRADLE_STEPS),
2552
+ line: clip(`> Task ${path}`),
2553
+ finished: false
2554
+ };
2555
+ }
2556
+ return null;
2557
+ }
2558
+ /**
2559
+ * Accumulates a build's tool output into its detail: xcodebuild counts the distinct targets it finished against the
2560
+ * total its dependency graph note gives; Gradle counts the task lines it printed and has no total; SwiftPM reports
2561
+ * its own `[done / total]` counts, which the parser passes through.
2562
+ */
2563
+ function createBuildDetailParser() {
2564
+ let seen = false;
2565
+ let step = null;
2566
+ let unit = null;
2567
+ let total = null;
2568
+ let line = null;
2569
+ let tasks = 0;
2570
+ let counted = null;
2571
+ const targets = /* @__PURE__ */ new Set();
2572
+ return {
2573
+ push(msg) {
2574
+ const parsed = parseBuildToolLine(msg);
2575
+ if (!parsed) return false;
2576
+ seen = true;
2577
+ if (parsed.kind === "total") {
2578
+ unit = "targets";
2579
+ total = parsed.total;
2580
+ return true;
2581
+ }
2582
+ if (parsed.kind === "configure") {
2583
+ step = "configure";
2584
+ return true;
2585
+ }
2586
+ if (parsed.kind === "count") {
2587
+ unit = "steps";
2588
+ counted = {
2589
+ done: parsed.done,
2590
+ total: parsed.total
2591
+ };
2592
+ step = parsed.step;
2593
+ if (parsed.line) line = parsed.line;
2594
+ return true;
2595
+ }
2596
+ unit = parsed.unit;
2597
+ if (parsed.unit === "tasks") tasks += 1;
2598
+ else if (parsed.finished) targets.add(parsed.id);
2599
+ if (parsed.step) step = parsed.step;
2600
+ if (parsed.line) line = parsed.line;
2601
+ return true;
2602
+ },
2603
+ detail(updatedAt) {
2604
+ if (!seen) return null;
2605
+ if (unit === "steps" && counted) return {
2606
+ step,
2607
+ unit,
2608
+ done: Math.min(counted.done, counted.total),
2609
+ total: counted.total,
2610
+ line,
2611
+ updatedAt
2612
+ };
2613
+ const done = unit === "tasks" ? tasks : unit === "targets" ? targets.size : null;
2614
+ return {
2615
+ step,
2616
+ unit,
2617
+ done: done !== null && total !== null ? Math.min(done, total) : done,
2618
+ total: unit === "tasks" ? null : total,
2619
+ line,
2620
+ updatedAt
2621
+ };
2622
+ }
2623
+ };
2624
+ }
2625
+ //#endregion
2626
+ //#region src/engine/build-progress.ts
2627
+ const ACTIVE_BUILD_KEY = "activeBuild";
2628
+ const NO_BUILD_PROGRESS = {
2629
+ step: () => {},
2630
+ estimate: () => {},
2631
+ miss: () => {},
2632
+ hit: () => {},
2633
+ deviceSetup: () => {},
2634
+ deviceSetupKnown: () => void 0,
2635
+ place: () => {},
2636
+ waitingOn: () => {},
2637
+ waitingFor: () => {},
2638
+ output: () => {},
2639
+ durations: () => ({}),
2640
+ steps: () => null,
2641
+ clear: () => {}
2642
+ };
2643
+ /** `writer`, with each record it writes also passed to `progress.output`. */
2644
+ function tapBuildLog(writer, progress) {
2645
+ if (progress === NO_BUILD_PROGRESS) return writer;
2646
+ return {
2647
+ get file() {
2648
+ return writer.file;
2649
+ },
2650
+ write(record) {
2651
+ progress.output(record);
2652
+ return writer.write(record);
2653
+ },
2654
+ close: () => writer.close(),
2655
+ get written() {
2656
+ return writer.written;
2657
+ },
2658
+ get dropped() {
2659
+ return writer.dropped;
2660
+ },
2661
+ get lastError() {
2662
+ return writer.lastError;
2663
+ }
2664
+ };
2665
+ }
2666
+ const DETAIL_WRITE_MS = 2e3;
2667
+ function toolLine(record) {
2668
+ if (!record || typeof record !== "object") return null;
2669
+ const { src, level, msg } = record;
2670
+ return src === "build" && level === "debug" && typeof msg === "string" ? msg : null;
2671
+ }
2672
+ function writeBuildDetail(root, claimId, detail) {
2673
+ const file = workspaceBuildDetailFile(root);
2674
+ const tmp = `${file}.tmp-${process.pid}`;
2675
+ mkdirSync(dirname(file), { recursive: true });
2676
+ writeFileSync(tmp, JSON.stringify({
2677
+ claimId,
2678
+ detail
2679
+ }));
2680
+ renameSync(tmp, file);
2681
+ }
2682
+ const COLD_PHASES = [
2683
+ "prebuild",
2684
+ "pods",
2685
+ "compile"
2686
+ ];
2687
+ const HIT_PHASES = ["install", "launch"];
2688
+ function settledOutcome(phase, entered) {
2689
+ if (COLD_PHASES.includes(phase)) return "cold";
2690
+ if (phase === "device") return entered.some((entry) => entry.phase === "cache-lookup") ? "hit" : null;
2691
+ return HIT_PHASES.includes(phase) ? "hit" : null;
2692
+ }
2693
+ function projectHistory(projectKey) {
2694
+ try {
2695
+ return readStats$1().record?.history?.[projectKey];
2696
+ } catch {
2697
+ return;
2698
+ }
2699
+ }
2700
+ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
2701
+ const startedAt = new Date(now()).toISOString();
2702
+ const record = {
2703
+ platform,
2704
+ slot,
2705
+ startedAt,
2706
+ phase: "prepare",
2707
+ phaseStartedAt: startedAt,
2708
+ phases: [{
2709
+ phase: "prepare",
2710
+ startedAt
2711
+ }],
2712
+ claim: {
2713
+ root: claim.root,
2714
+ path: claim.path,
2715
+ claimId: claim.claimId,
2716
+ pid: claim.owner.pid
2717
+ }
2718
+ };
2719
+ let warned = false;
2720
+ const guard = (fn) => {
2721
+ try {
2722
+ fn();
2723
+ } catch (error) {
2724
+ if (warned) return;
2725
+ warned = true;
2726
+ note(`Build progress could not be recorded in the workspace state: ${error?.message || error}`);
2727
+ }
2728
+ };
2729
+ const write = (before = (state) => state) => guard(() => updateWorkspaceState(root, (state) => ({
2730
+ ...before(state),
2731
+ [ACTIVE_BUILD_KEY]: record
2732
+ })));
2733
+ write(withInterruptedBuild);
2734
+ let projectKey = null;
2735
+ const parser = createBuildDetailParser();
2736
+ let detailWrittenAt = -Infinity;
2737
+ let detailTimer = null;
2738
+ const flushDetail = () => {
2739
+ detailTimer = null;
2740
+ detailWrittenAt = now();
2741
+ const detail = parser.detail(new Date(detailWrittenAt).toISOString());
2742
+ if (detail) guard(() => writeBuildDetail(root, record.claim.claimId, detail));
2743
+ };
2744
+ const settle = (outcome) => {
2745
+ record.outcome = outcome;
2746
+ if (projectKey && platform !== "macos") record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
2747
+ };
2748
+ const waits = /* @__PURE__ */ new Map();
2749
+ return {
2750
+ step(phase) {
2751
+ if (phase === record.phase) return;
2752
+ const at = new Date(now()).toISOString();
2753
+ record.phase = phase;
2754
+ record.phaseStartedAt = at;
2755
+ record.phases.push({
2756
+ phase,
2757
+ startedAt: at
2758
+ });
2759
+ if (phase !== "wait") delete record.waitingOn;
2760
+ const outcome = record.outcome || platform === "macos" ? null : settledOutcome(phase, record.phases);
2761
+ if (outcome) settle(outcome);
2762
+ write();
2763
+ },
2764
+ estimate(key) {
2765
+ if (platform === "macos") return;
2766
+ projectKey = key;
2767
+ record.estimate = estimateBuild(projectHistory(key), platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
2768
+ write();
2769
+ },
2770
+ miss(reason, provisional = false) {
2771
+ record.missReason = reason;
2772
+ settle("cold");
2773
+ if (provisional) record.missProvisional = true;
2774
+ else delete record.missProvisional;
2775
+ write();
2776
+ },
2777
+ hit() {
2778
+ delete record.missReason;
2779
+ delete record.missProvisional;
2780
+ settle("hit");
2781
+ write();
2782
+ },
2783
+ deviceSetup(setup) {
2784
+ if (setup === void 0) return;
2785
+ record.deviceSetup = setup;
2786
+ write();
2787
+ },
2788
+ deviceSetupKnown() {
2789
+ return record.deviceSetup;
2790
+ },
2791
+ place(remote) {
2792
+ const current = record.placement;
2793
+ if (!remote) {
2794
+ if (!current) return;
2795
+ delete record.placement;
2796
+ return write();
2797
+ }
2798
+ if (current?.host === remote.host && current.phase === remote.phase) return;
2799
+ const at = new Date(now()).toISOString();
2800
+ record.placement = {
2801
+ host: remote.host,
2802
+ phase: remote.phase,
2803
+ startedAt: current?.host === remote.host ? current.startedAt : at,
2804
+ phaseStartedAt: at
2805
+ };
2806
+ write();
2807
+ },
2808
+ waitingFor(info, kind) {
2809
+ if (info) waits.set(info.kind, info);
2810
+ else if (kind) waits.delete(kind);
2811
+ else waits.clear();
2812
+ const first = [...waits.values()].toSorted((a, b) => Date.parse(a.since) - Date.parse(b.since))[0];
2813
+ if (first) record.waitingFor = first;
2814
+ else delete record.waitingFor;
2815
+ write();
2816
+ },
2817
+ waitingOn(holder) {
2818
+ if (holder === null) {
2819
+ if (!record.waitingOn) return;
2820
+ delete record.waitingOn;
2821
+ } else {
2822
+ if (record.waitingOn?.path === holder) return;
2823
+ record.waitingOn = { path: holder };
2824
+ }
2825
+ write();
2826
+ },
2827
+ output(line) {
2828
+ const msg = toolLine(line);
2829
+ if (msg === null || !parser.push(msg) || detailTimer) return;
2830
+ const wait = detailWrittenAt + DETAIL_WRITE_MS - now();
2831
+ if (wait <= 0) return flushDetail();
2832
+ detailTimer = setTimeout(flushDetail, wait);
2833
+ detailTimer.unref?.();
2834
+ },
2835
+ durations() {
2836
+ return phaseDurations(record.phases, now());
2837
+ },
2838
+ steps() {
2839
+ const detail = parser.detail("");
2840
+ return detail?.unit === "steps" ? detail.total : null;
2841
+ },
2842
+ clear() {
2843
+ if (detailTimer) clearTimeout(detailTimer);
2844
+ detailTimer = null;
2845
+ guard(() => rmSync(workspaceBuildDetailFile(root), { force: true }));
2846
+ guard(() => {
2847
+ clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
2848
+ });
2849
+ }
2850
+ };
2851
+ }
2852
+ function phaseDurations(phases, now) {
2853
+ const out = {};
2854
+ phases.forEach(({ phase, startedAt }, index) => {
2855
+ const start = Date.parse(startedAt);
2856
+ const next = phases[index + 1];
2857
+ const end = next ? Date.parse(next.startedAt) : now;
2858
+ if (!Number.isFinite(start) || !Number.isFinite(end)) return;
2859
+ out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
2860
+ });
2861
+ return out;
2862
+ }
2863
+ function completedPhaseDurations(phases) {
2864
+ if (phases.length < 2) return void 0;
2865
+ const durations = phaseDurations(phases.slice(0, -1), Date.parse(phases.at(-1).startedAt));
2866
+ return Object.keys(durations).length ? durations : void 0;
2867
+ }
2868
+ const HISTORY_FIELDS = [
2869
+ "devicePlacement",
2870
+ "platform",
2871
+ "status",
2872
+ "configuration",
2873
+ "fingerprint",
2874
+ "cacheKey",
2875
+ "cacheHit",
2876
+ "cacheSkipped",
2877
+ "durationMs",
2878
+ "startedAt",
2879
+ "errorCode",
2880
+ "missReason",
2881
+ "buildMachine",
2882
+ "builtOn",
2883
+ "offloadedTo",
2884
+ "offloadFallback",
2885
+ "diagnostics",
2886
+ "compileSteps"
2887
+ ];
2888
+ function withHistoryEntry(state, platform, entry) {
2889
+ const saved = state[BUILD_HISTORY_KEY];
2890
+ const history = saved && typeof saved === "object" && !Array.isArray(saved) ? saved : {};
2891
+ const list = Array.isArray(history[platform]) ? history[platform] : [];
2892
+ return {
2893
+ ...state,
2894
+ [BUILD_HISTORY_KEY]: {
2895
+ ...history,
2896
+ [platform]: [entry, ...list].slice(0, BUILD_HISTORY_LIMIT)
2897
+ }
2898
+ };
2899
+ }
2900
+ function finishedResult(record) {
2901
+ if (record.status === "ok") return "succeeded";
2902
+ return record.errorCode === "STIM_CANCELLED" ? "cancelled" : "failed";
2903
+ }
2904
+ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now = Date.now } = {}) {
2905
+ const platform = record.platform;
2906
+ update(root, (state) => {
2907
+ const active = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
2908
+ const own = active?.platform === platform ? active : null;
2909
+ const entry = {
2910
+ ...Object.fromEntries(HISTORY_FIELDS.filter((key) => key in record).map((key) => [key, record[key]])),
2911
+ result: finishedResult(record),
2912
+ slot: own?.slot ?? "default",
2913
+ phases: own ? phaseDurations(own.phases, now()) : {}
2914
+ };
2915
+ const slot = own?.slot ?? "default";
2916
+ const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
2917
+ const savedSlot = isJsonObject(slots[slot]) ? slots[slot] : {};
2918
+ const savedDevice = slot === "default" ? state[platform] : savedSlot[platform];
2919
+ if (platform !== "macos" && (record.devicePlacement || isJsonObject(savedDevice))) {
2920
+ const device = isJsonObject(savedDevice) ? { ...savedDevice } : {};
2921
+ if (record.devicePlacement) device.devicePlacement = record.devicePlacement;
2922
+ else delete device.devicePlacement;
2923
+ state = slot === "default" ? {
2924
+ ...state,
2925
+ [platform]: device
2926
+ } : {
2927
+ ...state,
2928
+ deviceSlots: {
2929
+ ...slots,
2930
+ [slot]: {
2931
+ ...savedSlot,
2932
+ [platform]: device
2933
+ }
2934
+ }
2935
+ };
2936
+ }
2937
+ if (platform === "macos") return withHistoryEntry(state, platform, entry);
2938
+ return withHistoryEntry({
2939
+ ...state,
2940
+ lastBuild: record,
2941
+ [LAST_BUILD_KEYS[platform]]: record
2942
+ }, platform, entry);
2943
+ });
2944
+ }
2945
+ /** Adds one phase's duration to the recorded run of `platform` that started at `startedAt`. */
2946
+ function recordBuildPhase(root, platform, startedAt, phase, ms) {
2947
+ updateWorkspaceState(root, (state) => {
2948
+ const saved = state[BUILD_HISTORY_KEY];
2949
+ const list = isJsonObject(saved) && Array.isArray(saved[platform]) ? saved[platform] : [];
2950
+ const index = list.findIndex((entry) => isJsonObject(entry) && entry.startedAt === startedAt);
2951
+ const entry = list[index];
2952
+ if (!isJsonObject(entry)) return state;
2953
+ const phases = isJsonObject(entry.phases) ? entry.phases : {};
2954
+ const next = [...list];
2955
+ next[index] = {
2956
+ ...entry,
2957
+ phases: {
2958
+ ...phases,
2959
+ [phase]: Math.round(ms)
2960
+ }
2961
+ };
2962
+ return {
2963
+ ...state,
2964
+ [BUILD_HISTORY_KEY]: {
2965
+ ...saved,
2966
+ [platform]: next
2967
+ }
2968
+ };
2969
+ });
2970
+ }
2971
+ function withInterruptedBuild(state) {
2972
+ const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
2973
+ if (!left) return state;
2974
+ const last = left.platform === "macos" ? state[BUILD_HISTORY_KEY]?.macos?.[0] : state[LAST_BUILD_KEYS[left.platform]];
2975
+ if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
2976
+ return withHistoryEntry(state, left.platform, {
2977
+ platform: left.platform,
2978
+ status: "failed",
2979
+ result: "interrupted",
2980
+ slot: left.slot,
2981
+ configuration: null,
2982
+ fingerprint: null,
2983
+ cacheKey: null,
2984
+ cacheHit: false,
2985
+ cacheSkipped: false,
2986
+ durationMs: null,
2987
+ startedAt: left.startedAt,
2988
+ phases: {
2989
+ ...phaseDurations(left.phases, Date.parse(left.phaseStartedAt)),
2990
+ [left.phase]: 0
2991
+ }
2992
+ });
2993
+ }
2994
+ function parseActiveBuild(value) {
2995
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
2996
+ const record = value;
2997
+ const claim = record.claim;
2998
+ if (record.platform !== "ios" && record.platform !== "android" && record.platform !== "macos") return null;
2999
+ if (!isPhase(record.phase)) return null;
3000
+ if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
3001
+ if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
3002
+ const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
3003
+ const missReason = parseMissReason(record.missReason);
3004
+ const placement = parsePlacement(record.placement);
3005
+ const waitingOn = parseWaitingOn(record.waitingOn);
3006
+ const waitingFor = parseWaitingFor(record.waitingFor);
3007
+ const estimate = parseEstimate(record.estimate);
3008
+ return {
3009
+ platform: record.platform,
3010
+ slot: typeof record.slot === "string" ? record.slot : "default",
3011
+ startedAt: record.startedAt,
3012
+ phase: record.phase,
3013
+ phaseStartedAt: record.phaseStartedAt,
3014
+ phases,
3015
+ ...missReason ? { missReason } : {},
3016
+ ...missReason && record.missProvisional === true ? { missProvisional: true } : {},
3017
+ ...placement ? { placement } : {},
3018
+ ...waitingOn ? { waitingOn } : {},
3019
+ ...waitingFor ? { waitingFor } : {},
3020
+ ...typeof record.deviceSetup === "boolean" ? { deviceSetup: record.deviceSetup } : {},
3021
+ ...record.outcome === "hit" || record.outcome === "cold" ? { outcome: record.outcome } : {},
3022
+ ...estimate ? { estimate } : {},
3023
+ claim: {
3024
+ root: claim.root,
3025
+ path: typeof claim.path === "string" ? claim.path : "",
3026
+ claimId: claim.claimId,
3027
+ pid: typeof claim.pid === "number" ? claim.pid : 0
3028
+ }
3029
+ };
3030
+ }
3031
+ function parsePlacement(value) {
3032
+ if (!value || typeof value !== "object") return null;
3033
+ const { host, phase, startedAt, phaseStartedAt } = value;
3034
+ if ([
3035
+ host,
3036
+ phase,
3037
+ startedAt,
3038
+ phaseStartedAt
3039
+ ].some((field) => typeof field !== "string")) return null;
3040
+ return {
3041
+ host,
3042
+ phase,
3043
+ startedAt,
3044
+ phaseStartedAt
3045
+ };
3046
+ }
3047
+ function parseWaitingFor(value) {
3048
+ if (!value || typeof value !== "object") return null;
3049
+ const { kind, inUse, max, since } = value;
3050
+ if (kind !== "build-slot" && kind !== "device-slot") return null;
3051
+ if (!Number.isInteger(inUse) || inUse < 0 || !Number.isInteger(max) || max <= 0) return null;
3052
+ if (typeof since !== "string" || !Number.isFinite(Date.parse(since))) return null;
3053
+ return {
3054
+ kind,
3055
+ inUse,
3056
+ max,
3057
+ since
3058
+ };
3059
+ }
3060
+ function parseWaitingOn(value) {
3061
+ const path = value?.path;
3062
+ return typeof path === "string" && path ? { path } : null;
3063
+ }
3064
+ function parseEstimate(value) {
3065
+ if (!value || typeof value !== "object") return null;
3066
+ const { outcome, expectedMs, basis, phaseMs, planned } = value;
3067
+ if (outcome !== null && outcome !== "hit" && outcome !== "cold") return null;
3068
+ if (expectedMs !== null && typeof expectedMs !== "number") return null;
3069
+ if (typeof basis !== "number" || !Array.isArray(planned) || !phaseMs || typeof phaseMs !== "object") return null;
3070
+ const durations = Object.entries(phaseMs).filter((entry) => isPhase(entry[0]) && typeof entry[1] === "number");
3071
+ return {
3072
+ outcome,
3073
+ expectedMs,
3074
+ basis,
3075
+ phaseMs: Object.fromEntries(durations),
3076
+ planned: planned.filter(isPhase)
3077
+ };
3078
+ }
3079
+ function isPhase(value) {
3080
+ return BUILD_PHASES.includes(value);
3081
+ }
3082
+ function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
3083
+ if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
3084
+ if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
3085
+ return survey.unresolved.length ? "unknown" : "stale";
3086
+ }
3087
+ function median(values) {
3088
+ if (!values.length) return null;
3089
+ const sorted = values.toSorted((a, b) => a - b);
3090
+ const mid = Math.floor(sorted.length / 2);
3091
+ return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
3092
+ }
3093
+ function estimateBuild(history, platform, known, deviceSetup) {
3094
+ const lists = platform === "macos" ? void 0 : history?.[platform];
3095
+ const outcome = known ?? latestOutcome(lists);
3096
+ const samples = matchDeviceSetup(outcome && lists?.[outcome] || [], deviceSetup);
3097
+ const phaseMs = {};
3098
+ const planned = [];
3099
+ for (const phase of BUILD_PHASES) {
3100
+ const durations = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
3101
+ const ms = median(durations);
3102
+ if (ms === null) continue;
3103
+ phaseMs[phase] = ms;
3104
+ if (durations.length * 2 >= samples.length) planned.push(phase);
3105
+ }
3106
+ return {
3107
+ outcome,
3108
+ expectedMs: median(samples.map((sample) => sample.durationMs)),
3109
+ basis: samples.length,
3110
+ phaseMs,
3111
+ planned
3112
+ };
3113
+ }
3114
+ const MIN_TAGGED_SAMPLES = 3;
3115
+ function matchDeviceSetup(samples, deviceSetup) {
3116
+ if (deviceSetup === void 0) return samples;
3117
+ const tagged = samples.filter((sample) => sample.deviceSetup === deviceSetup);
3118
+ if (deviceSetup || tagged.length >= MIN_TAGGED_SAMPLES) return tagged;
3119
+ return samples.filter((sample) => sample.deviceSetup !== true);
3120
+ }
3121
+ function latestOutcome(lists) {
3122
+ let latest = null;
3123
+ for (const outcome of ["hit", "cold"]) {
3124
+ const last = lists?.[outcome]?.at(-1);
3125
+ const at = last ? Date.parse(last.at) : NaN;
3126
+ if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
3127
+ outcome,
3128
+ at
3129
+ };
3130
+ }
3131
+ return latest?.outcome ?? null;
3132
+ }
3133
+ function buildReport(record, { state, history }) {
3134
+ const estimate = record.estimate ?? estimateBuild(history, record.platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
3135
+ const plannedPhases = estimate.planned.flatMap((phase) => {
3136
+ const expectedMs = estimate.phaseMs[phase];
3137
+ return expectedMs === void 0 ? [] : [{
3138
+ phase,
3139
+ expectedMs
3140
+ }];
3141
+ });
3142
+ const completedPhaseMs = completedPhaseDurations(record.phases);
3143
+ return {
3144
+ platform: record.platform,
3145
+ slot: record.slot,
3146
+ state,
3147
+ phase: record.phase,
3148
+ startedAt: record.startedAt,
3149
+ phaseStartedAt: record.phaseStartedAt,
3150
+ outcome: estimate.outcome,
3151
+ outcomeKnown: record.outcome !== void 0,
3152
+ ...record.outcome && record.phases.some(({ phase }) => phase === "cache-lookup") ? { cacheLookupOutcome: record.outcome === "hit" ? "hit" : "miss" } : {},
3153
+ expectedMs: estimate.expectedMs,
3154
+ expectedPhaseMs: estimate.phaseMs[record.phase] ?? null,
3155
+ ...completedPhaseMs ? { completedPhaseMs } : {},
3156
+ basis: estimate.basis,
3157
+ plannedPhases: plannedPhases.length ? plannedPhases : null,
3158
+ ...record.missReason ? { missReason: record.missReason } : {},
3159
+ ...record.missReason && record.missProvisional ? { missProvisional: true } : {},
3160
+ placement: record.placement ?? "local",
3161
+ ...record.waitingOn ? { waitingOn: record.waitingOn } : {},
3162
+ ...record.waitingFor ? { waitingFor: record.waitingFor } : {}
3163
+ };
3164
+ }
3165
+ function remainingText(remainingMs) {
3166
+ return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
3167
+ }
3168
+ function buildStatusLine(report, now) {
3169
+ const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
3170
+ if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
3171
+ const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
3172
+ const remote = typeof report.placement === "object" ? ` on ${report.placement.host} (${report.placement.phase}, ${formatElapsed(Math.max(0, now - Date.parse(report.placement.phaseStartedAt)))})` : "";
3173
+ const waiting = report.waitingOn ? ` on ${report.waitingOn.path}` : "";
3174
+ const head = `build: ${report.platform}${slot} ${report.phase}${waiting}${remote}, ${formatElapsed(elapsedMs)} elapsed`;
3175
+ if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
3176
+ if (report.expectedMs === null) return head;
3177
+ const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
3178
+ const remainingMs = report.expectedMs - elapsedMs;
3179
+ return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
3180
+ }
3181
+ //#endregion
3182
+ //#region src/commands/gc/idle.ts
3183
+ function findOwnedDeviceActivity({ config, sims, androidSerial, readActivity, deadProjects = [] }) {
3184
+ const booted = new Map(sims.filter((sim) => sim.state === "Booted").map((sim) => [sim.udid, sim.name]));
3185
+ const dead = new Set(deadProjects);
3186
+ const found = [];
3187
+ for (const [project, record] of Object.entries(config?.projects ?? {})) {
3188
+ if (dead.has(project)) continue;
3189
+ for (const { slot, platforms } of projectDeviceSlots(record)) {
3190
+ const ios = platforms.ios;
3191
+ if (ios?.owned && ios.deviceUdid && booted.has(ios.deviceUdid)) found.push({
3192
+ kind: "ios",
3193
+ id: ios.deviceUdid,
3194
+ name: booted.get(ios.deviceUdid) ?? ios.deviceUdid,
3195
+ project,
3196
+ slot,
3197
+ activity: readActivity({
3198
+ platform: "ios",
3199
+ id: ios.deviceUdid,
3200
+ slot,
3201
+ workspace: project
3202
+ })
3203
+ });
3204
+ const android = platforms.android;
3205
+ const serial = android?.owned && android.avdName ? androidSerial(android.avdName) : null;
3206
+ if (android?.avdName && serial) found.push({
3207
+ kind: "android",
3208
+ id: android.avdName,
3209
+ name: android.avdName,
3210
+ project,
3211
+ slot,
3212
+ activity: readActivity({
3213
+ platform: "android",
3214
+ id: serial,
3215
+ slot,
3216
+ workspace: project
3217
+ })
3218
+ });
3219
+ }
3220
+ }
3221
+ return found;
3222
+ }
3223
+ function findIdleDevices({ buildInProgress, now, ...inputs }) {
3224
+ return findOwnedDeviceActivity(inputs).filter((device) => device.activity.state === "idle").map(({ kind, id, name, project, slot, activity }) => ({
3225
+ kind,
3226
+ id,
3227
+ name,
3228
+ project,
3229
+ slot,
3230
+ lastActivityAt: activity.lastActivityAt ?? null,
3231
+ idleForMs: idleForMs(activity, now),
3232
+ buildInProgress: buildInProgress(project)
3233
+ }));
3234
+ }
3235
+ function idleShutdownCandidates(devices, idleMs) {
3236
+ return devices.filter((d) => !d.buildInProgress && d.idleForMs !== null && d.idleForMs >= idleMs);
3237
+ }
3238
+ function parseIdleDuration(value) {
3239
+ const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value.trim());
3240
+ if (!match) return null;
3241
+ const unit = {
3242
+ m: 6e4,
3243
+ h: 36e5,
3244
+ d: 864e5
3245
+ }[match[2]];
3246
+ return Number(match[1]) * unit;
3247
+ }
3248
+ function workspaceBuildInProgress(project) {
3249
+ const record = parseActiveBuild(readWorkspaceState$1(project)?.[ACTIVE_BUILD_KEY]);
3250
+ if (!record) return false;
3251
+ try {
3252
+ return activeBuildState(record.claim) !== "stale";
3253
+ } catch {
3254
+ return true;
3255
+ }
3256
+ }
3257
+ function deviceActivityInputs(config, sims, now) {
3258
+ const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
3259
+ return {
3260
+ config,
3261
+ sims,
3262
+ readActivity: createActivityReader({ now }),
3263
+ androidSerial: (avdName) => {
3264
+ try {
3265
+ return resolve(avdName).serial ?? null;
3266
+ } catch {
3267
+ return null;
3268
+ }
3269
+ }
3270
+ };
3271
+ }
3272
+ function collectOwnedDeviceActivity(config, sims, now = Date.now()) {
3273
+ return findOwnedDeviceActivity(deviceActivityInputs(config, sims, now));
3274
+ }
3275
+ function collectIdleDevices(config, sims, deadProjects, now = Date.now()) {
3276
+ return findIdleDevices({
3277
+ ...deviceActivityInputs(config, sims, now),
3278
+ deadProjects,
3279
+ now,
3280
+ buildInProgress: workspaceBuildInProgress
3281
+ });
3282
+ }
3283
+ function idleDeviceLines(devices) {
3284
+ if (devices.length === 0) return [];
3285
+ return [`Idle owned devices (${devices.length}) - booted with no driver, claim, or recent activity:`, ...devices.map((d) => {
3286
+ const slot = d.slot === "default" ? "" : ` [${d.slot}]`;
3287
+ const idle = d.idleForMs === null ? "idle for an unknown time" : `idle ${formatLongDuration(d.idleForMs)}`;
3288
+ const build = d.buildInProgress ? ", build in progress" : "";
3289
+ return ` ${d.kind}${slot} ${d.name} (${d.project}) -- ${idle}${build}`;
3290
+ })];
3291
+ }
3292
+ function shutDownIdleDevices(devices, idleMs, recollect) {
3293
+ const candidates = idleShutdownCandidates(devices, idleMs);
3294
+ const shutDown = [];
3295
+ if (candidates.length === 0) {
3296
+ console.log(chalk.dim(`No owned device has been idle for ${formatLongDuration(idleMs)} or more.`));
3297
+ return {
3298
+ failures: 0,
3299
+ shutDown
3300
+ };
3301
+ }
3302
+ const fresh = idleShutdownCandidates(recollect(), idleMs);
3303
+ let failures = 0;
3304
+ for (const device of candidates) {
3305
+ const what = `${device.kind} ${device.name}`;
3306
+ const current = fresh.find((d) => d.kind === device.kind && d.id === device.id && d.project === device.project && d.slot === device.slot);
3307
+ if (!current) {
3308
+ console.log(chalk.dim(`Kept ${what}: it is no longer idle for ${formatLongDuration(idleMs)}.`));
3309
+ recordGcResult("idleDevice", "kept", device.name, {
3310
+ id: device.id,
3311
+ detail: `it is no longer idle for ${formatLongDuration(idleMs)}`
3312
+ });
3313
+ continue;
3314
+ }
3315
+ const outcome = device.kind === "ios" ? teardownOwnedIosSim(device.id, { label: device.name }) : teardownOwnedAvd(device.id, { owner: {
3316
+ projectPath: device.project,
3317
+ slot: device.slot
3318
+ } });
3319
+ if (outcome.status === "torn-down") {
3320
+ shutDown.push(device);
3321
+ console.log(chalk.green(`Shut down ${what}, idle ${formatLongDuration(current.idleForMs)}`));
3322
+ recordGcResult("idleDevice", "done", device.name, {
3323
+ id: device.id,
3324
+ detail: `idle ${formatLongDuration(current.idleForMs)}`
3325
+ });
3326
+ } else if (outcome.status === "missing") console.log(chalk.dim(`${what} is already gone; nothing to shut down.`));
3327
+ else if (outcome.status === "skipped") {
3328
+ console.log(chalk.yellow(`Skipped ${what}: ${outcome.reason}`));
3329
+ recordGcResult("idleDevice", "kept", device.name, {
3330
+ id: device.id,
3331
+ detail: outcome.reason
3332
+ });
3333
+ } else {
3334
+ failures++;
3335
+ console.log(chalk.red(`Failed to shut down ${what}: ${outcome.reason}`));
3336
+ recordGcResult("idleDevice", "failed", device.name, {
3337
+ id: device.id,
3338
+ detail: outcome.reason
3339
+ });
3340
+ }
3341
+ }
3342
+ return {
3343
+ failures,
3344
+ shutDown
3345
+ };
3346
+ }
3347
+ //#endregion
3348
+ //#region src/supervisor/stop-cause.ts
3349
+ function requestDevServerStop(root, processToken, requester) {
3350
+ if (!processToken) return;
3351
+ try {
3352
+ writeWorkspaceState(root, { [DEV_SERVER_STOP_REQUEST_KEY]: {
3353
+ processToken,
3354
+ by: requester.by,
3355
+ pid: process.pid,
3356
+ at: (/* @__PURE__ */ new Date()).toISOString(),
3357
+ ...requester.workspace ? { workspace: requester.workspace } : {}
3358
+ } });
3359
+ } catch {}
3360
+ }
3361
+ function withdrawDevServerStopRequest(root, processToken) {
3362
+ if (!processToken) return;
3363
+ try {
3364
+ clearWorkspaceStateKey(root, DEV_SERVER_STOP_REQUEST_KEY, (value) => {
3365
+ return readDevServerStopRequest({ [DEV_SERVER_STOP_REQUEST_KEY]: value })?.processToken === processToken;
3366
+ });
3367
+ } catch {}
3368
+ }
3369
+ function devServerStopRecord(trigger, request, at) {
3370
+ if (request) return {
3371
+ reason: "requested",
3372
+ at,
3373
+ by: request.by,
3374
+ byPid: request.pid,
3375
+ ...request.workspace ? { byWorkspace: request.workspace } : {}
3376
+ };
3377
+ return trigger.kind === "signal" ? {
3378
+ reason: "signal",
3379
+ at,
3380
+ signal: trigger.signal
3381
+ } : {
3382
+ reason: "server-exited",
3383
+ at,
3384
+ mode: trigger.mode,
3385
+ code: trigger.code,
3386
+ signal: trigger.signal
3387
+ };
3388
+ }
3389
+ function describeDevServerStop(record) {
3390
+ if (record.reason === "idle") return `idle for ${record.idleMinutes} minutes (metro.idleStopMinutes)`;
3391
+ if (record.reason === "requested") return `stop requested by ${record.by} (pid ${record.byPid}${record.byWorkspace ? ` in ${record.byWorkspace}` : ""})`;
3392
+ if (record.reason === "signal") return `received ${record.signal} with no Stim stop request recorded, so it likely came from outside Stim`;
3393
+ const detail = record.signal ? `signal ${record.signal}` : `exit code ${record.code ?? "unknown"}`;
3394
+ const expoSignal = record.mode === "expo-child" && record.code === 0 ? "; Expo CLI also exits 0 on SIGTERM, and no Stim stop request was recorded" : "";
3395
+ return `the ${record.mode} dev server exited unexpectedly (${detail})${expoSignal}`;
3396
+ }
3397
+ function devServerStopLevel(record) {
3398
+ if (record.reason === "server-exited") return "error";
3399
+ return record.reason === "signal" ? "warn" : "info";
3400
+ }
3401
+ /** The log line for a recorded supervisor whose process is proven gone, or null while it may still run. */
3402
+ function vanishedSupervisorMessage(record) {
3403
+ if (!record || typeof record.pid !== "number") return null;
3404
+ const identity = (0, process_identity_exports.inspectProcessIdentity)(record);
3405
+ if (identity !== "gone" && identity !== "different") return null;
3406
+ const started = typeof record.startedAt === "string" ? ` (started ${record.startedAt})` : "";
3407
+ return `supervisor pid ${record.pid}${started} ${VANISHED}`;
3408
+ }
3409
+ const VANISHED = "is gone and recorded no cause: usually SIGKILL, a crash or a machine restart";
3410
+ function logVanishedSupervisor(root, record) {
3411
+ const msg = vanishedSupervisorMessage(record);
3412
+ if (!msg) return;
3413
+ const writer = createNdjsonWriter(join(workspaceLogsDir$1(root), "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
3414
+ writer.write({
3415
+ src: "metro",
3416
+ level: "warn",
3417
+ event: "supervisor_vanished",
3418
+ msg
3419
+ });
3420
+ writer.close();
3421
+ }
3422
+ /** The recorded stop, else a vanished supervisor when status proved the recorded one gone. */
3423
+ function metroLastStop(state, supervisor) {
3424
+ const recorded = readDevServerStop(state);
3425
+ if (recorded) return recorded;
3426
+ if (supervisor?.status !== "stale" || typeof supervisor.pid !== "number") return null;
3427
+ const startedAt = typeof supervisor.startedAt === "string" ? supervisor.startedAt : null;
3428
+ return {
3429
+ reason: "vanished",
3430
+ pid: supervisor.pid,
3431
+ startedAt
3432
+ };
3433
+ }
3434
+ function describeMetroLastStop(stop) {
3435
+ return stop.reason === "vanished" ? `supervisor pid ${stop.pid} ${VANISHED}` : describeDevServerStop(stop);
3436
+ }
3437
+ //#endregion
2115
3438
  //#region src/supervisor/cache-reset.ts
2116
3439
  async function stopOwnedMetro(root, requester) {
2117
3440
  const project = getProject(root);
@@ -2163,7 +3486,6 @@ async function stopOwnedMetroForReset(root) {
2163
3486
  const MB = 1048576;
2164
3487
  const GB_IN_MB = 1024;
2165
3488
  const COMMITTED_MEMORY_SHARE = .6;
2166
- const STALE_CACHE_DAYS = 14;
2167
3489
  const DEVICE_LIST_TIMEOUT_MS = 1e4;
2168
3490
  const USAGE_TIMEOUT_MS = 1e4;
2169
3491
  const BUDGET_SETTING_REMEDY = "Fix the value with `stim settings set <key> <value>`, or unset the environment variable. Run `stim guide settings` for the budget keys.";
@@ -2207,7 +3529,7 @@ function machineNumber(key, config, env) {
2207
3529
  error: null
2208
3530
  };
2209
3531
  }
2210
- function resolveBudget({ config = loadConfig$1(), env = process.env, totalMemoryMb = totalmem$1() / MB } = {}) {
3532
+ function resolveBudget({ config = loadConfig$1(), env = process.env, totalMemoryMb = totalmem() / MB } = {}) {
2211
3533
  const minFree = machineNumber("budget.minFreeDiskGb", config, env);
2212
3534
  const hardFloor = machineNumber("budget.hardFloorDiskGb", config, env);
2213
3535
  const memory = machineNumber("budget.maxCommittedMemoryGb", config, env);
@@ -2280,6 +3602,13 @@ function listSims() {
2280
3602
  return null;
2281
3603
  }
2282
3604
  }
3605
+ function snapshotSims(snapshot) {
3606
+ try {
3607
+ return snapshot.read().filter((sim) => sim.available);
3608
+ } catch {
3609
+ return null;
3610
+ }
3611
+ }
2283
3612
  function runningSupervisorPid(path, project) {
2284
3613
  const target = resolveSupervisorTarget({
2285
3614
  state: readWorkspaceState$1(path)?.supervisor,
@@ -2288,11 +3617,11 @@ function runningSupervisorPid(path, project) {
2288
3617
  });
2289
3618
  return target.status === "ours" ? target.pid ?? null : null;
2290
3619
  }
2291
- function readMemoryUse() {
3620
+ function readMemoryUse(simSnapshot) {
2292
3621
  const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
2293
3622
  return estimateMemoryUse({
2294
3623
  config: loadConfig$1(),
2295
- sims: listSims(),
3624
+ sims: simSnapshot ? snapshotSims(simSnapshot) : listSims(),
2296
3625
  androidSerial: (avdName) => {
2297
3626
  try {
2298
3627
  return resolve(avdName).serial ?? null;
@@ -2475,14 +3804,17 @@ async function reclaimWorkspaceOutputs({ root, dryRun, now, diskRecovered }) {
2475
3804
  function cacheLabel(cache) {
2476
3805
  return `${cache.name} ${cache.dir}`;
2477
3806
  }
3807
+ function trimmableCaches() {
3808
+ return planCacheEmptying(discoverCaches(), false).filter((cache) => cache.prune !== "report-only" && cache.prune !== "atomic" && !cache.machineGlobal);
3809
+ }
2478
3810
  function reclaimStaleCacheEntries({ dryRun }) {
2479
- const caches = planCacheEmptying(discoverCaches(), false).filter((cache) => cache.prune !== "report-only" && cache.prune !== "atomic" && !cache.machineGlobal);
3811
+ const caches = trimmableCaches();
2480
3812
  if (dryRun) return {
2481
3813
  targets: caches.map(cacheLabel),
2482
3814
  failures: 0
2483
3815
  };
2484
3816
  return {
2485
- targets: trimCaches(caches, STALE_CACHE_DAYS).map(cacheLabel),
3817
+ targets: trimCaches(caches, 14).map(cacheLabel),
2486
3818
  failures: 0
2487
3819
  };
2488
3820
  }
@@ -2496,7 +3828,7 @@ const STEP_ACTIONS = {
2496
3828
  "idle-devices": "shut down idle owned devices",
2497
3829
  "idle-dev-servers": "stop idle dev servers",
2498
3830
  "workspace-outputs": "clear build outputs of idle workspaces",
2499
- "stale-cache-entries": `trim cache entries unused for ${STALE_CACHE_DAYS} days`
3831
+ "stale-cache-entries": `trim cache entries unused for 14 days`
2500
3832
  };
2501
3833
  async function runStep(step, context) {
2502
3834
  const log = console.log;
@@ -2520,7 +3852,7 @@ async function runStep(step, context) {
2520
3852
  }
2521
3853
  }
2522
3854
  function spaceUsers() {
2523
- const home = homedir$1();
3855
+ const home = homedir();
2524
3856
  const candidates = [
2525
3857
  ["Stim state", getConfigDir()],
2526
3858
  ["shared build cache", sharedBuildCache()],
@@ -2558,7 +3890,7 @@ function describeShortfall(budget, measure, short) {
2558
3890
  ...short.workspaces && measure.memory ? [`${measure.memory.liveWorkspaces} active workspaces, over the limit of ${budget.maxLiveWorkspaces}`] : []
2559
3891
  ];
2560
3892
  }
2561
- async function enforceBudget({ root, note, dryRun = false, budget: resolved }, overrides = {}) {
3893
+ async function enforceBudget({ root, note, dryRun = false, budget: resolved, simSnapshot }, overrides = {}) {
2562
3894
  const deps = {
2563
3895
  ...DEFAULT_DEPS,
2564
3896
  ...overrides
@@ -2579,7 +3911,7 @@ async function enforceBudget({ root, note, dryRun = false, budget: resolved }, o
2579
3911
  const paths = [root, getConfigDir()];
2580
3912
  const measureNow = () => ({
2581
3913
  volumes: budget.minFreeDiskMb > 0 || budget.hardFloorDiskMb > 0 ? deps.volumes(paths) : [],
2582
- memory: budget.maxCommittedMemoryMb > 0 || budget.maxLiveWorkspaces > 0 ? deps.memory() : null
3914
+ memory: budget.maxCommittedMemoryMb > 0 || budget.maxLiveWorkspaces > 0 ? deps.memory(simSnapshot) : null
2583
3915
  });
2584
3916
  let measure = measureNow();
2585
3917
  let short = budgetShortfalls(budget, measure);
@@ -2600,6 +3932,7 @@ async function enforceBudget({ root, note, dryRun = false, budget: resolved }, o
2600
3932
  }).disk.length === 0
2601
3933
  });
2602
3934
  if (!dryRun) {
3935
+ simSnapshot?.invalidate();
2603
3936
  measure = measureNow();
2604
3937
  short = budgetShortfalls(budget, measure);
2605
3938
  }
@@ -2734,4 +4067,4 @@ function budgetLine(report) {
2734
4067
  return `${report.volumes.length ? `${report.volumes.map((v) => `${v.freeGb} GB free on ${v.volume}`).join(", ")} (reclaims below ${Math.max(budget.minFreeDiskGb, budget.hardFloorDiskGb)} GB, ${budget.hardFloorDiskGb ? `refuses below ${budget.hardFloorDiskGb} GB` : "never refuses"})` : "disk budget off"}; ${report.memory ? `roughly ${report.memory.committedGb} GB of a ${budget.maxCommittedMemoryGb} GB memory budget committed` : "memory budget off"}`;
2735
4068
  }
2736
4069
  //#endregion
2737
- export { sizeCaches as $, includesWorkspaceOutputs as A, collectMemoryReport as B, findStaleProjectDevices as C, includesArchives as D, emptyCaches as E, selectsBeyondCaches as F, memorySweepIsScoped as G, memoryCacheKind as H, trimCaches as I, scopedMemoryReport as J, memoryWorkPending as K, parseArchiveSelector as L, planCacheEmptying as M, previewScopedEmptying as N, includesParkedDevices as O, selectCaches as P, discoverCaches as Q, GRADLE_DAEMONS_KIND as R, findStaleDeviceRecords as S, withAndroidAvdSizes as T, memoryLines as U, inspectWatchmanMemory as V, memoryScope as W, attributeMachineUsage as X, phase as Y, readFootprints as Z, describeParkedSims as _, machineNumber as a, eraseParkedDevices as b, resolveBudget as c, collectDeviceLeases as d, collectParkedAvds as f, deleteProjectDevices as g, deleteParkedSims as h, inspectBudget as i, isWorkspacesScope as j, includesRecordings as k, stopOwnedMetroForReset as l, deleteParkedAvds as m, budgetLine as n, peekBudget as o, collectParkedSims as p, reclaimMemory as q, enforceBudget as r, readVolumeSpace as s, budgetGate as t, DEVICE_LIST_TIMEOUT_MS$1 as u, describeUnverifiableDevices as v, unverifiedDeviceCommand as w, findOrphanedDevices as x, deviceSweepIsScoped as y, WATCHMAN_KIND as z };
4070
+ export { describeUnverifiableDevices as $, buildReport as A, phase as At, readStats$1 as B, idleDeviceLines as C, memoryCacheKind as Ct, ACTIVE_BUILD_KEY as D, memoryWorkPending as Dt, workspaceBuildInProgress as E, memorySweepIsScoped as Et, recordFinishedBuild as F, sizeCaches as Ft, DEVICE_LIST_TIMEOUT_MS$1 as G, recordCapacityWait as H, startBuildProgress as I, collectParkedSims as J, collectDeviceLeases as K, tapBuildLog as L, estimateBuild as M, readFootprints as Mt, parseActiveBuild as N, discoverCaches as Nt, NO_BUILD_PROGRESS as O, reclaimMemory as Ot, recordBuildPhase as P, pruneCache as Pt, describeParkedSims as Q, createRunRecorder as R, collectOwnedDeviceActivity as S, inspectWatchmanMemory as St, shutDownIdleDevices as T, memoryScope as Tt, recordRunStats as U, recordCapacityRefusal as V, statsProjectKey$1 as W, deleteParkedSims as X, deleteParkedAvds as Y, deleteProjectDevices as Z, metroLastStop as _, trimCaches as _t, inspectBudget as a, unverifiedDeviceCommand as at, withdrawDevServerStopRequest as b, WATCHMAN_KIND as bt, readVolumeSpace as c, includesArchives as ct, stopOwnedMetroForReset as d, includesWorkspaceOutputs as dt, deviceSweepIsScoped as et, describeDevServerStop as f, isWorkspacesScope as ft, logVanishedSupervisor as g, selectsBeyondCaches as gt, devServerStopRecord as h, selectCaches as ht, enforceBudget as i, findStaleProjectDevices as it, buildStatusLine as j, attributeMachineUsage as jt, activeBuildState as k, scopedMemoryReport as kt, resolveBudget as l, includesParkedDevices as lt, devServerStopLevel as m, previewScopedEmptying as mt, budgetLine as n, findOrphanedDevices as nt, machineNumber as o, withAndroidAvdSizes as ot, describeMetroLastStop as p, planCacheEmptying as pt, collectParkedAvds as q, cacheLabel as r, findStaleDeviceRecords as rt, peekBudget as s, emptyCaches as st, budgetGate as t, eraseParkedDevices as tt, trimmableCaches as u, includesRecordings as ut, requestDevServerStop as v, parseArchiveSelector as vt, parseIdleDuration as w, memoryLines as wt, collectIdleDevices as x, collectMemoryReport as xt, vanishedSupervisorMessage as y, GRADLE_DAEMONS_KIND as yt, readRunEstimates as z };