stim 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +60 -7
  2. package/dist/{acquire-artifact-CD4lbiWE.mjs → acquire-artifact-Co2k4f7O.mjs} +21 -3
  3. package/dist/{act-DHAw2A2S.mjs → act-DsuqEkiM.mjs} +298 -164
  4. package/dist/{activity-BzVfHSrY.mjs → activity-CMLmzp7o.mjs} +33 -12
  5. package/dist/{agent-device-usage-output-zh1vhbLp.mjs → agent-device-usage-output-DUFaTMdd.mjs} +7 -7
  6. package/dist/{android-BLgbNqox.mjs → android-ByRMUoiJ.mjs} +66 -52
  7. package/dist/{android-DUYkNF4u.mjs → android-C7sVmyI9.mjs} +160 -59
  8. package/dist/{android-CV_GCELZ.mjs → android-DGkNqa_c.mjs} +5 -5
  9. package/dist/{android-BEJ8Jpl7.mjs → android-DR5lZ2Az.mjs} +2 -2
  10. package/dist/android-cas-compiler.mjs +1 -1
  11. package/dist/{android-cas-Ct5b1xCK.mjs → android-cas-ngferVq2.mjs} +3 -3
  12. package/dist/{client-B7QVOlCr.d.mts → android-project-DVWyCbWU.d.mts} +145 -7
  13. package/dist/api.d.mts +132 -118
  14. package/dist/api.mjs +239 -42
  15. package/dist/{artifact-B8T3S5gi.mjs → artifact-8EY8SAPw.mjs} +40 -35
  16. package/dist/{artifact-DAuZ-FNU.mjs → artifact-DJPy518Y.mjs} +69 -40
  17. package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
  18. package/dist/{browser-web-QQzVjz3O.mjs → browser-web-Bcv99PBM.mjs} +187 -59
  19. package/dist/{budget-Bs6SxxzO.mjs → budget-Cvwn54qV.mjs} +830 -699
  20. package/dist/{build-CoPzQRNw.mjs → build-CabC3G23.mjs} +34 -27
  21. package/dist/{build-cache-DmyR9Zzc.mjs → build-cache-Dv7RN200.mjs} +4 -4
  22. package/dist/{build-plan-CaFskB7_.mjs → build-plan-DUC8Ka9y.mjs} +74 -14
  23. package/dist/{cache-manifest-DkkqguoK.mjs → cache-manifest-DSeQjt-Q.mjs} +1 -1
  24. package/dist/cache-manifest.mjs +1 -1
  25. package/dist/{ccache-BJRZ9pG3.mjs → ccache-Btwc36-I.mjs} +6 -6
  26. package/dist/{cdp-CWmIUMbw.mjs → cdp-3fwICjzi.mjs} +1 -1
  27. package/dist/{chrome-B6tfCta1.mjs → chrome-Bbw689-6.mjs} +1 -1
  28. package/dist/{cli-0DYf8QhQ.mjs → cli-CHZa9Lvk.mjs} +20 -20
  29. package/dist/cli.mjs +1 -1
  30. package/dist/{client-UXD70ZbM.mjs → client-OyRoEuSr.mjs} +218 -47
  31. package/dist/collector-run.d.mts +1 -1
  32. package/dist/collector-run.mjs +6 -6
  33. package/dist/{command-output-B1UrjZHL.mjs → command-output-gwpm28fu.mjs} +1 -1
  34. package/dist/{config-CYcBF478.mjs → config-DlrsduwG.mjs} +17 -11
  35. package/dist/{created-devices-CqeBlrEn.mjs → created-devices-x9rN6bhs.mjs} +13 -3
  36. package/dist/{dependency-state-BbKQW83h.mjs → dependency-state-1I9KZT1Y.mjs} +2 -2
  37. package/dist/{detached-entry-DFRyG1_o.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
  38. package/dist/{dev-client-UOeESKm6.mjs → dev-client-BSDR5h3F.mjs} +2 -2
  39. package/dist/{device-ExJq8Ei7.mjs → device-B-L3Fbxy.mjs} +71 -14
  40. package/dist/{device-DCxH7_By.mjs → device-DklWZLqb.mjs} +16 -16
  41. package/dist/{device-capacity-CMlqEcvw.mjs → device-capacity-DK5_EwRS.mjs} +9 -10
  42. package/dist/device-host-worker.mjs +25 -32
  43. package/dist/{device-ios-DRUeKaFV.mjs → device-ios-DoB6KFCO.mjs} +39 -16
  44. package/dist/{device-lease-run-C8raGFoP.mjs → device-lease-run-xJPQ_QQG.mjs} +5 -5
  45. package/dist/{device-pool-DMRpVX9a.mjs → device-pool-BMkdsefq.mjs} +3 -3
  46. package/dist/{doctor-DTvaDOda.mjs → doctor-Bo7BXLux.mjs} +24 -37
  47. package/dist/{doctor-Dhqebm0q.mjs → doctor-D5_EzwfA.mjs} +19 -16
  48. package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
  49. package/dist/doctor-fingerprint.mjs +1 -1
  50. package/dist/{doctor-BLHCYxzi.mjs → doctor-thjWAV0z.mjs} +1 -1
  51. package/dist/{doctor-watchman-Cv1F10Kj.mjs → doctor-watchman-N2wDotwQ.mjs} +5 -5
  52. package/dist/{eas-build-BomfRnFT.mjs → eas-build-CwknaQYj.mjs} +4 -4
  53. package/dist/{eas-fallback-DJwZpy0c.mjs → eas-fallback-CSgAulr5.mjs} +27 -18
  54. package/dist/{eas-session-ledger-op6A54yi.mjs → eas-session-ledger-DlY_serQ.mjs} +8 -7
  55. package/dist/{error-diagnostics-Bf0rZvG9.mjs → error-diagnostics-DBWO2rxE.mjs} +10 -10
  56. package/dist/{exec-_UbtCQcG.mjs → exec-DEoAhcze.mjs} +155 -47
  57. package/dist/{exec-H20xSg2T.d.mts → exec-DnYc4HGH.d.mts} +17 -4
  58. package/dist/{gc-_-dCXdyL.mjs → gc-CXxN-4SE.mjs} +587 -313
  59. package/dist/gc-DnNDQyaP.mjs +3 -0
  60. package/dist/{guide-Yqwt2bd6.mjs → guide-Br0LEfKy.mjs} +239 -43
  61. package/dist/{hosted-android-Bw-honsd.mjs → hosted-android-B-9f-jkd.mjs} +6 -6
  62. package/dist/{hosted-client-DB_gBPfY.mjs → hosted-client-DZAPrcro.mjs} +4 -4
  63. package/dist/{hosted-ios-CUvOf4Vr.mjs → hosted-ios-CsCS21hn.mjs} +1 -1
  64. package/dist/{hosted-logs-DL_P5AdN.mjs → hosted-logs-FIRx9X2f.mjs} +5 -5
  65. package/dist/{hosted-macos-QI141yKk.mjs → hosted-macos-_awYSpfv.mjs} +21 -12
  66. package/dist/{hosted-native-Ksyjgzq-.mjs → hosted-native-BdzE668-.mjs} +27 -14
  67. package/dist/{idle-BVeRGroT.d.mts → idle-C4cZ757K.d.mts} +3 -3
  68. package/dist/{idle-shutdown-DaKmZi0z.mjs → idle-shutdown-DDg3SdvY.mjs} +7 -7
  69. package/dist/ios-CDvlmUs7.d.mts +24 -0
  70. package/dist/{ios-CQ68hG9s.mjs → ios-Ds1clbIt.mjs} +8 -8
  71. package/dist/{ios-device-CwFMehUS.mjs → ios-device--h_-8ENa.mjs} +3 -3
  72. package/dist/{ios-device-CXGP1bsD.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
  73. package/dist/{ios-CpByZy12.mjs → ios-hcBpnEGk.mjs} +81 -34
  74. package/dist/{ios-ubFsBzwq.mjs → ios-pm4nL6By.mjs} +59 -50
  75. package/dist/{ios-project-WuwwBdvW.mjs → ios-project-CZhKODF3.mjs} +5 -5
  76. package/dist/{ios-signing-DTTIChGs.mjs → ios-signing-BtAffm0A.mjs} +2 -2
  77. package/dist/{ios-state-DvFX-K_l.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
  78. package/dist/{ios-qNJt4dFm.mjs → ios-xtlRHaeB.mjs} +1 -1
  79. package/dist/{js-swap-Cc1dttps.mjs → js-swap-Bwhh4S7V.mjs} +7 -29
  80. package/dist/{launch-Zq2mOSDy.mjs → launch-BjxemNpK.mjs} +40 -39
  81. package/dist/{launch-CD1yVc7U.mjs → launch-CCzXlc8r.mjs} +16 -16
  82. package/dist/{logs-BS00Anxf.mjs → logs-BfwwadsZ.mjs} +151 -24
  83. package/dist/{logs-CMm05HxN.mjs → logs-jTS_lHSo.mjs} +10 -17
  84. package/dist/{macos-B65--pPd.mjs → macos-DVlSSyUg.mjs} +1 -1
  85. package/dist/{macos-C-0qJ6zq.mjs → macos-NfV2D7dO.mjs} +143 -46
  86. package/dist/macos-run.mjs +1 -1
  87. package/dist/maintenance-run.mjs +8 -8
  88. package/dist/{metro-DEXpIhHC.mjs → metro-DiXtA3Ty.mjs} +59 -37
  89. package/dist/{metro-gateway-BMJNlj3E.mjs → metro-gateway-CKZqKqx7.mjs} +120 -22
  90. package/dist/{named-ports-BWTzt6mu.mjs → named-ports-DkEzOfzO.mjs} +40 -33
  91. package/dist/{native-android-JACyjTZs.mjs → native-android-CqgnOgsT.mjs} +43 -242
  92. package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
  93. package/dist/{native-gradle-inputs-Bep9JcSF.mjs → native-gradle-inputs-Dnh84Zbd.mjs} +3 -129
  94. package/dist/{native-run-DY_RLx3C.mjs → native-run-NwUuxbkg.mjs} +4 -5
  95. package/dist/{native-runtime-Dg1Q7tfF.mjs → native-runtime-B7KIafpM.mjs} +8 -7
  96. package/dist/native-source-Y0yLhFyQ.mjs +133 -0
  97. package/dist/{native-xcode-inputs-CB2iQeWq.mjs → native-xcode-inputs-D_VOfFL7.mjs} +2 -3
  98. package/dist/{native-xcode-ios-CXX39F7o.mjs → native-xcode-ios-BYDOHWLN.mjs} +27 -32
  99. package/dist/offload-worker.d.mts +65 -2
  100. package/dist/offload-worker.mjs +305 -73
  101. package/dist/operation-exec-BW0em61G.mjs +171 -0
  102. package/dist/{ownership-DEmM5vhh.mjs → ownership-C5fo5Edb.mjs} +3 -3
  103. package/dist/{page-CPaHeYqj.mjs → page-DBL2PiUU.mjs} +8 -4
  104. package/dist/{placement-log-BqGbTa61.mjs → placement-log-BnGgJRRZ.mjs} +1 -1
  105. package/dist/{plan-placement-Bwj-IjY1.mjs → plan-placement-DIsMtN-d.mjs} +12 -8
  106. package/dist/{ports-D-MmCTdv.mjs → ports-Cy1RkmuQ.mjs} +3 -3
  107. package/dist/{prebuild-uD_ipCxF.mjs → prebuild-D4JoEAEs.mjs} +49 -14
  108. package/dist/{project-BZNjmW_8.mjs → project-wM_XFTvE.mjs} +16 -16
  109. package/dist/{pull-request-Lfetn8Kr.mjs → pull-request-W1IuLXDt.mjs} +102 -20
  110. package/dist/{pull-request-zjCSAryH.d.mts → pull-request-eODyIqZF.d.mts} +6 -2
  111. package/dist/pull-requests.d.mts +2 -2
  112. package/dist/pull-requests.mjs +2 -2
  113. package/dist/{react-native-android-DuzH0cn3.mjs → react-native-android-6OZ7MSM7.mjs} +71 -48
  114. package/dist/{react-native-build-rhk4smwQ.mjs → react-native-build-Dvd8hC21.mjs} +8 -8
  115. package/dist/{react-native-doctor-CQpuIMso.mjs → react-native-doctor-DsoSF1Y9.mjs} +7 -7
  116. package/dist/{react-native-ios-Bhq1rJeV.mjs → react-native-ios-4u1Rn-GR.mjs} +40 -26
  117. package/dist/{recordings-DYteQSu4.mjs → recordings-CQmfzAh7.mjs} +1 -1
  118. package/dist/registration-BcRgF6Ox.mjs +51 -0
  119. package/dist/{reload-CmTRFJaX.mjs → reload-BzkYabB-.mjs} +16 -15
  120. package/dist/{reload-DzjSl5P_.mjs → reload-D7AVlb8N.mjs} +1 -1
  121. package/dist/{remote-ByYkXdGD.mjs → remote-DjGDmlTZ.mjs} +18 -15
  122. package/dist/{result-DNiS-tTP.mjs → result-D2Ykz_iD.mjs} +24 -23
  123. package/dist/{run-D23HmJMs.mjs → run-DidHghD1.mjs} +3 -2
  124. package/dist/{selection-CSl9i5qU.mjs → selection-DSMbWEX2.mjs} +6 -5
  125. package/dist/{server-bare-CxTrvDg8.mjs → server-bare-CafzuyFB.mjs} +2 -2
  126. package/dist/{server-command-CtzloH3v.mjs → server-command-C6QjeupS.mjs} +5 -5
  127. package/dist/{server-expo-DT_F_uVI.mjs → server-expo-CrjB29pq.mjs} +7 -5
  128. package/dist/server-expo-D58c9L0M.mjs +2 -0
  129. package/dist/{settings-CsJDEXgK.mjs → settings-C7O8A6ZI.mjs} +223 -243
  130. package/dist/{settings-T1gtc3bf.mjs → settings-DpR-1Wnn.mjs} +1 -1
  131. package/dist/{settings-write-HyVZ8eQ8.mjs → settings-write-CzD60rOD.mjs} +7 -6
  132. package/dist/settings.schema.json +13 -0
  133. package/dist/{simslim-Cgk17SXV.mjs → simslim-BNckWpXi.mjs} +2 -2
  134. package/dist/{slot-launch-DF8VfT64.mjs → slot-launch-CbfmNgM6.mjs} +6 -6
  135. package/dist/{stage-BIS0ydsV.mjs → stage-Bps5oius.mjs} +21 -4
  136. package/dist/{start-RChynRDp.mjs → start-Br-oxqMD.mjs} +1 -1
  137. package/dist/{start-7lpH7hmN.mjs → start-EojN4WFz.mjs} +622 -393
  138. package/dist/{state-C4ZtUisW.mjs → state--smjFSTL.mjs} +22 -7
  139. package/dist/{state-XMziexv2.mjs → state-08I3hw3_.mjs} +2 -2
  140. package/dist/{stats-53T7OTb9.mjs → stats-D3GerlFW.mjs} +5 -5
  141. package/dist/{stats-report-BFfMpWWF.mjs → stats-report-BzaPrRm6.mjs} +1 -1
  142. package/dist/{status-DqEUSSxs.mjs → status-BRROykC8.mjs} +2 -2
  143. package/dist/{status-CSi6tlRq.mjs → status-EvrK72L2.mjs} +1 -1
  144. package/dist/{status-BL7jVyAB.mjs → status-WBDajew2.mjs} +43 -29
  145. package/dist/{status-watch-GDCfqpTE.mjs → status-watch-Bg_u-pwR.mjs} +48 -16
  146. package/dist/status-worker.mjs +1 -1
  147. package/dist/{stim-desktop-C12we7lz.mjs → stim-desktop-D5OGpYZM.mjs} +2 -2
  148. package/dist/{stop-Bk_1qiV6.mjs → stop-DTZ9uTw3.mjs} +2 -2
  149. package/dist/{stop-D7h6jAXQ.mjs → stop-Dky10AEJ.mjs} +31 -22
  150. package/dist/{stop-CPzlM1L-.mjs → stop-Mv6W9FAk.mjs} +15 -16
  151. package/dist/supervisor-run.d.mts +3 -3
  152. package/dist/supervisor-run.mjs +28 -36
  153. package/dist/{support-Dlu37g6H.mjs → support-CNioewsd.mjs} +10 -10
  154. package/dist/{support-67vraa1Q.mjs → support-yUiOjnVY.mjs} +8 -8
  155. package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
  156. package/dist/swiftpm-macos-BIak-Rxv.mjs +532 -0
  157. package/dist/toolchain-BY8X8HXx.mjs +2 -0
  158. package/dist/{toolchain-Hp9sCpK4.mjs → toolchain-DpJMHq0n.mjs} +9 -6
  159. package/dist/{trigger-BAahxUPq.mjs → trigger-Cbyc41d_.mjs} +3 -3
  160. package/dist/trigger-yb_nFzPF.mjs +2 -0
  161. package/dist/{warm-progress-BHX5r0Ei.mjs → warm-progress-CA3TgT3-.mjs} +29 -16
  162. package/dist/web-CZ07gd77.mjs +2 -0
  163. package/dist/{web-CJmIj6AI.mjs → web-DKx6yoFA.mjs} +11 -10
  164. package/dist/web-run.mjs +11 -9
  165. package/dist/windows-report.mjs +1 -1
  166. package/dist/{workspace-state-Cjuigeeu.mjs → workspace-state-U08dEzhG.mjs} +3 -3
  167. package/dist/{workspaces-BccMFmGQ.mjs → workspaces-CpANmBlq.mjs} +594 -266
  168. package/dist/{worktree-DQ6Zi2Mv.mjs → worktree-CHecZ4Oq.mjs} +850 -551
  169. package/dist/worktree-ZqZVjD9K.mjs +2 -0
  170. package/dist/{xcode-Zlx3qjEs.mjs → xcode-BXn9-xYx.mjs} +5 -5
  171. package/package.json +7 -7
  172. package/shim/android-audio/Main.java +24 -0
  173. package/shim/android-audio/README.md +17 -0
  174. package/shim/android-audio.jar +0 -0
  175. package/dist/gc-C-WwL0yi.mjs +0 -3
  176. package/dist/git-C3iTsJaZ.mjs +0 -73
  177. package/dist/server-expo-C-90EhcG.mjs +0 -2
  178. package/dist/settings-DkdmlelE.d.mts +0 -15
  179. package/dist/swiftpm-macos-p8WZbxKU.mjs +0 -130
  180. package/dist/toolchain-DhKwp9iI.mjs +0 -2
  181. package/dist/trigger-Bf3uDcpv.mjs +0 -2
  182. package/dist/web-DknQETPs.mjs +0 -2
  183. package/dist/workspace-process-lock-1_1OoVW5.mjs +0 -57
  184. package/dist/worktree-CK2MpJW5.mjs +0 -2
@@ -1,22 +1,23 @@
1
- import { _ as debugLog, m as reportSignal, t as getExecutor, u as operationState } from "./exec-_UbtCQcG.mjs";
2
- import { $ as openAuthenticated, _ as loadConfig$1, at as sayHello, it as resolveEndpoint } from "./config-CYcBF478.mjs";
3
- import { en as throwIfCancelled } from "./settings-CsJDEXgK.mjs";
4
- import { n as gitAsync, t as git } from "./git-C3iTsJaZ.mjs";
1
+ import { _ as reportSignal, b as debugLog, m as operationState, t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { Q as openAuthenticated, _ as loadConfig$1, it as sayHello, rt as resolveEndpoint } from "./config-DlrsduwG.mjs";
3
+ import { f as throwIfCancelled, o as git, s as gitAsync } from "./operation-exec-BW0em61G.mjs";
5
4
  import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
6
- import { X as emptyCaches, br as discoverCaches, nt as planCacheEmptying } from "./budget-Bs6SxxzO.mjs";
5
+ import { X as emptyCaches, br as discoverCaches, nt as planCacheEmptying } from "./budget-Cvwn54qV.mjs";
7
6
  import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
8
- import { d as runCancellationSignal } from "./native-run-DY_RLx3C.mjs";
9
- import { n as CCACHE_UNAVAILABLE, t as CCACHE_NOT_RUN } from "./ccache-BJRZ9pG3.mjs";
10
- import { n as COMPILATION_CACHE_UNAVAILABLE, t as COMPILATION_CACHE_NOT_RUN } from "./xcode-Zlx3qjEs.mjs";
7
+ import { d as runCancellationSignal } from "./native-run-NwUuxbkg.mjs";
8
+ import { n as CCACHE_UNAVAILABLE, t as CCACHE_NOT_RUN } from "./ccache-Btwc36-I.mjs";
9
+ import { n as COMPILATION_CACHE_UNAVAILABLE, t as COMPILATION_CACHE_NOT_RUN } from "./xcode-BXn9-xYx.mjs";
11
10
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
12
- import { h as readRubyVersion, u as toolchainMismatches } from "./toolchain-Hp9sCpK4.mjs";
13
- import { l as pairedMachines, r as namedBuildMachine, t as OffloadRefusal } from "./selection-CSl9i5qU.mjs";
11
+ import { a as iosToolchainAsync, d as toolchainMismatches, f as workerToolchain, g as readRubyVersion } from "./toolchain-DpJMHq0n.mjs";
12
+ import { l as pairedMachines, r as namedBuildMachine, t as OffloadRefusal } from "./selection-DSMbWEX2.mjs";
14
13
  import { r as manifestDigest } from "./native-inputs-TRTTTRxt.mjs";
15
- import { a as nativeGradleTransfer, c as checkNativeTransferMembership, d as sourceManifest, l as gitVisiblePaths, u as nativeTransferManifest } from "./native-gradle-inputs-Bep9JcSF.mjs";
14
+ import { a as sourceManifest, i as nativeTransferManifest, n as gitVisiblePaths, t as checkNativeTransferMembership } from "./native-source-Y0yLhFyQ.mjs";
15
+ import { a as nativeGradleTransfer } from "./native-gradle-inputs-Dnh84Zbd.mjs";
16
16
  import { createHash, webcrypto } from "node:crypto";
17
17
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
18
+ import { isDeepStrictEqual } from "node:util";
18
19
  import { basename, dirname, isAbsolute, join, relative, sep } from "node:path";
19
- import { LOG_ROTATE_BYTES, ambientContext, rotatedLogPath, withDirLock } from "@stim-cli/core";
20
+ import { LOG_ROTATE_BYTES, ambientContext, reactNativeArtifactIdentity, reactNativeArtifactQuery, rotatedLogPath, swiftpmArtifactQuery, withDirLock } from "@stim-cli/core";
20
21
  import { MAINTENANCE_LOG_NAME, OFFLOAD_MODES, automaticMachineEnabled, isJsonObject, maintenanceDir, maintenanceNdjsonFile, requireAutomaticMachine, runId, saturation, workspaceLogsDir } from "@stim-cli/core/state";
21
22
  import { WebSocket } from "ws";
22
23
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
@@ -66,13 +67,14 @@ function maintenanceLogger(settings, pass, trigger) {
66
67
  //#endregion
67
68
  //#region src/cache/compilation-cache-corruption.ts
68
69
  const COMPILATION_CACHE_CORRUPT = "STIM_COMPILATION_CACHE_CORRUPT";
69
- function emptyCompilationCache(dir) {
70
+ async function emptyCompilationCache(dir) {
70
71
  const results = [];
71
72
  const cache = discoverCaches().find((candidate) => canonicalPath(candidate.dir) === canonicalPath(dir));
72
73
  if (cache?.source !== "registered" || cache.prune !== "atomic") return `${dir} is not a registered cache Stim empties whole`;
73
74
  const [planned] = planCacheEmptying([cache], true);
74
- emptyCaches(planned ? [planned] : [], {
75
+ await emptyCaches(planned ? [planned] : [], {
75
76
  log: () => {},
77
+ error: () => {},
76
78
  record: (kind, status, label, { id = null, bytes = null, detail = null } = {}) => {
77
79
  results.push({
78
80
  kind,
@@ -106,11 +108,11 @@ function recordInMaintenanceLog(workspace, msg, fields, cleared) {
106
108
  * Empties the shared compilation cache a failed build reported corrupt, through the path `gc --delete --cache` uses,
107
109
  * unless another build may be using it. It never retries the build; the result is the refusal to print.
108
110
  */
109
- function clearCorruptCompilationCache(corruption, workspace) {
111
+ async function clearCorruptCompilationCache(corruption, workspace) {
110
112
  const { dir, line } = corruption;
111
113
  let blocked;
112
114
  try {
113
- blocked = emptyCompilationCache(dir);
115
+ blocked = await emptyCompilationCache(dir);
114
116
  } catch (error) {
115
117
  blocked = error instanceof Error ? error.message : String(error);
116
118
  }
@@ -156,6 +158,60 @@ function reportRemoteFailure(context, event, fields) {
156
158
  } catch {}
157
159
  }
158
160
  //#endregion
161
+ //#region src/offload/react-native-artifact.ts
162
+ function reactNativeBuildQuery(build, fingerprint, project, toolchain) {
163
+ if (build.native) return null;
164
+ return reactNativeArtifactQuery({
165
+ project,
166
+ fingerprint,
167
+ toolchain,
168
+ isExpo: build.isExpo === true,
169
+ platform: build.platform,
170
+ ...build.platform === "ios" ? { ios: {
171
+ runtime: build.runtime,
172
+ configuration: build.configuration ?? "Debug",
173
+ scheme: build.scheme ?? null,
174
+ projectPath: build.iosProjectPath ?? "ios",
175
+ optimizations: build.optimizations
176
+ } } : { android: build.android }
177
+ });
178
+ }
179
+ async function reactNativeArtifactToolchain(platform, root) {
180
+ if (platform === "ios") {
181
+ const tools = await iosToolchainAsync(root);
182
+ return tools.stimBuild && tools.xcode && tools.simulatorSdk && tools.cocoapods ? {
183
+ ...tools,
184
+ os: process.platform
185
+ } : null;
186
+ }
187
+ const { stimBuild, os, arch, jdk, androidSdk } = workerToolchain(null, "gradle");
188
+ return stimBuild && jdk && androidSdk ? {
189
+ stimBuild,
190
+ os,
191
+ arch,
192
+ jdk,
193
+ androidSdk
194
+ } : null;
195
+ }
196
+ function reactNativeArtifactReceipt(query, toolchain) {
197
+ if (!toolchain || !isDeepStrictEqual(reactNativeArtifactQuery({
198
+ ...query,
199
+ toolchain
200
+ })?.toolchain, query.toolchain)) return null;
201
+ const receipt = {
202
+ query,
203
+ toolchain
204
+ };
205
+ const identity = reactNativeArtifactIdentity(receipt);
206
+ return {
207
+ identity: {
208
+ hash: identity.fingerprint,
209
+ key: identity.cacheKey
210
+ },
211
+ receipt
212
+ };
213
+ }
214
+ //#endregion
159
215
  //#region src/offload/client.ts
160
216
  const CONNECT_TIMEOUT_MS = 1e4;
161
217
  const OFFER_TIMEOUT_MS = 2e4;
@@ -270,7 +326,14 @@ function offloadPlacement({ mode, machines, here, unsupported, localEnabled = tr
270
326
  }
271
327
  function matchingArtifact(offer, identity) {
272
328
  const cached = offer.artifact;
273
- return identity && cached && cached.cacheKey === identity.cacheKey && cached.fingerprint === identity.fingerprint && typeof cached.name === "string" && basename(cached.name) === cached.name && cached.name.endsWith(".app") && Number.isSafeInteger(cached.size) && cached.size > 0 && typeof cached.sha256 === "string" && /^[a-f0-9]{64}$/.test(cached.sha256) ? cached : null;
329
+ if (!identity || !cached || typeof cached.name !== "string" || basename(cached.name) !== cached.name || !Number.isSafeInteger(cached.size) || cached.size <= 0 || typeof cached.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(cached.sha256)) return null;
330
+ if (identity === "react-native-ios" || identity === "react-native-android") {
331
+ const platform = identity === "react-native-ios" ? "ios" : "android";
332
+ return ARTIFACT_NAME[platform].test(cached.name) && /^[a-f0-9]{64}$/.test(cached.fingerprint) && cached.cacheKey === `react-native-${platform}-${cached.fingerprint}` && (platform === "ios" || ANDROID_PACKAGE.test(String(cached.androidPackage ?? ""))) ? cached : null;
333
+ }
334
+ if (identity === "swiftpm") return cached.name.endsWith(".app") && typeof cached.fingerprint === "string" && /^[a-f0-9]{64}$/.test(cached.fingerprint) && cached.cacheKey === `swiftpm-peer-${cached.fingerprint}` ? cached : null;
335
+ if (identity === "native-gradle") return cached.name.endsWith(".apk") && typeof cached.fingerprint === "string" && /^[a-f0-9]{64}$/.test(cached.fingerprint) && typeof cached.cacheKey === "string" && cached.cacheKey.length > 0 && cached.cacheKey.length <= 1024 && typeof cached.androidPackage === "string" && ANDROID_PACKAGE.test(cached.androidPackage) ? cached : null;
336
+ return cached.name.endsWith(".app") && cached.cacheKey === identity.cacheKey && cached.fingerprint === identity.fingerprint ? cached : null;
274
337
  }
275
338
  const gb = (bytes) => (bytes / 1024 ** 3).toFixed(1);
276
339
  /** Every reason a machine's offer cannot take this build, in either mode; empty when it can. */
@@ -302,7 +365,7 @@ function offerProblems(offer, target) {
302
365
  * every local build slot is busy any machine that accepts will do, otherwise its load per core must be lower than
303
366
  * this machine's. A named selection considers only that machine and skips this local-capacity gating.
304
367
  * A machine that reports no load (a stim-server older than capacity) takes an `auto` build only while
305
- * every local slot is busy. The rest rank warmest first, then least loaded.
368
+ * every local slot is busy. Matching dependency installations rank first, then load.
306
369
  */
307
370
  function pickOffer({ mode, here, offers, target, localEnabled = true, selected = "auto", artifact, cacheOnly = false }) {
308
371
  const slotsFull = here.maxBuilds > 0 && here.builds >= here.maxBuilds;
@@ -321,7 +384,7 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
321
384
  offers.forEach(({ machine, offer, failure }, index) => {
322
385
  if (namedBuildMachine(selected) && machine !== selected) return;
323
386
  if (!offer) return skip(machine, "unreachable", failure ?? "no offer");
324
- if (matchingArtifact(offer, artifact)) {
387
+ if (matchingArtifact(offer, artifact) && (artifact !== "swiftpm" || toolchainMismatches(target, offer.toolchain).length === 0)) {
325
388
  ranked.push({
326
389
  index,
327
390
  score: Number.POSITIVE_INFINITY,
@@ -342,7 +405,7 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
342
405
  if (typeof load !== "number") return skip(machine, "load", "capacity unknown (older stim-server) while this machine has a free slot");
343
406
  if (load >= here.loadPerCore) return skip(machine, "load", `no less loaded (load ${load}/core there, ${here.loadPerCore}/core here)`);
344
407
  }
345
- const score = Number(offer.warm.checkout) + Number(offer.warm.dependencies) + Number(offer.warm.build);
408
+ const score = Number(offer.warm.dependencies);
346
409
  ranked.push({
347
410
  index,
348
411
  score,
@@ -382,6 +445,7 @@ function closeOnExit(socket, context) {
382
445
  var BuildConnection = class BuildConnection {
383
446
  nextId = 2;
384
447
  pending = /* @__PURE__ */ new Map();
448
+ writeWaiters = /* @__PURE__ */ new Set();
385
449
  progress = null;
386
450
  binary = null;
387
451
  closed = null;
@@ -425,6 +489,7 @@ var BuildConnection = class BuildConnection {
425
489
  socket.on("close", (code, reason) => {
426
490
  clearInterval(this.keepalive);
427
491
  this.closed = `the connection closed (${code}${reason.length ? ` ${reason.toString()}` : ""})`;
492
+ for (const wake of this.writeWaiters) wake();
428
493
  for (const resolve of this.pending.values()) resolve({ error: {
429
494
  code: "closed",
430
495
  message: this.closed
@@ -553,8 +618,21 @@ var BuildConnection = class BuildConnection {
553
618
  }
554
619
  async sendBinary(frame) {
555
620
  if (this.closed) return;
556
- this.socket.send(frame, { binary: true });
557
- while (this.socket.bufferedAmount > MAX_BUFFERED && !this.closed) await new Promise((resolve) => setTimeout(resolve, 5));
621
+ let completed = false;
622
+ let resume;
623
+ this.socket.send(frame, { binary: true }, () => {
624
+ completed = true;
625
+ resume?.();
626
+ });
627
+ if (completed || this.closed || this.socket.bufferedAmount <= MAX_BUFFERED) return;
628
+ await new Promise((resolve) => {
629
+ const wake = () => {
630
+ this.writeWaiters.delete(wake);
631
+ resolve();
632
+ };
633
+ resume = wake;
634
+ this.writeWaiters.add(wake);
635
+ });
558
636
  }
559
637
  onProgress(listener) {
560
638
  this.progress = listener;
@@ -591,6 +669,7 @@ var BuildConnection = class BuildConnection {
591
669
  forget() {
592
670
  this.ended = true;
593
671
  this.closed ??= "the connection was closed by this client";
672
+ for (const wake of this.writeWaiters) wake();
594
673
  for (const resolve of this.pending.values()) resolve({ error: {
595
674
  code: "closed",
596
675
  message: this.closed
@@ -630,6 +709,13 @@ function repositoryIdentity(projectRoot, repoRoot, common) {
630
709
  lockfile: lock ? createHash("sha256").update(readFileSync(join(repoRoot, lock))).digest("hex") : null
631
710
  };
632
711
  }
712
+ function dependencySelection(identity, target) {
713
+ if (!identity.lockfile || target.platform === "macos" || target.native) return void 0;
714
+ return {
715
+ project: identity.project.split(sep).join("/"),
716
+ packageName: packageName(join(identity.repoRoot, identity.project))
717
+ };
718
+ }
633
719
  /** Why the native inputs cannot be sent to a remote machine, such as an ignored file among them, or null when they can. */
634
720
  async function nativeTransferRefusal(repoRoot, snapshot, signal) {
635
721
  try {
@@ -681,8 +767,12 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
681
767
  const reply = await connection.request("build.offer", {
682
768
  repo: identity.repo,
683
769
  ...identity.lockfile ? { lockfile: identity.lockfile } : {},
770
+ ...identity.dependencies && connection.supports("build-dependency-cache") ? { dependencies: identity.dependencies } : {},
684
771
  ...native ? { native } : identity.rubyVersion ? { rubyVersion: identity.rubyVersion } : {},
685
- ...native === "xcode" && identity.artifact && connection.supports("build-artifact-cache") ? { artifact: identity.artifact } : {}
772
+ ...native === "xcode" && identity.artifact && connection.supports("build-artifact-cache") ? { artifact: identity.artifact } : {},
773
+ ...identity.swiftpmArtifact && connection.supports("swiftpm-peer-cache") ? { swiftpmArtifact: identity.swiftpmArtifact } : {},
774
+ ...identity.reactNativeArtifact && connection.supports("react-native-peer-cache") ? { reactNativeArtifact: identity.reactNativeArtifact } : {},
775
+ ...native === "gradle" && identity.gradleArtifact && connection.supports("native-gradle-peer-cache") ? { gradleArtifact: identity.gradleArtifact } : {}
686
776
  }, offerMs);
687
777
  const failure = replyError(reply);
688
778
  if (failure || !("result" in reply)) {
@@ -692,17 +782,28 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
692
782
  failure: failure ?? "no offer"
693
783
  };
694
784
  }
785
+ const reported = reply.result;
786
+ const offer = {
787
+ ...reported,
788
+ warm: {
789
+ ...reported.warm,
790
+ dependencies: identity.dependencies !== void 0 && connection.supports("build-dependency-cache") && reported.warm.dependencies
791
+ }
792
+ };
695
793
  return {
696
794
  credential,
697
795
  connection,
698
- offer: reply.result
796
+ offer: identity.swiftpmArtifact && !connection.supports("swiftpm-peer-cache") || identity.reactNativeArtifact && !connection.supports("react-native-peer-cache") || native === "gradle" && (!identity.gradleArtifact || !connection.supports("native-gradle-peer-cache")) ? {
797
+ ...offer,
798
+ artifact: null
799
+ } : offer
699
800
  };
700
801
  }
701
802
  /**
702
803
  * Asks every paired machine for an offer in parallel and keeps the connection to the one `pickOffer` chooses, or
703
804
  * returns why none takes the build. A named selection probes only its credential and skips auto load gating.
704
805
  */
705
- async function chooseBuildMachine({ projectRoot, target, mode, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, cacheOnly = false }) {
806
+ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, gradleArtifact, reactNativeArtifact, swiftpmArtifact, cacheOnly = false }) {
706
807
  const started = Date.now();
707
808
  let identity;
708
809
  try {
@@ -713,11 +814,32 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
713
814
  if (namedBuildMachine(selected)) machines = machines.filter((each) => each.machine === selected).slice(0, 1);
714
815
  else machines = machines.filter((each) => automaticMachineEnabled("build", each.machine));
715
816
  const rubyVersion = readRubyVersion(projectRoot) ?? void 0;
817
+ const gradleQuery = gradleArtifact ? {
818
+ ...gradleArtifact,
819
+ project: identity.project
820
+ } : void 0;
821
+ const reactNativeQuery = reactNativeArtifact ? reactNativeBuildQuery(reactNativeArtifact.request, reactNativeArtifact.fingerprint, identity.project, target.local) : null;
822
+ const swiftpmQuery = swiftpmArtifact?.artifactInputs ? swiftpmArtifactQuery({
823
+ project: identity.project,
824
+ sourceDigest: manifestDigest(await sourceManifest(identity.repoRoot, true, runCancellationSignal(ambientContext()) ?? ambientContext()?.signal)),
825
+ stimBuild: target.local.stimBuild,
826
+ inputs: swiftpmArtifact.artifactInputs,
827
+ build: {
828
+ product: swiftpmArtifact.product,
829
+ infoPlist: swiftpmArtifact.infoPlist,
830
+ resources: swiftpmArtifact.resources ?? {},
831
+ assetCatalog: swiftpmArtifact.assetCatalog ?? null
832
+ }
833
+ }) : null;
716
834
  const asked = await Promise.all(machines.map((credential) => probeMachine(credential, {
717
835
  ...identity,
718
836
  rubyVersion,
837
+ dependencies: dependencySelection(identity, target),
719
838
  ...target.platform !== "macos" ? { native: target.native } : {},
720
- ...artifact ? { artifact } : {}
839
+ ...artifact ? { artifact } : {},
840
+ ...gradleQuery ? { gradleArtifact: gradleQuery } : {},
841
+ ...reactNativeQuery ? { reactNativeArtifact: reactNativeQuery } : {},
842
+ ...swiftpmQuery ? { swiftpmArtifact: swiftpmQuery } : {}
721
843
  })));
722
844
  const { order, reasons, candidates } = pickOffer({
723
845
  localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local"),
@@ -725,7 +847,7 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
725
847
  mode,
726
848
  here,
727
849
  target,
728
- artifact,
850
+ artifact: swiftpmQuery ? "swiftpm" : reactNativeQuery ? `react-native-${reactNativeQuery.platform}` : gradleQuery ? "native-gradle" : artifact,
729
851
  cacheOnly,
730
852
  offers: asked.map((each) => ({
731
853
  machine: each.credential.machine,
@@ -757,7 +879,23 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
757
879
  identity,
758
880
  runnersUp: rest,
759
881
  automatic: selected === "auto",
760
- cacheOnly
882
+ cacheOnly,
883
+ ...gradleQuery ? { gradleArtifact: gradleQuery } : {},
884
+ ...reactNativeQuery ? { reactNativeArtifact: reactNativeQuery } : {},
885
+ ...swiftpmQuery ? { swiftpmArtifact: swiftpmQuery } : {}
886
+ };
887
+ }
888
+ function macosBuildParameters(request, peerCache) {
889
+ return {
890
+ ...request.cacheArtifact === true && peerCache ? { cacheArtifact: true } : {},
891
+ macos: {
892
+ ...request.artifactInputs && peerCache ? { artifactInputs: request.artifactInputs } : {},
893
+ product: request.product,
894
+ infoPlist: request.infoPlist,
895
+ bundleId: request.bundleId,
896
+ ...request.resources !== void 0 ? { resources: request.resources } : {},
897
+ ...request.assetCatalog !== void 0 ? { assetCatalog: request.assetCatalog } : {}
898
+ }
761
899
  };
762
900
  }
763
901
  function validArtifactIdentity(request, fingerprint) {
@@ -769,6 +907,38 @@ const ARTIFACT_NAME = {
769
907
  android: /^[^/]+\.apk$/,
770
908
  macos: /^[^/]+\.app$/
771
909
  };
910
+ async function peerArtifact(choice, request, fingerprint) {
911
+ const swiftpm = choice.swiftpmArtifact;
912
+ if (swiftpm) {
913
+ if (request.platform !== "macos" || !isDeepStrictEqual(swiftpm, swiftpmArtifactQuery({
914
+ ...swiftpm,
915
+ inputs: request.artifactInputs,
916
+ build: {
917
+ product: request.product,
918
+ infoPlist: request.infoPlist,
919
+ resources: request.resources ?? {},
920
+ assetCatalog: request.assetCatalog ?? null
921
+ }
922
+ }))) throw new Error("The SwiftPM artifact query does not match the build request.");
923
+ if (!choice.connection.supports("swiftpm-peer-cache") || manifestDigest(await sourceManifest(choice.identity.repoRoot, true, runCancellationSignal(ambientContext()) ?? ambientContext()?.signal)) !== swiftpm.sourceDigest) return null;
924
+ return matchingArtifact(choice.offer, "swiftpm");
925
+ }
926
+ const reactNative = choice.reactNativeArtifact;
927
+ if (reactNative) {
928
+ if (typeof fingerprint !== "string" || !isDeepStrictEqual(reactNative, reactNativeBuildQuery(request, fingerprint, choice.identity.project, choice.target.local))) throw new Error("The React Native artifact query does not match the build request.");
929
+ return choice.connection.supports("react-native-peer-cache") ? matchingArtifact(choice.offer, `react-native-${reactNative.platform}`) : null;
930
+ }
931
+ const query = choice.gradleArtifact;
932
+ if (query) {
933
+ if (request.platform !== "android" || request.native?.provider !== "gradle" || !request.native.cache?.read || !request.native.cache.remote || query.project !== choice.identity.project || query.sourceDigest !== request.native.transfer.digest || !isDeepStrictEqual(query.inputs, request.native.transfer.declaration) || !isDeepStrictEqual(query.android, request.android)) throw new Error("The Gradle artifact query does not match the build request.");
934
+ return choice.connection.supports("native-gradle-peer-cache") ? matchingArtifact(choice.offer, "native-gradle") : null;
935
+ }
936
+ if (request.platform === "ios" && request.native && typeof fingerprint === "string" && choice.connection.supports("build-artifact-cache")) return matchingArtifact(choice.offer, {
937
+ fingerprint,
938
+ cacheKey: request.native.cacheKey
939
+ });
940
+ return null;
941
+ }
772
942
  /**
773
943
  * Reconnects to the machine that runs `job` and takes the job over with `build.attach`, retrying until
774
944
  * `RESUME_WINDOW_MS`, shorter than the machine's grace for a dropped connection, has passed. Returns why it
@@ -1018,6 +1188,7 @@ async function offloadBuild(input) {
1018
1188
  choice.connection.close();
1019
1189
  const probe = await probeMachine(choice.credential, {
1020
1190
  ...identity,
1191
+ dependencies: dependencySelection(identity, choice.target),
1021
1192
  ...native ? { native: native.provider } : {}
1022
1193
  });
1023
1194
  if ("failure" in probe) return fail(probe.failure);
@@ -1049,10 +1220,7 @@ async function offloadBuild(input) {
1049
1220
  checkCancelled();
1050
1221
  if (!validArtifactIdentity(request, expectedFingerprint)) return fail("The build request has an invalid reusable artifact identity.");
1051
1222
  if (native?.provider === "xcode" && native.snapshot.hash !== expectedFingerprint) return fail("The native source snapshot does not match the requested artifact identity.");
1052
- const cachedIdentity = native?.provider === "xcode" && typeof expectedFingerprint === "string" ? {
1053
- fingerprint: expectedFingerprint,
1054
- cacheKey: native.cacheKey
1055
- } : void 0;
1223
+ let cached = null;
1056
1224
  let job = null;
1057
1225
  let early = [];
1058
1226
  let resuming = false;
@@ -1113,13 +1281,14 @@ async function offloadBuild(input) {
1113
1281
  if (moveOn(reason)) continue;
1114
1282
  return fail(reason);
1115
1283
  }
1116
- const cached = native?.provider === "xcode" && choice.connection.supports("build-artifact-cache") ? matchingArtifact(choice.offer, cachedIdentity) : null;
1284
+ cached = await peerArtifact(choice, request, expectedFingerprint);
1117
1285
  if (cached) {
1118
1286
  cacheHit = true;
1119
1287
  settle({
1120
1288
  ok: true,
1121
1289
  artifact: cached,
1122
- fingerprint: expectedFingerprint
1290
+ fingerprint: expectedFingerprint,
1291
+ androidPackage: cached.androidPackage
1123
1292
  });
1124
1293
  break;
1125
1294
  }
@@ -1150,21 +1319,19 @@ async function offloadBuild(input) {
1150
1319
  cacheKey: native.cacheKey,
1151
1320
  arch: native.arch,
1152
1321
  parameters: native.snapshot.parameters
1153
- } : { inputs: native.transfer.declaration }
1322
+ } : {
1323
+ inputs: native.transfer.declaration,
1324
+ ...choice.connection.supports("native-gradle-artifact-cache") ? { cache: native.cache } : {}
1325
+ }
1154
1326
  } } : {},
1155
- ...request.platform === "macos" ? { macos: {
1156
- product: request.product,
1157
- infoPlist: request.infoPlist,
1158
- bundleId: request.bundleId,
1159
- ...request.resources !== void 0 ? { resources: request.resources } : {},
1160
- ...request.assetCatalog !== void 0 ? { assetCatalog: request.assetCatalog } : {}
1161
- } } : {
1327
+ ...request.platform === "macos" ? macosBuildParameters(request, choice.connection.supports("swiftpm-peer-cache")) : {
1162
1328
  configuration: request.platform === "ios" ? request.configuration : null,
1163
1329
  scheme: request.platform === "ios" ? request.scheme : null,
1164
1330
  iosProjectPath: request.platform === "ios" ? request.iosProjectPath ?? null : null,
1165
1331
  runtime: request.platform === "ios" ? request.runtime : null,
1166
1332
  packageName: packageName(join(identity.repoRoot, identity.project)),
1167
1333
  isExpo: request.isExpo,
1334
+ ...!native && request.cacheArtifact === true && choice.connection.supports("react-native-peer-cache") ? { cacheArtifact: true } : {},
1168
1335
  optimizations: request.platform === "ios" && isJsonObject(request.optimizations) ? request.optimizations : null,
1169
1336
  ...request.platform === "android" ? { android: request.android } : {}
1170
1337
  },
@@ -1219,15 +1386,19 @@ async function offloadBuild(input) {
1219
1386
  cacheHit,
1220
1387
  checkCancelled,
1221
1388
  method: cacheHit ? "build.cached-artifact" : "build.artifact",
1222
- params: cacheHit && native?.provider === "xcode" ? {
1389
+ params: cached ? {
1223
1390
  repo: identity.repo,
1224
1391
  artifact: {
1225
- fingerprint: expectedFingerprint,
1226
- cacheKey: native.cacheKey
1227
- }
1392
+ fingerprint: cached.fingerprint,
1393
+ cacheKey: cached.cacheKey
1394
+ },
1395
+ ...choice.gradleArtifact ? { gradleArtifact: choice.gradleArtifact } : {},
1396
+ ...choice.reactNativeArtifact ? { reactNativeArtifact: choice.reactNativeArtifact } : {},
1397
+ ...choice.swiftpmArtifact ? { swiftpmArtifact: choice.swiftpmArtifact } : {}
1228
1398
  } : { job }
1229
1399
  });
1230
1400
  if ("failure" in downloaded) return cacheHit ? await retryCachedMiss(downloaded.failure) : fail(downloaded.failure);
1401
+ if (cacheHit && choice.swiftpmArtifact && !await peerArtifact(choice, request, expectedFingerprint)) return await retryCachedMiss("The SwiftPM source changed during artifact transfer.");
1231
1402
  const { artifactPath, digest, received, declared } = downloaded;
1232
1403
  const fetchMs = Date.now() - fetchStarted;
1233
1404
  closeOffload(choice);
@@ -1403,4 +1574,4 @@ function offloadCheck(projectRoot, targets) {
1403
1574
  };
1404
1575
  }
1405
1576
  //#endregion
1406
- export { nativeTransferRefusal as a, offloadPlacement as c, simulatorRuntime as d, setRemoteLogSink as f, maintenanceLogger as h, closeOffload as i, placementLoad as l, clearCorruptCompilationCache as m, buildPlacementCandidates as n, offloadBuild as o, COMPILATION_CACHE_CORRUPT as p, chooseBuildMachine as r, offloadCheck as s, BuildConnection as t, remotePhaseText as u };
1577
+ export { clearCorruptCompilationCache as _, nativeTransferRefusal as a, offloadPlacement as c, simulatorRuntime as d, reactNativeArtifactReceipt as f, COMPILATION_CACHE_CORRUPT as g, setRemoteLogSink as h, closeOffload as i, placementLoad as l, reactNativeBuildQuery as m, buildPlacementCandidates as n, offloadBuild as o, reactNativeArtifactToolchain as p, chooseBuildMachine as r, offloadCheck as s, BuildConnection as t, remotePhaseText as u, maintenanceLogger as v };
@@ -1,4 +1,4 @@
1
- import { n as NdjsonWriter, t as Executor } from "./exec-H20xSg2T.mjs";
1
+ import { n as NdjsonWriter, t as Executor } from "./exec-DnYc4HGH.mjs";
2
2
  import { ChildProcess } from "node:child_process";
3
3
  //#region src/collector/android.d.ts
4
4
  declare function androidClockOffset(serial: string, { exec, now }?: {
@@ -1,12 +1,12 @@
1
- import { p as process_identity_exports } from "./exec-_UbtCQcG.mjs";
1
+ import { g as process_identity_exports } from "./exec-DEoAhcze.mjs";
2
2
  import { m as workspaceLogsDir } from "./paths-DQtTgsBf.mjs";
3
- import { H as deviceSlotKey, J as validateDeviceSlot } from "./config-CYcBF478.mjs";
3
+ import { V as deviceSlotKey, q as validateDeviceSlot } from "./config-DlrsduwG.mjs";
4
4
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
5
5
  import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
6
- import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-CXGP1bsD.mjs";
7
- import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-DEmM5vhh.mjs";
8
- import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-BEJ8Jpl7.mjs";
9
- import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-qNJt4dFm.mjs";
6
+ import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-BXZ0c7Kb.mjs";
7
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-C5fo5Edb.mjs";
8
+ import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-DR5lZ2Az.mjs";
9
+ import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-xtlRHaeB.mjs";
10
10
  import { existsSync } from "node:fs";
11
11
  import { isAbsolute, join, resolve } from "node:path";
12
12
  import { LOG_ROTATE_BYTES } from "@stim-cli/core";
@@ -1,5 +1,5 @@
1
1
  import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
2
- import { t as NO_PROJECT_REFUSAL } from "./project-BZNjmW_8.mjs";
2
+ import { t as NO_PROJECT_REFUSAL } from "./project-wM_XFTvE.mjs";
3
3
  import { quotedPath as quotedPath$1 } from "@stim-cli/core";
4
4
  import chalk from "chalk";
5
5
  //#region src/diagnostics/launch-error-preview.ts
@@ -1,4 +1,5 @@
1
- import { f as ownership_claim_exports, g as trackReportResource, m as reportSignal, p as process_identity_exports, t as getExecutor } from "./exec-_UbtCQcG.mjs";
1
+ import { _ as reportSignal, g as process_identity_exports, r as WorkspaceProcessCleanupError, t as getExecutor, x as ownership_claim_exports, y as trackReportResource } from "./exec-DEoAhcze.mjs";
2
+ import { t as runOperationFile } from "./operation-exec-BW0em61G.mjs";
2
3
  import { join } from "node:path";
3
4
  import { ambientEnv, configDir, ensurePrivateDir } from "@stim-cli/core";
4
5
  import { allMetroPorts, cannotHost, clientIdentity, configCorruptRepair, endpoint, findEnclosingWorktreeRoot, findPeer as findPeer$1, getConcurrencyLimits, getConfigPath, getConfigPath as getConfigPath$1, getProject, getProjectSettings, getRepoSettings, isJsonObject, isPathPrefix, loadConfig, loadConfig as loadConfig$1, machineEndpoint, parseMachine, parseMachine as parseMachine$1, validateAutomaticPool, withConfigLock, withConfigLock as withConfigLock$1, withConfigLockAsync, withConfigLockAsync as withConfigLockAsync$1 } from "@stim-cli/core/state";
@@ -77,7 +78,7 @@ function outdatedServer(entry, version, command) {
77
78
  return {
78
79
  title: `Remote machine ${entry} runs an older stim-server`,
79
80
  detail: `The stim-server on ${entry} speaks an older protocol than this Stim, so it cannot authenticate this machine.`,
80
- fix: command ? `${update}, then run this there to approve this machine: ${command}` : `${update}, then run \`stim doctor --fix\` here.`
81
+ fix: command ? `${update}, then run this there to approve this machine: ${command}\nAfter approving, run \`stim doctor\` on this machine to reconnect.` : `${update}, then run \`stim doctor --fix\` here.`
81
82
  };
82
83
  }
83
84
  /**
@@ -254,10 +255,10 @@ async function resolveEndpoint(credential, status = () => tailscaleStatusAsync(s
254
255
  }
255
256
  /** The remedy for a pending request: the printed setup command, or where the person finds it. */
256
257
  function setupRemedy(entry, command) {
257
- return command ? `A person on ${entry} runs this there to approve this machine: ${command}` : `A person on ${entry} runs the \`stim-server setup\` command Stim Desktop showed for this machine.`;
258
+ return command ? `A person on ${entry} runs this there to approve this machine: ${command}\nAfter approving, run \`stim doctor\` on this machine to reconnect.` : `A person on ${entry} runs the \`stim-server setup\` command Stim Desktop showed for this machine.`;
258
259
  }
259
260
  function setupCommand(ticket, expiresAt, flags, version) {
260
- return `STIM_SETUP_TICKET=${ticket} npx --yes --package @stim-cli/server@${version} stim-server setup --expires ${expiresAt} ${flags.map((flag) => `--${flag}`).join(" ")}`;
261
+ return `STIM_SETUP_TICKET=${ticket} STIM_SETUP_ORIGIN=doctor npx --yes --package @stim-cli/server@${version} stim-server setup --expires ${expiresAt} ${flags.map((flag) => `--${flag}`).join(" ")}`;
261
262
  }
262
263
  function newPending(input, ticket, expiresAt, now) {
263
264
  return {
@@ -601,17 +602,22 @@ function isOnMountedVolume(path, mountedVolumes, { statFn = statSync } = {}) {
601
602
  function directorySize(dir, { timeoutMs }) {
602
603
  return measuredDirectorySize(dir, { timeoutMs }) ?? 0;
603
604
  }
604
- async function directorySizeAsync(dir, { timeoutMs }) {
605
- return await measuredDirectorySizeAsync(dir, { timeoutMs }) ?? 0;
605
+ async function directorySizeAsync(dir, options) {
606
+ return await measuredDirectorySizeAsync(dir, options) ?? 0;
606
607
  }
607
- async function measuredDirectorySizeAsync(dir, { timeoutMs }) {
608
+ async function measuredDirectorySizeAsync(dir, { timeoutMs, signal, operation }) {
608
609
  let out;
609
610
  try {
610
- out = await getExecutor().runFileAsync("du", ["-sk", dir], {
611
+ out = await runOperationFile(operation, getExecutor(), "du", ["-sk", dir], {
611
612
  timeoutMs,
612
- killSignal: "SIGKILL"
613
+ killSignal: "SIGKILL",
614
+ signal,
615
+ cwd: operation?.cwd
613
616
  });
614
- } catch {
617
+ } catch (error) {
618
+ if (error instanceof WorkspaceProcessCleanupError) throw error;
619
+ signal?.throwIfAborted();
620
+ operation?.signal.throwIfAborted();
615
621
  return null;
616
622
  }
617
623
  if (!out) return 0;
@@ -946,4 +952,4 @@ function allConsolePortsAndSerials({ isMounted = isOnMountedVolume } = {}) {
946
952
  return result;
947
953
  }
948
954
  //#endregion
949
- export { openAuthenticated as $, writeConfigSettingAsync as A, assignSlotDevice as B, saveConfig as C, withConfigLock$1 as D, upsertProject as E, isOnMountedVolume as F, parseDeviceSlotOption as G, deviceSlotKey as H, listMountedVolumes as I, validateDeviceSlot as J, projectDeviceSlots as K, measuredDirectorySize as L, directorySize as M, directorySizeAsync as N, withConfigLockAsync$1 as O, formatBytes as P, findPeer$1 as Q, measuredDirectorySizeAsync as R, removeProject as S, setSupervisor as T, deviceSlotPlatforms as U, deviceSlotFileKey as V, parseDeviceSlotKey as W, doctorIo as X, SERVER_OUTDATED as Y, endpoint as Z, loadConfig$1 as _, clearDevice as a, sayHello as at, releaseAndroidConsolePort as b, ensureConfig as c, readHostPermissions as ct, getConfigDir as d, outdatedServer as et, getConfigPath$1 as f, isPathPrefix as g, getRepoSettings as h, clearAndroidBootPending as i, resolveEndpoint as it, acquireAvdClaim as j, writeConfigSetting as k, findEnclosingWorktreeRoot as l, getProjectSettings as m, allMetroPorts as n, reachMachine as nt, clearSupervisor as o, setupRemedy as ot, getProject as p, removeSlotDevice as q, claimMetroPort as r, realIo as rt, configCorruptRepair as s, tailscaleStatusAsync as st, allConsolePortsAndSerials as t, parseMachine$1 as tt, getConcurrencyLimits as u, recordIosSchemeApprovals as v, setDevice as w, releaseMetroPort as x, refuseRelativeStimPaths as y, volumeRootFor as z };
955
+ export { outdatedServer as $, writeConfigSettingAsync as A, deviceSlotFileKey as B, saveConfig as C, withConfigLock$1 as D, upsertProject as E, isOnMountedVolume as F, projectDeviceSlots as G, deviceSlotPlatforms as H, listMountedVolumes as I, SERVER_OUTDATED as J, removeSlotDevice as K, measuredDirectorySizeAsync as L, directorySize as M, directorySizeAsync as N, withConfigLockAsync$1 as O, formatBytes as P, openAuthenticated as Q, volumeRootFor as R, removeProject as S, setSupervisor as T, parseDeviceSlotKey as U, deviceSlotKey as V, parseDeviceSlotOption as W, endpoint as X, doctorIo as Y, findPeer$1 as Z, loadConfig$1 as _, clearDevice as a, setupRemedy as at, releaseAndroidConsolePort as b, ensureConfig as c, getConfigDir as d, parseMachine$1 as et, getConfigPath$1 as f, isPathPrefix as g, getRepoSettings as h, clearAndroidBootPending as i, sayHello as it, acquireAvdClaim as j, writeConfigSetting as k, findEnclosingWorktreeRoot as l, getProjectSettings as m, allMetroPorts as n, realIo as nt, clearSupervisor as o, tailscaleStatusAsync as ot, getProject as p, validateDeviceSlot as q, claimMetroPort as r, resolveEndpoint as rt, configCorruptRepair as s, readHostPermissions as st, allConsolePortsAndSerials as t, reachMachine as tt, getConcurrencyLimits as u, recordIosSchemeApprovals as v, setDevice as w, releaseMetroPort as x, refuseRelativeStimPaths as y, assignSlotDevice as z };
@@ -1,5 +1,5 @@
1
- import { v as withDirLock$1 } from "./paths-DQtTgsBf.mjs";
2
- import { d as getConfigDir } from "./config-CYcBF478.mjs";
1
+ import { v as withDirLock$1, y as withDirLockAsync$1 } from "./paths-DQtTgsBf.mjs";
2
+ import { d as getConfigDir } from "./config-DlrsduwG.mjs";
3
3
  import { renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { ensurePrivateDir } from "@stim-cli/core";
5
5
  import { createdDevicesFile, createdDevicesLock, readCreatedDevices, readCreatedDevices as readCreatedDevices$1 } from "@stim-cli/core/state";
@@ -34,5 +34,15 @@ function recordCreatedDevice(platform, id) {
34
34
  function forgetCreatedDevice(platform, id) {
35
35
  update(platform, (entries) => entries.delete(id));
36
36
  }
37
+ /** Waits asynchronously for the ledger lock, then atomically forgets the device. The synchronous transaction decides whether to commit the removal; cancellation stops admission. */
38
+ function forgetCreatedDeviceAsync(platform, id, signal, transaction = (forget) => {
39
+ forget();
40
+ return true;
41
+ }) {
42
+ return withDirLockAsync$1(createdDevicesLock(), () => transaction(() => forgetCreatedDevice(platform, id)), {
43
+ ensureParent: () => ensurePrivateDir(getConfigDir()),
44
+ signal
45
+ });
46
+ }
37
47
  //#endregion
38
- export { readCreatedDevices$1 as n, recordCreatedDevice as r, forgetCreatedDevice as t };
48
+ export { recordCreatedDevice as i, forgetCreatedDeviceAsync as n, readCreatedDevices$1 as r, forgetCreatedDevice as t };
@@ -1,5 +1,5 @@
1
- import { t as getExecutor } from "./exec-_UbtCQcG.mjs";
2
- import { Ft as repoRoot } from "./settings-CsJDEXgK.mjs";
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { Mt as repoRoot } from "./settings-C7O8A6ZI.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { dirname, join, relative } from "node:path";
5
5
  //#region src/dependency-state.ts
@@ -1,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-_UbtCQcG.mjs";
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
2
  import { openSync } from "node:fs";
3
3
  //#region src/detached-entry.ts
4
4
  const LOG_FILE_FLAG = "--log-file";
@@ -1,5 +1,5 @@
1
- import { C as resolvePackageJson, b as isPackageResolvable } from "./project-BZNjmW_8.mjs";
2
- import { An as readBundleSchemes, kn as pickDevClientScheme } from "./budget-Bs6SxxzO.mjs";
1
+ import { C as resolvePackageJson, b as isPackageResolvable } from "./project-wM_XFTvE.mjs";
2
+ import { An as readBundleSchemes, kn as pickDevClientScheme } from "./budget-Cvwn54qV.mjs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { isJsonObject, readJsonObject } from "@stim-cli/core/state";
5
5
  //#region src/commands/dev-client.ts