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,18 +1,18 @@
1
- import { d as withDrainingCancellation, f as ownership_claim_exports } from "./exec-_UbtCQcG.mjs";
1
+ import { h as withDrainingCancellation, x as ownership_claim_exports } from "./exec-DEoAhcze.mjs";
2
2
  import { d as workspaceDir } from "./paths-DQtTgsBf.mjs";
3
- import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-B1UrjZHL.mjs";
4
- import { en as throwIfCancelled } from "./settings-CsJDEXgK.mjs";
5
- import { Hn as isEasAuthFailureText, Ln as RESOLVE_TIMEOUT_MS, Vn as easAuthNote } from "./budget-Bs6SxxzO.mjs";
6
- import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-DY_RLx3C.mjs";
7
- import { d as prepareProviderDownloadDir, f as providerDownloadPath } from "./build-cache-DmyR9Zzc.mjs";
8
- import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine, t as CCACHE_NOT_RUN } from "./ccache-BJRZ9pG3.mjs";
9
- import { c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, u as remotePhaseText } from "./client-UXD70ZbM.mjs";
10
- import { a as requireLocalBuild, r as namedBuildMachine, t as OffloadRefusal } from "./selection-CSl9i5qU.mjs";
11
- import { f as formatDiagnostic } from "./react-native-build-rhk4smwQ.mjs";
12
- import { c as skippedMissReason } from "./prebuild-uD_ipCxF.mjs";
13
- import { t as buildPlacementRecord } from "./placement-log-BqGbTa61.mjs";
14
- import { t as acquireArtifact } from "./acquire-artifact-CD4lbiWE.mjs";
15
- import { a as PLATFORM, h as displayPath } from "./support-67vraa1Q.mjs";
3
+ import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-gwpm28fu.mjs";
4
+ import { f as throwIfCancelled } from "./operation-exec-BW0em61G.mjs";
5
+ import { Hn as isEasAuthFailureText, Ln as RESOLVE_TIMEOUT_MS, Vn as easAuthNote } from "./budget-Cvwn54qV.mjs";
6
+ import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-NwUuxbkg.mjs";
7
+ import { d as prepareProviderDownloadDir, f as providerDownloadPath } from "./build-cache-Dv7RN200.mjs";
8
+ import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine, t as CCACHE_NOT_RUN } from "./ccache-Btwc36-I.mjs";
9
+ import { c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, u as remotePhaseText } from "./client-OyRoEuSr.mjs";
10
+ import { a as requireLocalBuild, r as namedBuildMachine, t as OffloadRefusal } from "./selection-DSMbWEX2.mjs";
11
+ import { f as formatDiagnostic } from "./react-native-build-Dvd8hC21.mjs";
12
+ import { l as skippedMissReason } from "./prebuild-D4JoEAEs.mjs";
13
+ import { t as buildPlacementRecord } from "./placement-log-BnGgJRRZ.mjs";
14
+ import { n as settleArtifactUploads, t as acquireArtifact } from "./acquire-artifact-Co2k4f7O.mjs";
15
+ import { a as PLATFORM, h as displayPath } from "./support-yUiOjnVY.mjs";
16
16
  import { t as AndroidRecipeRefusal } from "./android-project-BCAAmMwz.mjs";
17
17
  import { rmSync } from "node:fs";
18
18
  import { join } from "node:path";
@@ -74,6 +74,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
74
74
  const loadTieredProvider = cachePolicy.remote && cacheProviderConfig ? () => providerLoad ??= loadCacheProviderModule({
75
75
  projectRoot: root,
76
76
  config: cacheProviderConfig,
77
+ env: context.env,
77
78
  timeoutMs: timeoutFromEnv(PROVIDER_LOAD_TIMEOUT_ENV, PROVIDER_LOAD_TIMEOUT_MS, context.env)
78
79
  }).then((loaded) => {
79
80
  if (!loaded.provider || !recipe.providerCache) return loaded;
@@ -160,9 +161,9 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
160
161
  let abandonedRemote = false;
161
162
  let uploadPending = null;
162
163
  async function resolveRemoteArtifact() {
163
- if (cacheIneligible || !recipe.legacyCache) return;
164
+ if (cacheIneligible || !recipe.expoCache) return;
164
165
  if (!apkPath) {
165
- const loaded = await recipe.legacyCache.load();
166
+ const loaded = await recipe.expoCache.load();
166
167
  if (loaded?.unavailable) phase("cache", chalk.yellow(`provider not usable: ${loaded.unavailable}`));
167
168
  else if (loaded?.provider) remote = loaded;
168
169
  if (remote?.name === "eas") {
@@ -185,7 +186,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
185
186
  platform: PLATFORM,
186
187
  projectRoot: root,
187
188
  fingerprintHash: hash,
188
- runOptions: recipe.legacyCache?.runOptions ?? null
189
+ runOptions: recipe.expoCache?.runOptions ?? null
189
190
  });
190
191
  if (hit?.appPath) {
191
192
  let stored = null;
@@ -333,6 +334,14 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
333
334
  });
334
335
  if (!placement.offload) {
335
336
  hereReason = placement.reason;
337
+ if (placement.code === "this-mac-free" && cachePolicy.read && cachePolicy.remote && (recipe.offload?.uncachedArtifacts || recipe.offload && !recipe.offload.request.native)) return {
338
+ cacheOnly: true,
339
+ mode,
340
+ here,
341
+ code: placement.code,
342
+ reason: placement.reason,
343
+ machines
344
+ };
336
345
  writer.write(buildPlacementRecord({
337
346
  platform: PLATFORM,
338
347
  buildMachine,
@@ -345,6 +354,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
345
354
  return null;
346
355
  }
347
356
  return {
357
+ cacheOnly: false,
348
358
  mode,
349
359
  here,
350
360
  code: placement.code,
@@ -354,14 +364,17 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
354
364
  }
355
365
  /** Asks the paired machines once the post-mutation key is known; null builds here. */
356
366
  async function chooseMachine(candidate) {
367
+ const offload = recipe.offload;
357
368
  let asked = [];
358
369
  let target;
359
370
  try {
360
- target = await recipe.offload.target();
371
+ target = await offload.target();
361
372
  } catch (error) {
373
+ if (candidate.cacheOnly) return null;
362
374
  fallBack(error.message);
363
375
  return null;
364
376
  }
377
+ const request = offload.request;
365
378
  const choice = await chooseBuildMachine({
366
379
  projectRoot: root,
367
380
  target,
@@ -370,9 +383,23 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
370
383
  note: (line) => phase("build", chalk.dim(`offload: ${line}`)),
371
384
  machines: candidate.machines,
372
385
  selected: buildMachine,
373
- onCandidates: (each) => asked = each
386
+ onCandidates: (each) => asked = each,
387
+ cacheOnly: candidate.cacheOnly,
388
+ ...cachePolicy.read && cachePolicy.remote && storeHash && !request.native ? { reactNativeArtifact: {
389
+ fingerprint: storeHash,
390
+ request
391
+ } } : {},
392
+ ...cachePolicy.read && cachePolicy.remote && request.native?.provider === "gradle" && request.android.variant ? { gradleArtifact: {
393
+ sourceDigest: request.native.transfer.digest,
394
+ inputs: request.native.transfer.declaration,
395
+ android: {
396
+ ...request.android,
397
+ variant: request.android.variant
398
+ }
399
+ } } : {}
374
400
  });
375
401
  if (typeof choice === "string") {
402
+ if (candidate.cacheOnly) return null;
376
403
  const only = candidate.machines.length === 1 ? candidate.machines[0].machine : null;
377
404
  if (only && choice.startsWith(`${only}: `)) fallbackMachine = only;
378
405
  fallBack(choice, choice, {
@@ -473,6 +500,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
473
500
  throwIfCancelled(signal, "offloaded build cache copy");
474
501
  step("compile");
475
502
  if (!outcome.ok || !stored) {
503
+ if (candidate.cacheOnly) return false;
476
504
  const why = reason ?? "the APK was not stored";
477
505
  fallbackMachine = choice.machine;
478
506
  fallBack(`${choice.machine}: ${why}`, `offload failed: ${why}`, {
@@ -492,9 +520,10 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
492
520
  if (uncached) {
493
521
  record.fingerprint = null;
494
522
  record.cacheKey = null;
495
- record.cacheHit = false;
496
- record.cacheSkipped = true;
523
+ record.cacheHit = outcome.cacheHit ? "remote" : false;
524
+ record.cacheSkipped = !outcome.cacheHit;
497
525
  }
526
+ if (outcome.cacheHit) lateHit();
498
527
  apkPath = stored;
499
528
  handoff = outcome.handoff ?? null;
500
529
  record.builtOn = outcome.machine;
@@ -506,13 +535,13 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
506
535
  buildMs: timings.totalMs
507
536
  });
508
537
  ccacheActivity = outcome.ccache;
509
- phase("build", `built on ${outcome.machine} in ${formatDuration(timings.totalMs)}: offer ${formatDuration(timings.offerMs)}, sync ${formatDuration(timings.syncMs)}, build ${formatDuration(timings.workerMs)}, fetch ${formatDuration(timings.fetchMs)}`);
538
+ phase("build", `${outcome.cacheHit ? "reused from" : "built on"} ${outcome.machine} in ${formatDuration(timings.totalMs)}: offer ${formatDuration(timings.offerMs)}, sync ${formatDuration(timings.syncMs)}, build ${formatDuration(timings.workerMs)}, fetch ${formatDuration(timings.fetchMs)}`);
510
539
  phase("cache", `compilation cache on ${outcome.machine} ${ccacheActivityLine(ccacheActivity)}`);
511
540
  writer.write({
512
541
  src: "build",
513
542
  level: "info",
514
543
  event: "offload_done",
515
- msg: `built on ${outcome.machine}`,
544
+ msg: `${outcome.cacheHit ? "reused from" : "built on"} ${outcome.machine}`,
516
545
  timings
517
546
  });
518
547
  return true;
@@ -574,7 +603,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
574
603
  explainMiss(rekeyedBy);
575
604
  step("compile");
576
605
  }
577
- if (offload) stats.setPlacement({
606
+ if (offload && !offload.cacheOnly) stats.setPlacement({
578
607
  decision: "fell-back",
579
608
  slotWaitMs,
580
609
  deviceSlotWaitMs: stats.deviceSlotWaitMs(),
@@ -664,16 +693,19 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
664
693
  phase("cache", chalk.yellow(`could not store the build: ${err?.message || err}`));
665
694
  }
666
695
  }
667
- if (remote) uploadPending = uploadRemoteBuild({
668
- context,
669
- logWriter: writer,
670
- provider: remote.provider,
671
- platform: PLATFORM,
672
- projectRoot: root,
673
- fingerprintHash: storeHash,
674
- buildPath: artifactPath,
675
- runOptions: recipe.legacyCache?.runOptions ?? null
676
- });
696
+ if (remote) {
697
+ uploadPending = uploadRemoteBuild({
698
+ context,
699
+ logWriter: writer,
700
+ provider: remote.provider,
701
+ platform: PLATFORM,
702
+ projectRoot: root,
703
+ fingerprintHash: storeHash,
704
+ buildPath: artifactPath,
705
+ runOptions: recipe.expoCache?.runOptions ?? null
706
+ });
707
+ uploadPending.catch(() => {});
708
+ }
677
709
  }
678
710
  const acquired = await acquireArtifact({
679
711
  platform: PLATFORM,
@@ -719,7 +751,7 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
719
751
  };
720
752
  },
721
753
  settleFailed: async () => {
722
- await Promise.allSettled([uploadPending, providerUpload]);
754
+ await settleArtifactUploads(uploadPending, providerUpload);
723
755
  },
724
756
  refuse: (error) => {
725
757
  if (error instanceof OffloadRefusal) {
@@ -759,11 +791,8 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
759
791
  handoff,
760
792
  androidPackage,
761
793
  release: async () => {
762
- try {
763
- await Promise.allSettled([providerUpload, remote?.provider && "easCli" in remote.provider ? uploadPending : null]);
764
- } finally {
765
- acquired.release();
766
- }
794
+ await settleArtifactUploads(providerUpload, uploadPending);
795
+ acquired.release();
767
796
  },
768
797
  waitedForBuild,
769
798
  ccache: ccacheActivity,
@@ -0,0 +1,27 @@
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { join } from "node:path";
3
+ //#region src/macos/artifact-platform.ts
4
+ async function validateMacosArtifactPlatform(context, bundle, product, signal) {
5
+ const binary = join(bundle, "Contents", "MacOS", product);
6
+ const options = {
7
+ timeoutMs: 3e4,
8
+ signal,
9
+ declareFor: context
10
+ };
11
+ const architecture = process.arch === "x64" ? "x86_64" : process.arch;
12
+ const archs = await getExecutor().runFileAsync("xcrun", [
13
+ "lipo",
14
+ "-archs",
15
+ binary
16
+ ], options);
17
+ const platform = await getExecutor().runFileAsync("xcrun", [
18
+ "vtool",
19
+ "-arch",
20
+ architecture,
21
+ "-show-build",
22
+ binary
23
+ ], options);
24
+ if (!archs.trim().split(/\s+/).includes(architecture) || !/^\s*platform\s+MACOS\s*$/m.test(platform)) throw new Error("The cached macOS executable does not match this platform and architecture.");
25
+ }
26
+ //#endregion
27
+ export { validateMacosArtifactPlatform as t };
@@ -1,25 +1,26 @@
1
- import { t as getExecutor } from "./exec-_UbtCQcG.mjs";
2
- import { d as workspaceDir, m as workspaceLogsDir } from "./paths-DQtTgsBf.mjs";
3
- import { p as getProject } from "./config-CYcBF478.mjs";
4
- import { l as phaseLine } from "./command-output-B1UrjZHL.mjs";
5
- import { r as readWorkspaceState } from "./workspace-state-Cjuigeeu.mjs";
6
- import { Qt as cancellableSleep, a as SETTING_SHAPE_REMEDY, at as webSettings, j as metroPortSetting } from "./settings-CsJDEXgK.mjs";
7
- import { b as isPackageResolvable, v as detectIsExpo } from "./project-BZNjmW_8.mjs";
8
- import { s as readNdjsonGenerations } from "./ndjson-CgE_o3Dl.mjs";
9
- import { f as resolveProjectMetro } from "./metro-DEXpIhHC.mjs";
10
- import { f as webLogFile, m as webSupervisorLogFile, o as readWebRecord, s as updateWebRecord } from "./state-C4ZtUisW.mjs";
11
- import { en as readMetroRecords } from "./budget-Bs6SxxzO.mjs";
12
- import { T as teardownBrowserHeld, m as resolveSupervisorTarget } from "./workspaces-BccMFmGQ.mjs";
13
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-1_1OoVW5.mjs";
14
- import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-BWTzt6mu.mjs";
15
- import { n as sendToOwnedPage, t as liveWebRecord } from "./page-CPaHeYqj.mjs";
16
- import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-B6tfCta1.mjs";
17
- import { o as resolveWorkspaceMetroPort } from "./start-7lpH7hmN.mjs";
1
+ import { g as process_identity_exports, i as withWorkspaceProcessLock, r as WorkspaceProcessCleanupError, t as getExecutor, x as ownership_claim_exports } from "./exec-DEoAhcze.mjs";
2
+ import { d as workspaceDir, m as workspaceLogsDir$1 } from "./paths-DQtTgsBf.mjs";
3
+ import { p as getProject } from "./config-DlrsduwG.mjs";
4
+ import { l as phaseLine } from "./command-output-gwpm28fu.mjs";
5
+ import { d as cancelledError, f as throwIfCancelled } from "./operation-exec-BW0em61G.mjs";
6
+ import { r as readWorkspaceState$1 } from "./workspace-state-U08dEzhG.mjs";
7
+ import { a as SETTING_SHAPE_REMEDY, at as webSettings, j as metroPortSetting } from "./settings-C7O8A6ZI.mjs";
8
+ import { b as isPackageResolvable, v as detectIsExpo } from "./project-wM_XFTvE.mjs";
9
+ import { s as readNdjsonGenerations$1 } from "./ndjson-CgE_o3Dl.mjs";
10
+ import { d as resolveProjectMetro } from "./metro-DiXtA3Ty.mjs";
11
+ import { f as webLogFile, m as webSupervisorLogFile, o as readWebRecord, s as updateWebRecord } from "./state--smjFSTL.mjs";
12
+ import { en as readMetroRecords } from "./budget-Cvwn54qV.mjs";
13
+ import { E as teardownBrowserHeld, h as resolveSupervisorTarget } from "./workspaces-CpANmBlq.mjs";
14
+ import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-DkEzOfzO.mjs";
15
+ import { n as sendToOwnedPage, t as liveWebRecord } from "./page-DBL2PiUU.mjs";
16
+ import { o as resolveWorkspaceMetroPort } from "./start-EojN4WFz.mjs";
18
17
  import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
19
- import { n as windowsLauncherArgs } from "./detached-entry-DFRyG1_o.mjs";
18
+ import { n as windowsLauncherArgs } from "./detached-entry-BwNEtIrP.mjs";
19
+ import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-Bbw689-6.mjs";
20
20
  import { randomUUID } from "node:crypto";
21
- import { mkdirSync, openSync } from "node:fs";
21
+ import { mkdirSync, openSync, statSync, watch } from "node:fs";
22
22
  import { ambientEnv } from "@stim-cli/core";
23
+ import { followLogs } from "@stim-cli/core/state";
23
24
  import chalk from "chalk";
24
25
  //#region src/web/launch.ts
25
26
  const PORT_PLACEHOLDER = /\{port:([^}]*)\}/g;
@@ -141,7 +142,7 @@ function webLaunchRemedy(verdict, { url, template, usesMetro, serve }) {
141
142
  //#endregion
142
143
  //#region src/web/runtime.ts
143
144
  const REGISTER_WAIT_MS = 3e4;
144
- const POLL_MS$1 = 250;
145
+ const POLL_MS = 250;
145
146
  function failure$1(code, message, remedy) {
146
147
  return {
147
148
  ok: false,
@@ -172,7 +173,7 @@ function startSupervisor(root, { url, port, config, launchId }) {
172
173
  if (!config.headless) args.push("--headed");
173
174
  if (config.viewport !== "desktop") args.push("--viewport", config.viewport);
174
175
  if (config.ignoreCertificateErrors) args.push("--ignore-certificate-errors");
175
- mkdirSync(workspaceLogsDir(root), { recursive: true });
176
+ mkdirSync(workspaceLogsDir$1(root), { recursive: true });
176
177
  const logFile = webSupervisorLogFile(root);
177
178
  if (process.platform === "win32") {
178
179
  const launcher = windowsLauncherArgs({
@@ -198,34 +199,67 @@ function startSupervisor(root, { url, port, config, launchId }) {
198
199
  stdio: [
199
200
  "ignore",
200
201
  fd,
201
- fd
202
+ fd,
203
+ "ipc"
202
204
  ],
203
205
  env: ambientEnv()
204
206
  });
205
207
  child.unref?.();
206
208
  return child;
207
209
  }
208
- async function waitForSupervisor(root, child, launchId) {
209
- let exited = false;
210
- if (process.platform !== "win32") child.once("exit", () => {
211
- exited = true;
212
- });
210
+ function waitForSupervisor(root, child, launchId, signal) {
213
211
  const deadline = Date.now() + REGISTER_WAIT_MS;
214
- while (Date.now() < deadline) {
215
- const record = readWebRecord(root);
216
- if (record?.launchId === launchId && record.targetId) return record;
217
- if (exited) return null;
218
- await cancellableSleep(POLL_MS$1);
219
- }
220
- return null;
212
+ return new Promise((resolve) => {
213
+ let settled = false;
214
+ let repairTimer;
215
+ const finish = (record) => {
216
+ if (settled) return;
217
+ settled = true;
218
+ clearTimeout(repairTimer);
219
+ clearTimeout(deadlineTimer);
220
+ child.removeListener("message", onMessage);
221
+ child.removeListener("exit", onExit);
222
+ child.removeListener("error", onExit);
223
+ child.removeListener("disconnect", check);
224
+ signal?.removeEventListener("abort", check);
225
+ resolve(record);
226
+ };
227
+ const check = () => {
228
+ if (settled) return;
229
+ if (Date.now() >= deadline) return finish(null);
230
+ const record = readWebRecord(root);
231
+ if (record?.launchId === launchId && (record.targetId || signal?.aborted)) return finish(record);
232
+ if (process.platform !== "win32" && (child.exitCode !== null || child.signalCode !== null)) finish(null);
233
+ };
234
+ const onExit = () => {
235
+ check();
236
+ finish(null);
237
+ };
238
+ const onMessage = (message) => {
239
+ if (message === "web-registered") check();
240
+ };
241
+ const repair = () => {
242
+ check();
243
+ if (!settled) repairTimer = setTimeout(repair, process.platform === "win32" ? POLL_MS : 1e3);
244
+ };
245
+ const deadlineTimer = setTimeout(() => finish(null), REGISTER_WAIT_MS);
246
+ child.on("message", onMessage);
247
+ if (process.platform !== "win32") child.once("exit", onExit);
248
+ child.once("error", onExit);
249
+ child.once("disconnect", check);
250
+ signal?.addEventListener("abort", check);
251
+ check();
252
+ if (!settled) repairTimer = setTimeout(repair, process.platform === "win32" ? POLL_MS : 1e3);
253
+ });
221
254
  }
222
- async function launchOwnedBrowser({ url, config }, { root, note }) {
223
- return withWorkspaceProcessLock(workspaceDir(root), "web", async () => {
255
+ async function launchOwnedBrowser({ url, config }, { root, note, signal }) {
256
+ return withWorkspaceProcessLock(workspaceDir(root), "web", async (claim) => {
257
+ throwIfCancelled(signal, "browser launch");
224
258
  const live = liveWebRecord(readWebRecord(root));
225
259
  if (live && sameLaunch(live, config)) {
226
260
  const since = Date.now();
227
261
  try {
228
- await sendToOwnedPage(live, "Page.navigate", { url });
262
+ await sendToOwnedPage(live, "Page.navigate", { url }, signal);
229
263
  updateWebRecord(root, live, { url });
230
264
  note(chalk.dim(phaseLine("device", `reusing the owned Chrome (pid ${live.chromeProcess?.pid})`)));
231
265
  return {
@@ -238,21 +272,53 @@ async function launchOwnedBrowser({ url, config }, { root, note }) {
238
272
  reused: true
239
273
  };
240
274
  } catch (error) {
275
+ throwIfCancelled(signal, "browser launch");
241
276
  note(chalk.dim(phaseLine("device", `restarting the owned Chrome: ${error.message}`)));
242
277
  }
243
278
  }
279
+ throwIfCancelled(signal, "browser launch");
244
280
  const stopped = await teardownBrowserHeld(root);
245
281
  if (stopped.status === "failed" || stopped.status === "skipped") return failure$1("STIM_WEB_BROWSER_HELD", `The previous owned Chrome could not be stopped: ${stopped.reason ?? "unknown reason"}.`, "Run `stim status` and `stim guide errors teardown`.");
282
+ throwIfCancelled(signal, "browser launch");
246
283
  const port = await reserveBrowserPort(root);
247
284
  const since = Date.now();
248
285
  note(chalk.dim(phaseLine("device", `starting ${config.headless ? "headless " : ""}Chrome on DevTools port ${port}`)));
249
286
  const launchId = randomUUID();
250
- const record = await waitForSupervisor(root, startSupervisor(root, {
251
- url,
252
- port,
253
- config,
254
- launchId
255
- }), launchId);
287
+ throwIfCancelled(signal, "browser launch");
288
+ (0, ownership_claim_exports.markClaimChildPending)(claim);
289
+ let child;
290
+ try {
291
+ child = startSupervisor(root, {
292
+ url,
293
+ port,
294
+ config,
295
+ launchId
296
+ });
297
+ } catch (error) {
298
+ (0, ownership_claim_exports.clearClaimChild)(claim);
299
+ throw error;
300
+ }
301
+ let record;
302
+ try {
303
+ const captured = child.pid === void 0 ? null : (0, process_identity_exports.captureProcessIdentity)(child.pid);
304
+ if (captured?.ok) try {
305
+ (0, ownership_claim_exports.setClaimChild)(claim, {
306
+ pid: child.pid,
307
+ processToken: captured.token
308
+ });
309
+ } catch {
310
+ throw new WorkspaceProcessCleanupError([claim], "The browser supervisor could not be recorded.", "Run `stim stop`.");
311
+ }
312
+ record = await waitForSupervisor(root, child, launchId, signal);
313
+ } finally {
314
+ if (child.connected) child.disconnect();
315
+ }
316
+ if (signal?.aborted) {
317
+ const cleanup = record ? await teardownBrowserHeld(root) : null;
318
+ if (!cleanup || cleanup.status === "failed" || cleanup.status === "skipped") throw new WorkspaceProcessCleanupError([claim], "The cancelled browser launch could not be stopped.", "Run `stim stop`.");
319
+ (0, ownership_claim_exports.clearClaimChild)(claim);
320
+ throwIfCancelled(signal, "browser launch");
321
+ }
256
322
  if (!record) return failure$1("STIM_WEB_LAUNCH_FAILED", "The owned Chrome did not start.", `Read ${webSupervisorLogFile(root)} and \`stim logs --errors\`, then run \`stim web\` again.`);
257
323
  return {
258
324
  ok: true,
@@ -262,12 +328,86 @@ async function launchOwnedBrowser({ url, config }, { root, note }) {
262
328
  };
263
329
  }, {
264
330
  external: true,
265
- ownerPurpose: "stim web"
331
+ ownerPurpose: "stim web",
332
+ signal
266
333
  });
267
334
  }
268
335
  //#endregion
269
336
  //#region src/integrations/browser-web.ts
270
- const POLL_MS = 250;
337
+ async function verifyLaunch(root, since, expectBundle, signal) {
338
+ signal?.throwIfAborted();
339
+ const startedAt = Date.now();
340
+ let stop;
341
+ let fileWatch;
342
+ let timer;
343
+ let queued;
344
+ let onAbort;
345
+ try {
346
+ return await new Promise((resolve, reject) => {
347
+ const schedule = () => {
348
+ queued ??= setImmediate(check);
349
+ };
350
+ const watchFile = () => {
351
+ try {
352
+ const file = webLogFile(root);
353
+ const stat = statSync(file);
354
+ if (fileWatch?.dev === stat.dev && fileWatch.ino === stat.ino) return;
355
+ fileWatch?.watcher.close();
356
+ fileWatch = void 0;
357
+ const watcher = watch(file, { persistent: false }, schedule);
358
+ fileWatch = {
359
+ watcher,
360
+ dev: stat.dev,
361
+ ino: stat.ino
362
+ };
363
+ const lost = () => {
364
+ if (fileWatch?.watcher === watcher) fileWatch = void 0;
365
+ watcher.close();
366
+ };
367
+ watcher.once("error", lost);
368
+ watcher.once("close", lost);
369
+ } catch {
370
+ fileWatch?.watcher.close();
371
+ fileWatch = void 0;
372
+ }
373
+ };
374
+ const check = () => {
375
+ clearImmediate(queued);
376
+ queued = void 0;
377
+ clearTimeout(timer);
378
+ try {
379
+ signal?.throwIfAborted();
380
+ watchFile();
381
+ const elapsedMs = Date.now() - startedAt;
382
+ const measured = webLaunchVerdict({
383
+ records: readNdjsonGenerations$1(webLogFile(root)),
384
+ metroRecords: expectBundle ? readMetroRecords(workspaceLogsDir$1(root)) : [],
385
+ since,
386
+ expectBundle,
387
+ elapsedMs
388
+ });
389
+ if (measured) resolve(measured);
390
+ else timer = setTimeout(check, Math.max(0, (elapsedMs < 2e4 ? VERIFY_WAIT_MS : LOADING_WAIT_MS) - elapsedMs));
391
+ } catch (error) {
392
+ reject(error);
393
+ }
394
+ };
395
+ stop = followLogs({
396
+ dir: workspaceLogsDir$1(root),
397
+ onRecord: schedule
398
+ });
399
+ onAbort = () => reject(cancelledError("wait"));
400
+ signal?.addEventListener("abort", onAbort, { once: true });
401
+ check();
402
+ });
403
+ } finally {
404
+ stop?.();
405
+ fileWatch?.watcher.close();
406
+ clearTimeout(timer);
407
+ clearImmediate(queued);
408
+ if (onAbort) signal?.removeEventListener("abort", onAbort);
409
+ }
410
+ }
271
411
  function failure(code, message, remedy) {
272
412
  return {
273
413
  ok: false,
@@ -297,7 +437,7 @@ function browserWebProject(root) {
297
437
  }
298
438
  const metro = usesMetro && metroPort !== null ? await resolveProjectMetro(metroPort, root) : null;
299
439
  const supervisor = resolveSupervisorTarget({
300
- state: readWorkspaceState(root)?.supervisor,
440
+ state: readWorkspaceState$1(root)?.supervisor,
301
441
  record: getProject(root)?.supervisor,
302
442
  reservedPort: metroPort
303
443
  });
@@ -338,19 +478,7 @@ function browserWebProject(root) {
338
478
  },
339
479
  launch: launchOwnedBrowser,
340
480
  async verify({ url, verification: { template, expectBundle, serve, foreign } }, { since }) {
341
- const startedAt = Date.now();
342
- let measured;
343
- for (;;) {
344
- measured = webLaunchVerdict({
345
- records: readNdjsonGenerations(webLogFile(root)),
346
- metroRecords: expectBundle ? readMetroRecords(workspaceLogsDir(root)) : [],
347
- since,
348
- expectBundle,
349
- elapsedMs: Date.now() - startedAt
350
- });
351
- if (measured) break;
352
- await cancellableSleep(POLL_MS);
353
- }
481
+ const measured = await verifyLaunch(root, since, expectBundle, context?.signal);
354
482
  const verdict = foreign ? {
355
483
  launched: "unverified",
356
484
  kind: "no-response",