stim 1.26.0 → 1.28.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 (172) hide show
  1. package/dist/{acquire-artifact-DVsvSwf7.mjs → acquire-artifact-CKByBnTD.mjs} +2 -2
  2. package/dist/{act-C-BqJEpu.mjs → act-8iswyfRa.mjs} +319 -126
  3. package/dist/{activity-Lnb_EoRY.mjs → activity-DRMg4_mD.mjs} +6 -6
  4. package/dist/{agent-device-usage-output-DbXy5tg8.mjs → agent-device-usage-output-tE90fDdo.mjs} +5 -5
  5. package/dist/{android-CiNQw3kq.mjs → android-CHmSU4B4.mjs} +101 -45
  6. package/dist/{android-DTAcRwBC.mjs → android-CsPs-7Mg.mjs} +23 -18
  7. package/dist/{android-B5P81yI-.mjs → android-D577ApKG.mjs} +37 -15
  8. package/dist/{android-CSbLRD53.mjs → android-YWCbmkVK.mjs} +5 -5
  9. package/dist/{android-cas-BTVhZ0Qs.mjs → android-cas-_aDifWW0.mjs} +4 -4
  10. package/dist/android-cas-compiler.mjs +1 -1
  11. package/dist/api.d.mts +14 -4
  12. package/dist/api.mjs +39 -29
  13. package/dist/{apk-signed-tail-B46U9hXc.mjs → apk-signed-tail-CQbwM0qO.mjs} +2 -2
  14. package/dist/{artifact-CsAP6AGK.mjs → artifact-DYtHjxsn.mjs} +19 -24
  15. package/dist/{artifact-BxREhAaV.mjs → artifact-bFkfD3vf.mjs} +18 -23
  16. package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
  17. package/dist/auto-placement-BVqs8AJi.mjs +350 -0
  18. package/dist/{browser-web-rYPyqhTf.mjs → browser-web-BUaLcafY.mjs} +16 -16
  19. package/dist/{build-DPhApsjV.mjs → build-cQURy_KW.mjs} +35 -31
  20. package/dist/{build-cache-DrXNCy3T.mjs → build-cache-CZULpXVl.mjs} +43 -21
  21. package/dist/{build-plan-DrMMdayj.mjs → build-plan-CxoYfxsc.mjs} +7 -6
  22. package/dist/{cache-manifest-BEZ9Bpl1.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/{budget-k2mZGvvk.mjs → ccache-Bm_A1xX9.mjs} +562 -1604
  25. package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
  26. package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
  27. package/dist/{cli-BBKFGOFl.mjs → cli-CpbaLDa7.mjs} +24 -23
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-D9CaRks-.mjs → client-YxCer6ab.mjs} +84 -65
  30. package/dist/collector-run.d.mts +10 -9
  31. package/dist/collector-run.mjs +42 -27
  32. package/dist/{command-output-BF5AR2dL.mjs → command-output-C8R1KIvi.mjs} +1 -1
  33. package/dist/{config-BktkY_zC.mjs → config-Cn94Jc0g.mjs} +23 -4
  34. package/dist/{dependencies-Dw6wfQdv.mjs → dependencies-DKeMzwXY.mjs} +108 -60
  35. package/dist/{dependency-state-DFB41vfr.mjs → dependency-state-CojA2o0t.mjs} +14 -7
  36. package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
  37. package/dist/{dev-client-DXR_tPVY.mjs → dev-client-D-BW5uiq.mjs} +2 -2
  38. package/dist/{device-BK-zwyd_.mjs → device-CgXfbcz5.mjs} +25 -24
  39. package/dist/{device-capacity-DCSvUF0l.mjs → device-capacity-Cd8lMSn3.mjs} +175 -22
  40. package/dist/{device-BcYeHSFu.mjs → device-eeK95Lir.mjs} +16 -16
  41. package/dist/device-host-worker.mjs +22 -20
  42. package/dist/{device-ios-BLGfXQeK.mjs → device-ios-Cc9ulihb.mjs} +251 -23
  43. package/dist/{device-lease-run-BmvIl7bI.mjs → device-lease-run-Mtzp4THX.mjs} +5 -5
  44. package/dist/{device-pool-Dluix4H3.mjs → device-pool-eRz6DtCg.mjs} +3 -3
  45. package/dist/{doctor-Bhg1ii70.mjs → doctor-Bz_ouYAW.mjs} +28 -16
  46. package/dist/{doctor-Cp-BhzTS.mjs → doctor-C2QyhejJ.mjs} +1 -1
  47. package/dist/{doctor-fingerprint-D3a04Mhu.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +1 -1
  48. package/dist/doctor-fingerprint.mjs +1 -1
  49. package/dist/{doctor-watchman-BStK05nt.mjs → doctor-watchman-BTW82PDC.mjs} +5 -5
  50. package/dist/{doctor-OnwP94ne.mjs → doctor-xf7ht-5n.mjs} +76 -32
  51. package/dist/{eas-build-Dsj93iM9.mjs → eas-build-Dm6q68QY.mjs} +4 -4
  52. package/dist/eas-fallback-DajNpxf-.mjs +87 -0
  53. package/dist/{eas-session-ledger-B5vygTiD.mjs → eas-session-ledger-CBFo_Uo1.mjs} +37 -8
  54. package/dist/{error-diagnostics-BOOm9Db7.mjs → error-diagnostics-D1QfyJzQ.mjs} +51 -25
  55. package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
  56. package/dist/{gc-ldgr-hXU.mjs → gc-DM5oMm-J.mjs} +161 -45
  57. package/dist/{gc-C_79zvz4.mjs → gc-PLFwb0k4.mjs} +2 -2
  58. package/dist/{guide-D7K0X6KG.mjs → guide-C4I46XAk.mjs} +674 -213
  59. package/dist/{hosted-android-Bk54ej6n.mjs → hosted-android-DlaKLbW0.mjs} +6 -7
  60. package/dist/{hosted-client-fHO8yqzc.mjs → hosted-client-DDRm9hPJ.mjs} +51 -20
  61. package/dist/{hosted-logs-BfbmDM4M.mjs → hosted-logs-bSebOKbz.mjs} +8 -8
  62. package/dist/{hosted-logs-sync-B0pvmOk-.mjs → hosted-logs-sync-B0c53W_c.mjs} +5 -5
  63. package/dist/{hosted-macos-CPl0OZ9h.mjs → hosted-macos-B7-8Pv4H.mjs} +6 -6
  64. package/dist/{hosted-native-CpDB3-PO.mjs → hosted-native-CDe33CSr.mjs} +22 -18
  65. package/dist/{idle-shutdown-FfxL1KdG.mjs → idle-shutdown-CQ0QwU9J.mjs} +7 -8
  66. package/dist/{ios-WxpDJ5T1.mjs → ios-B1DYuOjh.mjs} +27 -11
  67. package/dist/{ios-B7-lToDu.mjs → ios-B1HvafEG.mjs} +8 -8
  68. package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
  69. package/dist/{ios-device-CsyryvpT.mjs → ios-device-B4elVFKi.mjs} +3 -3
  70. package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
  71. package/dist/{ios-project-Ty5pHl9O.mjs → ios-project-CR4mZ7CH.mjs} +22 -9
  72. package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
  73. package/dist/{ios-state-Cw7-WQf2.mjs → ios-state-BPHqMDdZ.mjs} +1 -1
  74. package/dist/{ios-ftxdQbJS.mjs → ios-tg4tp3q1.mjs} +94 -37
  75. package/dist/{js-swap-BMhXYVDS.mjs → js-swap-CVpSW1fn.mjs} +8 -7
  76. package/dist/{launch-DOp8RjDz.mjs → launch-DoySmhjz.mjs} +42 -38
  77. package/dist/lightened-DFAJgfIk.mjs +171 -0
  78. package/dist/{logs-s1dRIG1E.mjs → logs-BGsW7iPe.mjs} +46 -21
  79. package/dist/{logs-dQDki6Tt.mjs → logs-DI5ILkYB.mjs} +7 -7
  80. package/dist/{macos-DBBPNnIA.mjs → macos-Bo9st9Di.mjs} +73 -38
  81. package/dist/{macos-B0VEV3Gf.mjs → macos-C12RMJQF.mjs} +1 -1
  82. package/dist/macos-run.mjs +1 -1
  83. package/dist/maintenance-run.mjs +7 -7
  84. package/dist/{metro-CjC10t6E.mjs → metro-BnhXV2Mj.mjs} +4 -4
  85. package/dist/{metro-gateway-B6_PgD0L.mjs → metro-request-DXyKjVDF.mjs} +26 -47
  86. package/dist/{named-ports-BG0j1X4g.mjs → named-ports-Phoi2POD.mjs} +3 -3
  87. package/dist/{native-android-CL2NGiik.mjs → native-android-vxgtLD7w.mjs} +17 -18
  88. package/dist/{native-gradle-artifact-inputs-btSUulme.mjs → native-gradle-artifact-inputs-BN96IVw8.mjs} +5 -5
  89. package/dist/{native-runtime-Dq3RBcON.mjs → native-runtime-DG4Rodzj.mjs} +9 -8
  90. package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
  91. package/dist/{native-xcode-inputs-BW7H8JGu.mjs → native-xcode-inputs-BKarCoKg.mjs} +3 -3
  92. package/dist/{native-xcode-ios-CBXJAxfC.mjs → native-xcode-ios-8A-efGa5.mjs} +17 -17
  93. package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
  94. package/dist/offload-worker.mjs +23 -24
  95. package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
  96. package/dist/{ownership-BjYvMNX_.mjs → ownership-DJCq48IJ.mjs} +3 -3
  97. package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
  98. package/dist/{phone-reverses-lmj6kcPm.mjs → phone-reverses-BzTa8g1F.mjs} +18 -4
  99. package/dist/{placement-log-DIFPQAXp.mjs → placement-log-Cvhta5ib.mjs} +3 -3
  100. package/dist/{plan-placement-IiiSQhtz.mjs → plan-placement-WkZdccuN.mjs} +36 -10
  101. package/dist/{ports-C2_w1Z0Z.mjs → ports-UV4mJgyC.mjs} +3 -3
  102. package/dist/{prebuild-gmouvmJZ.mjs → prebuild-k8d_tqOq.mjs} +16 -17
  103. package/dist/{project-BUu6Is4k.mjs → project-Sui52ywT.mjs} +17 -17
  104. package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
  105. package/dist/pull-requests.mjs +1 -1
  106. package/dist/{react-native-android-Cgg99REN.mjs → react-native-android-DANlGGQf.mjs} +32 -26
  107. package/dist/{react-native-build-oNwqF5Wb.mjs → react-native-build-jUHnIfZ9.mjs} +9 -9
  108. package/dist/{react-native-doctor-BhA3KUte.mjs → react-native-doctor-DCWRjS7K.mjs} +6 -6
  109. package/dist/{react-native-ios-B-nf4rjN.mjs → react-native-ios-BwMsFMXi.mjs} +23 -17
  110. package/dist/{recordings-BldzVKq0.mjs → recordings-iy0mkm7b.mjs} +1 -1
  111. package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
  112. package/dist/{reload-C9OduiNc.mjs → reload-Bj7QyuDy.mjs} +1 -1
  113. package/dist/{reload-CCR7KC_l.mjs → reload-c_uEyc_X.mjs} +16 -16
  114. package/dist/{remote-C8S7FlPF.mjs → remote-DFlpAqdV.mjs} +23 -10
  115. package/dist/{result-7F5hEwQJ.mjs → result-BIcXREyC.mjs} +32 -21
  116. package/dist/{run-BqB0v3pt.mjs → run-y2HwyNvg.mjs} +3 -3
  117. package/dist/{selection-BNPBZ6T5.mjs → selection-CXgM_VK_.mjs} +37 -29
  118. package/dist/{server-bare-A75rDIdD.mjs → server-bare-2N4vSRZG.mjs} +2 -2
  119. package/dist/{server-command-CssKFOD7.mjs → server-command-qneHPcRI.mjs} +6 -6
  120. package/dist/{server-expo-eQfOdydb.mjs → server-expo-Ccm9zB0o.mjs} +4 -4
  121. package/dist/server-expo-WulkyAwT.mjs +2 -0
  122. package/dist/{settings-CosW5X-S.mjs → settings-CY5JZlNN.mjs} +375 -62
  123. package/dist/{settings-OaGQF-ri.mjs → settings-Cfd_Q6ys.mjs} +24 -3
  124. package/dist/settings-payload-DwQiEMCn.mjs +257 -0
  125. package/dist/settings-write-CJpjkeAd.mjs +185 -0
  126. package/dist/settings.schema.json +51 -33
  127. package/dist/{simslim-Bax1qcxu.mjs → simslim-DCQwzoPy.mjs} +2 -2
  128. package/dist/{slot-launch-CYCEhfBY.mjs → slot-launch-BpmanOnk.mjs} +6 -6
  129. package/dist/{stage-jKQ7CP_B.mjs → stage-CmugrSG5.mjs} +2 -2
  130. package/dist/{start-C_wefNKB.mjs → start-CHH3zgIU.mjs} +1 -1
  131. package/dist/{start-_BdJ32cZ.mjs → start-DYLk6GXn.mjs} +27 -22
  132. package/dist/{state-C1i2nMOP.mjs → state-B2QJbDwz.mjs} +4 -4
  133. package/dist/{state-C4OdpOTF.mjs → state-BXC1Lfxw.mjs} +2 -2
  134. package/dist/{stats-tEpEEH-u.mjs → stats-DxKqhcGp.mjs} +5 -5
  135. package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
  136. package/dist/{status-CRXz-Gtj.mjs → status-7ULDEJ1e.mjs} +1 -1
  137. package/dist/{status-DQrqodLj.mjs → status-BHCkOZga.mjs} +51 -28
  138. package/dist/{status-B9M7x4CZ.mjs → status-D_Ljc89p.mjs} +1 -1
  139. package/dist/{status-watch-B5wDIH_o.mjs → status-watch-BmsPqYSU.mjs} +18 -7
  140. package/dist/status-worker.mjs +1 -1
  141. package/dist/{stim-desktop-6Dqp-gjX.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
  142. package/dist/{stop-DRqQVqDJ.mjs → stop-D-dGE9gh.mjs} +21 -20
  143. package/dist/{stop-ySNQHXMG.mjs → stop-DQvE-P76.mjs} +10 -6
  144. package/dist/{stop-CmdNhGlC.mjs → stop-b2pouxAO.mjs} +2 -2
  145. package/dist/supervisor-run.mjs +237 -63
  146. package/dist/{support-BGSCBoib.mjs → support-04IhBUTT.mjs} +6 -6
  147. package/dist/{support-CVOCp0Ft.mjs → support-BtlJKjyQ.mjs} +12 -11
  148. package/dist/{swiftpm-artifact-inputs-CfUzt_0Z.mjs → swiftpm-artifact-inputs-Cj2UpmPN.mjs} +4 -4
  149. package/dist/{swiftpm-macos-x6HPpl_2.mjs → swiftpm-macos-BhF2stxY.mjs} +11 -12
  150. package/dist/{toolchain-J4J8MrAr.mjs → toolchain-mLA_km-b.mjs} +321 -15
  151. package/dist/{toolchain-DoavrvIA.mjs → toolchain-qktiV8xc.mjs} +1 -1
  152. package/dist/{trigger-KVaWWNyn.mjs → trigger-DMou-X7j.mjs} +2 -2
  153. package/dist/trigger-qp2ji5wE.mjs +2 -0
  154. package/dist/{warm-progress-DvhTX_eu.mjs → warm-progress-B0Vpuvpl.mjs} +731 -727
  155. package/dist/{web-Bihbf7-u.mjs → web-BYmK0TjL.mjs} +9 -9
  156. package/dist/web-CrVLVQZY.mjs +2 -0
  157. package/dist/web-run.mjs +9 -9
  158. package/dist/windows-report.mjs +1 -1
  159. package/dist/{workspace-state-pUg3_RRA.mjs → workspace-state-kIZrdlSg.mjs} +3 -3
  160. package/dist/{workspaces-g2lhdBXF.mjs → workspaces-CmOcceDN.mjs} +1879 -74
  161. package/dist/{worktree-BKuklFh_.mjs → worktree-2dk5edza.mjs} +933 -534
  162. package/dist/worktree-nliAoHxB.mjs +2 -0
  163. package/package.json +7 -7
  164. package/dist/ccache-Bx5TbxwG.mjs +0 -143
  165. package/dist/eas-fallback-FwkeqqGi.mjs +0 -381
  166. package/dist/hosted-ios-D55QhYaD.mjs +0 -15
  167. package/dist/native-run-BfIDFKLH.mjs +0 -275
  168. package/dist/server-expo-wvcj5tiZ.mjs +0 -2
  169. package/dist/settings-write-QjYfSrjF.mjs +0 -360
  170. package/dist/trigger-DzJu208Q.mjs +0 -2
  171. package/dist/web-BFLueSh-.mjs +0 -2
  172. package/dist/worktree-Bm4cb-nU.mjs +0 -2
@@ -1,4 +1,4 @@
1
- import { c as throwIfCancelled, s as cancelledError } from "./exec-VFRpu1iA.mjs";
1
+ import { c as throwIfCancelled, s as cancelledError } from "./exec-aULwtNly.mjs";
2
2
  import { WebSocket } from "ws";
3
3
  //#region src/web/cdp.ts
4
4
  const COMMAND_TIMEOUT_MS = 15e3;
@@ -1,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-VFRpu1iA.mjs";
1
+ import { t as getExecutor } from "./exec-aULwtNly.mjs";
2
2
  import { existsSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
@@ -1,27 +1,27 @@
1
- import { E as debugLog } from "./exec-VFRpu1iA.mjs";
2
- import { y as refuseRelativeStimPaths } from "./config-BktkY_zC.mjs";
1
+ import { E as debugLog } from "./exec-aULwtNly.mjs";
2
+ import { y as refuseRelativeStimPaths } from "./config-Cn94Jc0g.mjs";
3
3
  import { readFileSync } from "node:fs";
4
- import { runId } from "@stim-cli/core/state";
4
+ import { runId, trace } from "@stim-cli/core/state";
5
5
  import { Command } from "commander";
6
6
  //#region bin/cli.ts
7
7
  const commands = /* @__PURE__ */ new Map([
8
- ["doctor", () => import("./doctor-Cp-BhzTS.mjs")],
9
- ["worktree", () => import("./worktree-Bm4cb-nU.mjs")],
10
- ["start", () => import("./start-C_wefNKB.mjs")],
11
- ["ports", () => import("./ports-C2_w1Z0Z.mjs")],
12
- ["stop", () => import("./stop-CmdNhGlC.mjs")],
13
- ["ios", () => import("./ios-B7-lToDu.mjs")],
14
- ["android", () => import("./android-CSbLRD53.mjs")],
15
- ["web", () => import("./web-BFLueSh-.mjs")],
16
- ["macos", () => import("./macos-B0VEV3Gf.mjs")],
17
- ["reload", () => import("./reload-C9OduiNc.mjs")],
18
- ["device", () => import("./device-BcYeHSFu.mjs")],
19
- ["logs", () => import("./logs-s1dRIG1E.mjs")],
20
- ["settings", () => import("./settings-OaGQF-ri.mjs")],
21
- ["status", () => import("./status-B9M7x4CZ.mjs")],
22
- ["stats", () => import("./stats-tEpEEH-u.mjs")],
23
- ["gc", () => import("./gc-C_79zvz4.mjs")],
24
- ["guide", () => import("./guide-D7K0X6KG.mjs")]
8
+ ["doctor", () => import("./doctor-C2QyhejJ.mjs")],
9
+ ["worktree", () => import("./worktree-nliAoHxB.mjs")],
10
+ ["start", () => import("./start-CHH3zgIU.mjs")],
11
+ ["ports", () => import("./ports-UV4mJgyC.mjs")],
12
+ ["stop", () => import("./stop-b2pouxAO.mjs")],
13
+ ["ios", () => import("./ios-B1HvafEG.mjs")],
14
+ ["android", () => import("./android-YWCbmkVK.mjs")],
15
+ ["web", () => import("./web-CrVLVQZY.mjs")],
16
+ ["macos", () => import("./macos-C12RMJQF.mjs")],
17
+ ["reload", () => import("./reload-Bj7QyuDy.mjs")],
18
+ ["device", () => import("./device-eeK95Lir.mjs")],
19
+ ["logs", () => import("./logs-BGsW7iPe.mjs")],
20
+ ["settings", () => import("./settings-Cfd_Q6ys.mjs")],
21
+ ["status", () => import("./status-D_Ljc89p.mjs")],
22
+ ["stats", () => import("./stats-DxKqhcGp.mjs")],
23
+ ["gc", () => import("./gc-PLFwb0k4.mjs")],
24
+ ["guide", () => import("./guide-C4I46XAk.mjs")]
25
25
  ]);
26
26
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
27
27
  const program = new Command();
@@ -37,9 +37,10 @@ try {
37
37
  for (const module of modules) module.default(program, pkg.version);
38
38
  }
39
39
  program.hook("preAction", async (_command, action) => {
40
+ const path = [];
41
+ for (let each = action; each?.parent; each = each.parent) path.unshift(each.name());
42
+ trace.command(`stim ${path.join(" ")}`, { version: pkg.version });
40
43
  if (debugLog.enabled()) {
41
- const path = [];
42
- for (let each = action; each?.parent; each = each.parent) path.unshift(each.name());
43
44
  const started = Date.now();
44
45
  debugLog.log("run_start", {
45
46
  version: pkg.version,
@@ -52,7 +53,7 @@ try {
52
53
  }));
53
54
  }
54
55
  try {
55
- const { triggerMaintenance } = await import("./trigger-DzJu208Q.mjs");
56
+ const { triggerMaintenance } = await import("./trigger-qp2ji5wE.mjs");
56
57
  triggerMaintenance(action.name());
57
58
  } catch {}
58
59
  });
package/dist/cli.mjs CHANGED
@@ -4,6 +4,6 @@ const encode = (version) => version.split(".", 3).reduce((sum, part) => sum * 1e
4
4
  if (encode(process.versions.node) < encode("22.12.0")) {
5
5
  process.stderr.write(`STIM_NODE_UNSUPPORTED: Stim needs Node 22.12.0 or later; this is Node ${process.versions.node} at ${process.execPath}. To run Stim where a project pins an older Node, see https://stim.appandflow.com/docs/requirements#older-node-pins\n`);
6
6
  process.exitCode = 1;
7
- } else import("./cli-BBKFGOFl.mjs");
7
+ } else import("./cli-CpbaLDa7.mjs");
8
8
  //#endregion
9
9
  export {};
@@ -1,21 +1,19 @@
1
- import { C as reportSignal, E as debugLog, b as operationState, c as throwIfCancelled, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { _ as loadConfig$1, at as resolveEndpoint, et as openAuthenticated, ot as sayHello } from "./config-BktkY_zC.mjs";
3
- import { o as git, s as gitAsync } from "./operation-exec-CUZifp6Z.mjs";
4
- import { Dr as discoverCaches, E as maintenanceLogger, ct as planCacheEmptying, nt as emptyCaches } from "./budget-k2mZGvvk.mjs";
1
+ import { C as reportSignal, E as debugLog, b as operationState, c as throwIfCancelled, t as getExecutor } from "./exec-aULwtNly.mjs";
2
+ import { _ as loadConfig$1, ot as resolveEndpoint, st as sayHello, tt as openAuthenticated } from "./config-Cn94Jc0g.mjs";
3
+ import { o as git, s as gitAsync } from "./operation-exec-Dp4FuIGR.mjs";
4
+ import { G as planCacheEmptying, R as maintenanceLogger, n as CCACHE_UNAVAILABLE, t as CCACHE_NOT_RUN, ur as discoverCaches, z as emptyCaches } from "./ccache-Bm_A1xX9.mjs";
5
5
  import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
6
- import { d as runCancellationSignal } from "./native-run-BfIDFKLH.mjs";
6
+ import { A as COMPILATION_CACHE_UNAVAILABLE, E as readRubyVersion, a as cocoapodsDifference, k as COMPILATION_CACHE_NOT_RUN, ot as runCancellationSignal, s as iosToolchainAsync, v as toolchainMismatches, x as workerToolchain, y as toolchainNotes } from "./toolchain-mLA_km-b.mjs";
7
7
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
8
- import { n as CCACHE_UNAVAILABLE, t as CCACHE_NOT_RUN } from "./ccache-Bx5TbxwG.mjs";
9
- import { A as COMPILATION_CACHE_UNAVAILABLE, E as readRubyVersion, a as cocoapodsDifference, k as COMPILATION_CACHE_NOT_RUN, s as iosToolchainAsync, v as toolchainMismatches, x as workerToolchain, y as toolchainNotes } from "./toolchain-J4J8MrAr.mjs";
10
- import { f as pairedMachines, i as namedBuildMachine, t as OffloadRefusal, u as workerFailureReason } from "./selection-BNPBZ6T5.mjs";
8
+ import { f as workerFailureReason, m as pairedMachines, o as namedBuildMachine, t as OffloadRefusal } from "./selection-CXgM_VK_.mjs";
11
9
  import { n as fingerprintNativeInputs, r as manifestDigest } from "./native-inputs-TRTTTRxt.mjs";
12
- import { a as sourceManifest, i as nativeTransferManifest, n as gitVisiblePaths, r as nativeFileDigest, t as checkNativeTransferMembership } from "./native-source-D-4Dh4JU.mjs";
10
+ import { a as sourceManifest, i as nativeTransferManifest, n as gitVisiblePaths, r as nativeFileDigest, t as checkNativeTransferMembership } from "./native-source-D1AzWiuP.mjs";
13
11
  import { createHash, webcrypto } from "node:crypto";
14
12
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, writeSync } from "node:fs";
15
13
  import { isDeepStrictEqual } from "node:util";
16
14
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
17
15
  import { ambientContext, dependencyLockfile, reactNativeArtifactIdentity, reactNativeArtifactQuery, swiftpmArtifactQuery } from "@stim-cli/core";
18
- import { OFFLOAD_MODES, automaticMachineEnabled, isJsonObject, maintenanceDir, requireAutomaticMachine, runId, saturation } from "@stim-cli/core/state";
16
+ import { automaticMachineEnabled, isJsonObject, maintenanceDir, mayRunHere, placementWord, requireAutomaticMachine, runId, saturation } from "@stim-cli/core/state";
19
17
  import { WebSocket } from "ws";
20
18
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
21
19
  import { access, lstat, readFile, readlink, realpath } from "node:fs/promises";
@@ -393,16 +391,12 @@ const PAGE_BYTES = 49152;
393
391
  const CHUNK_BYTES = 61440;
394
392
  const MAX_BUFFERED = 8388608;
395
393
  const DIGEST_BYTES = 32;
396
- function offloadMode(env = ambientContext()?.env ?? process.env) {
397
- const raw = env.STIM_REMOTE_BUILD_MODE || loadConfig$1()?.remote?.buildMode;
398
- return OFFLOAD_MODES.includes(raw) ? raw : "auto";
399
- }
400
394
  function buildPlacementCandidates(selected) {
401
395
  const config = loadConfig$1();
396
+ const word = placementWord(selected);
402
397
  return {
403
- localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local", config),
404
- mode: selected === "local" ? "off" : offloadMode(),
405
- machines: selected === "local" ? [] : namedBuildMachine(selected) ? pairedMachines([selected]).slice(0, 1) : pairedMachines().filter((entry) => automaticMachineEnabled("build", entry.machine, config))
398
+ localEnabled: word === null || word === "local" || mayRunHere(word) && automaticMachineEnabled("build", "local", config),
399
+ machines: word === "local" ? [] : word === null ? pairedMachines([selected]).slice(0, 1) : pairedMachines().filter((entry) => automaticMachineEnabled("build", entry.machine, config))
406
400
  };
407
401
  }
408
402
  function remotePhaseText(name, msg, machine) {
@@ -426,10 +420,12 @@ function placementLoad(choice) {
426
420
  /**
427
421
  * Whether a build may go to a remote machine at all, before any machine is asked. `auto` keeps the build here while
428
422
  * this machine has a free `concurrency.maxBuilds` slot and its load per core is under `server.maxLoadPerCore`.
429
- * A named selection ignores local capacity and mode, and refuses an unsupported build or missing pairing.
423
+ * `remote` always tries the remote machines first and `remote-only` never builds here. A named selection ignores
424
+ * local capacity, and refuses an unsupported build or missing pairing.
430
425
  */
431
- function offloadPlacement({ mode, machines, here, unsupported, localEnabled = true, selected = "auto" }) {
432
- if (namedBuildMachine(selected)) {
426
+ function offloadPlacement({ machines, here, unsupported, localEnabled = true, selected = "auto" }) {
427
+ const word = placementWord(selected);
428
+ if (word === null) {
433
429
  if (unsupported) throw new OffloadRefusal(selected, `${unsupported}, so a named remote machine cannot take it`);
434
430
  if (machines === 0) throw new OffloadRefusal(selected, "no remote machine is paired");
435
431
  return {
@@ -438,25 +434,21 @@ function offloadPlacement({ mode, machines, here, unsupported, localEnabled = tr
438
434
  reason: `selected with --remote-build ${selected}`
439
435
  };
440
436
  }
441
- if (selected === "local") return {
437
+ if (word === "local") return {
442
438
  offload: false,
443
439
  code: "local-selected",
444
440
  reason: "--remote-build local"
445
441
  };
446
- if (!localEnabled) {
447
- const reason = mode === "off" ? "remote.buildMode is off" : unsupported ?? (machines === 0 ? "no enabled remote machine is paired" : null);
448
- if (reason) throw new OffloadRefusal("auto", `${reason}; local is disabled in remote.buildPoolDisabled`);
442
+ if (!localEnabled || !mayRunHere(word)) {
443
+ const why = word === "remote-only" ? "remote-only never builds here" : "local is disabled in remote.buildPoolDisabled";
444
+ const reason = unsupported ?? (machines === 0 ? "no enabled remote machine is paired" : null);
445
+ if (reason) throw new OffloadRefusal(selected, `${reason}; ${why}`);
449
446
  return {
450
447
  offload: true,
451
- code: "local-disabled",
452
- reason: "local is disabled in remote.buildPoolDisabled"
448
+ code: word === "remote-only" ? "remote-only" : "local-disabled",
449
+ reason: why
453
450
  };
454
451
  }
455
- if (mode === "off") return {
456
- offload: false,
457
- code: "mode-off",
458
- reason: "remote.buildMode is off"
459
- };
460
452
  if (machines === 0) return {
461
453
  offload: false,
462
454
  code: "no-remote-mac",
@@ -467,10 +459,10 @@ function offloadPlacement({ mode, machines, here, unsupported, localEnabled = tr
467
459
  code: "unsupported",
468
460
  reason: unsupported
469
461
  };
470
- if (mode === "force") return {
462
+ if (word === "remote") return {
471
463
  offload: true,
472
- code: "forced",
473
- reason: "remote.buildMode is force"
464
+ code: "remote",
465
+ reason: "remote machines come first"
474
466
  };
475
467
  const busy = saturation(here);
476
468
  return busy ? {
@@ -521,14 +513,15 @@ function offerProblems(offer, target, named = false) {
521
513
  return problems;
522
514
  }
523
515
  /**
524
- * The asked machines that can take the build, best first, and one reason per machine that cannot. A machine with any
525
- * `offerProblems` never takes it. In `auto`, a machine must also be expected to build faster than this machine: while
526
- * every local build slot is busy any machine that accepts will do, otherwise its load per core must be lower than
527
- * this machine's. A named selection considers only that machine and skips this local-capacity gating.
528
- * A machine that reports no load (a stim-server older than capacity) takes an `auto` build only while
529
- * every local slot is busy. Matching dependency installations rank first, then load.
516
+ * The asked machines that can take the build, in the order they should be tried, and one reason per machine that
517
+ * cannot. A machine with any `offerProblems` never takes it, nor does one whose load per core is at or above its own
518
+ * `server.maxLoadPerCore` (this machine's setting stands in for a stim-server that does not report it). Machines that
519
+ * can take it keep the order of `remote.machines`, so the first one with a free slot under its load threshold gets
520
+ * the build; only a machine that already holds the exact completed artifact goes ahead of that order. A named
521
+ * selection considers only that machine. In `auto` a machine that reports no load (a stim-server older than capacity)
522
+ * takes the build only while every local slot is busy.
530
523
  */
531
- function pickOffer({ mode, here, offers, target, localEnabled = true, selected = "auto", artifact, cacheOnly = false }) {
524
+ function pickOffer({ here, offers, target, localEnabled = true, selected = "auto", artifact, cacheOnly = false }) {
532
525
  const slotsFull = here.maxBuilds > 0 && here.builds >= here.maxBuilds;
533
526
  const reasons = [];
534
527
  const candidates = [];
@@ -548,8 +541,7 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
548
541
  if (matchingArtifact(offer, artifact) && (artifact !== "swiftpm" || toolchainMismatches(target, offer.toolchain).length === 0)) {
549
542
  ranked.push({
550
543
  index,
551
- score: Number.POSITIVE_INFINITY,
552
- load: 0
544
+ cached: true
553
545
  });
554
546
  candidates.push({
555
547
  machine,
@@ -561,16 +553,13 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
561
553
  if (cacheOnly) return skip(machine, "artifact-miss", "no matching completed artifact");
562
554
  const problems = offerProblems(offer, target, namedBuildMachine(selected));
563
555
  if (problems.length) return skip(machine, problemCode(problems[0]), problems.map((problem) => problem.reason).join("; "), problems.map((problem) => problem.code));
564
- const load = offer.capacity.loadPerCore;
565
- if (selected === "auto" && localEnabled && mode === "auto" && !slotsFull) {
566
- if (typeof load !== "number") return skip(machine, "load", "capacity unknown (older stim-server) while this machine has a free slot");
567
- if (load >= here.loadPerCore) return skip(machine, "load", `no less loaded (load ${load}/core there, ${here.loadPerCore}/core here)`);
568
- }
569
- const score = Number(offer.warm.dependencies);
556
+ const { loadPerCore: load, maxLoadPerCore } = offer.capacity;
557
+ const ceiling = maxLoadPerCore ?? here.maxLoadPerCore;
558
+ if (typeof load === "number" && !namedBuildMachine(selected) && load >= ceiling) return skip(machine, "load", `saturated: load ${load}/core there, at or above ${ceiling}/core`);
559
+ if (selected === "auto" && localEnabled && !slotsFull && typeof load !== "number") return skip(machine, "load", "capacity unknown (older stim-server) while this machine has a free slot");
570
560
  ranked.push({
571
561
  index,
572
- score,
573
- load: typeof load === "number" ? load : Number.POSITIVE_INFINITY
562
+ cached: false
574
563
  });
575
564
  const notes = toolchainNotes(target, offer.toolchain).map((each) => each.reason);
576
565
  candidates.push({
@@ -579,7 +568,7 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
579
568
  msg: [typeof load === "number" ? `can take the build (load ${load}/core there)` : "can take the build", ...notes].join("; ")
580
569
  });
581
570
  });
582
- ranked.sort((a, b) => b.score - a.score || a.load - b.load);
571
+ ranked.sort((a, b) => Number(b.cached) - Number(a.cached));
583
572
  return {
584
573
  order: ranked.map((each) => each.index),
585
574
  reasons,
@@ -610,7 +599,10 @@ var BuildConnection = class BuildConnection {
610
599
  writeWaiters = /* @__PURE__ */ new Set();
611
600
  progress = null;
612
601
  binary = null;
602
+ event = null;
603
+ dropped = null;
613
604
  closed = null;
605
+ lastWrite = Promise.resolve();
614
606
  heard = Date.now();
615
607
  watched = false;
616
608
  ended = false;
@@ -642,6 +634,7 @@ var BuildConnection = class BuildConnection {
642
634
  }
643
635
  if (!isJsonObject(message)) return;
644
636
  if (message.event === "build.progress") return this.progress?.(message);
637
+ if (typeof message.event === "string") return this.event?.(message);
645
638
  const resolve = typeof message.id === "number" ? this.pending.get(message.id) : void 0;
646
639
  if (resolve) {
647
640
  this.pending.delete(message.id);
@@ -666,6 +659,7 @@ var BuildConnection = class BuildConnection {
666
659
  message: this.closed
667
660
  }
668
661
  });
662
+ this.dropped?.(code);
669
663
  });
670
664
  socket.on("error", () => {});
671
665
  }
@@ -782,8 +776,11 @@ var BuildConnection = class BuildConnection {
782
776
  if (this.closed) return;
783
777
  let completed = false;
784
778
  let resume;
779
+ let written;
780
+ this.lastWrite = new Promise((resolve) => written = resolve);
785
781
  this.socket.send(frame, { binary: true }, () => {
786
782
  completed = true;
783
+ written?.();
787
784
  resume?.();
788
785
  });
789
786
  if (completed || this.closed || this.socket.bufferedAmount <= MAX_BUFFERED) return;
@@ -796,12 +793,31 @@ var BuildConnection = class BuildConnection {
796
793
  this.writeWaiters.add(wake);
797
794
  });
798
795
  }
796
+ /** Resolves once the last binary frame left this process, or at once when the connection has ended. */
797
+ flushed() {
798
+ return this.closed ? Promise.resolve() : this.lastWrite;
799
+ }
800
+ /** Stops reading frames from the machine until `resume()`, so the machine's sends wait on the network. */
801
+ pause() {
802
+ this.socket.pause();
803
+ }
804
+ resume() {
805
+ this.socket.resume();
806
+ }
799
807
  onProgress(listener) {
800
808
  this.progress = listener;
801
809
  }
802
810
  onBinary(listener) {
803
811
  this.binary = listener;
804
812
  }
813
+ /** Server events other than `build.progress`, such as `device-host.metro.link.open`. */
814
+ onEvent(listener) {
815
+ this.event = listener;
816
+ }
817
+ /** Called once with the close code when the machine or the network ends the connection; never after `close()` or `drop()`. */
818
+ onDropped(listener) {
819
+ this.dropped = listener;
820
+ }
805
821
  get failure() {
806
822
  return this.closed;
807
823
  }
@@ -813,14 +829,18 @@ var BuildConnection = class BuildConnection {
813
829
  this.heard = Date.now();
814
830
  this.watched = true;
815
831
  }
832
+ /** Stops treating silence as a dropped connection, as before `watch()`. */
833
+ unwatch() {
834
+ this.watched = false;
835
+ }
816
836
  /** Closes with a close frame, which tells the machine to cancel this connection's jobs. */
817
- close() {
837
+ close(code = 1e3) {
818
838
  if (this.ended) return;
819
839
  this.forget();
820
840
  if (this.socket.readyState === WebSocket.CLOSED) return;
821
841
  const timer = setTimeout(() => this.socket.terminate(), CLOSE_TIMEOUT_MS);
822
842
  this.socket.once("close", () => clearTimeout(timer));
823
- this.socket.close(1e3);
843
+ this.socket.close(code);
824
844
  }
825
845
  /** Ends the connection without a close frame, which leaves its jobs on the machine for a new connection. */
826
846
  drop() {
@@ -839,6 +859,8 @@ var BuildConnection = class BuildConnection {
839
859
  this.pending.clear();
840
860
  this.progress = null;
841
861
  this.binary = null;
862
+ this.event = null;
863
+ this.dropped = null;
842
864
  clearInterval(this.keepalive);
843
865
  this.socket.removeAllListeners("close");
844
866
  this.unregisterExitCleanup?.();
@@ -962,7 +984,7 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
962
984
  * Asks every paired machine for an offer in parallel and keeps the connection to the one `pickOffer` chooses, or
963
985
  * returns why none takes the build. A named selection probes only its credential and skips auto load gating.
964
986
  */
965
- async function chooseBuildMachine({ projectRoot, target, mode, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, gradleArtifact, reactNativeArtifact, swiftpmArtifact, cacheOnly = false }) {
987
+ async function chooseBuildMachine({ projectRoot, target, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, gradleArtifact, reactNativeArtifact, swiftpmArtifact, cacheOnly = false }) {
966
988
  const started = Date.now();
967
989
  let identity;
968
990
  try {
@@ -1001,9 +1023,8 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1001
1023
  ...swiftpmQuery ? { swiftpmArtifact: swiftpmQuery } : {}
1002
1024
  })));
1003
1025
  const { order, reasons, candidates } = pickOffer({
1004
- localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local"),
1026
+ localEnabled: buildPlacementCandidates(selected).localEnabled,
1005
1027
  selected,
1006
- mode,
1007
1028
  here,
1008
1029
  target,
1009
1030
  artifact: swiftpmQuery ? "swiftpm" : reactNativeQuery ? `react-native-${reactNativeQuery.platform}` : gradleQuery ? "native-gradle" : artifact,
@@ -1031,13 +1052,12 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1031
1052
  });
1032
1053
  return {
1033
1054
  ...first,
1034
- mode,
1055
+ selected,
1035
1056
  here,
1036
1057
  target,
1037
1058
  offerMs: Date.now() - started,
1038
1059
  identity,
1039
1060
  runnersUp: rest,
1040
- automatic: selected === "auto",
1041
1061
  cacheOnly,
1042
1062
  ...gradleQuery ? { gradleArtifact: gradleQuery } : {},
1043
1063
  ...reactNativeQuery ? { reactNativeArtifact: reactNativeQuery } : {},
@@ -1264,7 +1284,7 @@ async function fetchArtifact({ connection, method, params, artifact, request, st
1264
1284
  if (badFrame) return { failure: "fetch: an artifact frame had another digest or could not be written here" };
1265
1285
  if (digest !== artifact.sha256 || declared.sha256 !== digest || declared.size !== received) return { failure: `fetch: the artifact's sha256 ${digest.slice(0, 12)} does not match ${String(artifact.sha256).slice(0, 12)}` };
1266
1286
  if (cacheHit) {
1267
- if ((await getExecutor().runFileAsync("tar", ["-tf", archive], { timeoutMs: 6e5 })).split("\n").filter(Boolean).some((member) => {
1287
+ if ((await getExecutor().runFileAsync("tar", ["-tf", archive], { timeoutMs: 6e5 })).split(/\r?\n/).filter(Boolean).some((member) => {
1268
1288
  const clean = member.replace(/^\.\//, "");
1269
1289
  return !(clean === name || clean.startsWith(`${name}/`)) || clean.split("/").includes("..");
1270
1290
  })) return { failure: "fetch: the archive contains paths outside its app" };
@@ -1383,11 +1403,10 @@ async function offloadBuild(input) {
1383
1403
  });
1384
1404
  if ("failure" in probe) return fail(probe.failure);
1385
1405
  const placement = pickOffer({
1386
- mode: choice.mode,
1387
1406
  here: choice.here,
1388
1407
  target: choice.target,
1389
- selected: choice.automatic ? "auto" : choice.machine,
1390
- localEnabled: !choice.automatic || automaticMachineEnabled("build", "local"),
1408
+ selected: choice.selected,
1409
+ localEnabled: buildPlacementCandidates(choice.selected).localEnabled,
1391
1410
  offers: [{
1392
1411
  machine: choice.machine,
1393
1412
  offer: probe.offer
@@ -1463,7 +1482,7 @@ async function offloadBuild(input) {
1463
1482
  return true;
1464
1483
  };
1465
1484
  for (;;) {
1466
- if (choice.automatic && !automaticMachineEnabled("build", choice.machine)) {
1485
+ if (!namedBuildMachine(choice.selected) && !automaticMachineEnabled("build", choice.machine)) {
1467
1486
  const reason = `${choice.machine} is disabled in remote.buildPoolDisabled`;
1468
1487
  if (moveOn(reason)) continue;
1469
1488
  return fail(reason);
@@ -1498,7 +1517,7 @@ async function offloadBuild(input) {
1498
1517
  workerStarted = Date.now();
1499
1518
  early = [];
1500
1519
  choice.connection.onProgress((event) => job === null ? early.push(event) : handle(event));
1501
- if (choice.automatic) requireAutomaticMachine("build", choice.machine);
1520
+ if (!namedBuildMachine(choice.selected)) requireAutomaticMachine("build", choice.machine);
1502
1521
  checkCancelled();
1503
1522
  const reply = await choice.connection.request("build.start", {
1504
1523
  repo: identity.repo,
@@ -1,10 +1,6 @@
1
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
- declare function androidClockOffset(serial: string, { exec, now }?: {
5
- exec?: Executor;
6
- now?: () => number;
7
- }): number | null;
8
4
  interface PidResolution {
9
5
  ok?: boolean;
10
6
  pid?: number;
@@ -13,19 +9,21 @@ interface PidResolution {
13
9
  }
14
10
  interface PidWatcher {
15
11
  stop(): void;
16
- probe(): number | null;
12
+ probe(): Promise<number | null>;
17
13
  readonly pid: number | null;
18
14
  }
19
- declare function watchAppPid({ serial, packageName, pid, intervalMs, exec, onChange, resolve, setTimer, clearTimer }: {
15
+ declare function watchAppPid({ serial, packageName, pid, intervalMs, exec, signal, onChange, resolve, setTimer, clearTimer }: {
20
16
  serial: string;
21
17
  packageName: string;
22
18
  pid: number | null;
23
19
  intervalMs?: number | null;
24
20
  exec?: Executor | null;
21
+ signal?: AbortSignal;
25
22
  onChange: (nextPid: number) => void | Promise<void>;
26
23
  resolve?: (serial: string, packageName: string, opts: {
27
24
  exec?: Executor | null;
28
- }) => number | null;
25
+ signal?: AbortSignal;
26
+ }) => number | null | Promise<number | null>;
29
27
  setTimer?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;
30
28
  clearTimer?: (t: ReturnType<typeof setTimeout>) => void;
31
29
  }): PidWatcher;
@@ -83,10 +81,13 @@ interface RunCollectorOptions {
83
81
  pidTimeoutMs?: number;
84
82
  pidOf?: ((serial: string, packageName: string, opts: {
85
83
  exec?: Executor | null;
86
- }) => number | null) | null;
84
+ }) => number | null | Promise<number | null>) | null;
87
85
  pidWatchMs?: number | null;
88
86
  watchPid?: typeof watchAppPid;
89
- resolveClockOffset?: typeof androidClockOffset;
87
+ resolveClockOffset?: (serial: string, opts: {
88
+ now?: () => number;
89
+ signal?: AbortSignal;
90
+ }) => number | null | Promise<number | null>;
90
91
  now?: () => number;
91
92
  onExit?: (code: number) => void;
92
93
  attachSignals?: boolean;
@@ -1,12 +1,12 @@
1
- import { S as process_identity_exports } from "./exec-VFRpu1iA.mjs";
2
- import { k as workspaceLogsDir } from "./workspace-state-pUg3_RRA.mjs";
3
- import { V as deviceSlotKey, q as validateDeviceSlot } from "./config-BktkY_zC.mjs";
1
+ import { S as process_identity_exports } from "./exec-aULwtNly.mjs";
2
+ import { k as workspaceLogsDir } from "./workspace-state-kIZrdlSg.mjs";
3
+ import { V as deviceSlotKey, q as validateDeviceSlot } from "./config-Cn94Jc0g.mjs";
4
4
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
5
- import { c as watchAppPid, i as parseLogcatLine, o as startAndroidLogcat, s as waitForAppPid, t as androidClockOffset } from "./android-B5P81yI-.mjs";
6
- import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
7
- import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-B6HK951C.mjs";
8
- import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-BjYvMNX_.mjs";
9
- import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-ENC4sRPA.mjs";
5
+ import { c as watchAppPid, i as parseLogcatLine, o as startAndroidLogcat, s as waitForAppPid, t as androidClockOffset } from "./android-D577ApKG.mjs";
6
+ import { i as createNdjsonWriter } from "./ndjson-Dy2W4vRa.mjs";
7
+ import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-CiBA-er9.mjs";
8
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-DJCq48IJ.mjs";
9
+ import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-CsRVik64.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";
@@ -130,11 +130,13 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
130
130
  return null;
131
131
  }
132
132
  let finished = false;
133
+ const shutdown = new AbortController();
133
134
  let captured = 0;
134
135
  let watcher = null;
135
136
  const finish = (code, level, msg, event, { signalled = false } = {}) => {
136
137
  if (finished) return;
137
138
  finished = true;
139
+ shutdown.abort();
138
140
  watcher?.stop();
139
141
  if (physical && captured === 0 && !signalled) writer.write({
140
142
  ...attribution,
@@ -187,7 +189,8 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
187
189
  }) : await waitForAppPid({
188
190
  serial,
189
191
  packageName,
190
- timeoutMs: pidTimeoutMs
192
+ timeoutMs: pidTimeoutMs,
193
+ signal: shutdown.signal
191
194
  });
192
195
  if (!resolved.ok) {
193
196
  finish(1, "error", `device log collector could not attach: ${resolved.reason}`, "collector_failed");
@@ -214,8 +217,11 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
214
217
  })
215
218
  });
216
219
  const parse = platform === "ios" ? physical ? parseDeviceConsoleLine : parseLogStreamLine : parseLogcatLine;
217
- const attach = (streamPid) => {
218
- const clockOffsetMs = platform === "android" ? resolveClockOffset(serial, { now }) : null;
220
+ const readClockOffset = async () => platform === "android" ? await resolveClockOffset(serial, {
221
+ now,
222
+ signal: shutdown.signal
223
+ }) : null;
224
+ const attach = (streamPid, clockOffsetMs) => {
219
225
  if (platform === "android") writer.write({
220
226
  ...attribution,
221
227
  src: "device",
@@ -284,17 +290,21 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
284
290
  spawned.on("exit", (code, signal) => {
285
291
  if (spawned !== child) return;
286
292
  flushReaders();
287
- const next = platform === "android" ? watcher?.probe() : null;
288
- if (next && next !== pid) {
289
- reattach(next, "the log stream ended");
290
- return;
291
- }
292
- const how = signal ? `signal ${signal}` : `exit code ${code}`;
293
- if (physical && code) {
294
- finish(1, "error", `the devicectl console ended with ${how}; treat the run as failed`, "collector_failed");
295
- return;
296
- }
297
- finish(0, "info", `device log stream ended (${how}); the app or device is gone`, "collector_stopped");
293
+ const settle = (next) => {
294
+ if (spawned !== child) return;
295
+ if (next && next !== pid) {
296
+ reattach(next, "the log stream ended");
297
+ return;
298
+ }
299
+ const how = signal ? `signal ${signal}` : `exit code ${code}`;
300
+ if (physical && code) {
301
+ finish(1, "error", `the devicectl console ended with ${how}; treat the run as failed`, "collector_failed");
302
+ return;
303
+ }
304
+ finish(0, "info", `device log stream ended (${how}); the app or device is gone`, "collector_stopped");
305
+ };
306
+ if (platform === "android" && watcher) watcher.probe().then(settle);
307
+ else settle(null);
298
308
  });
299
309
  spawned.on("error", (err) => {
300
310
  if (spawned !== child) return;
@@ -302,12 +312,13 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
302
312
  });
303
313
  return spawned;
304
314
  };
305
- const reattach = (nextPid, why = "the app restarted") => {
306
- if (finished) return;
315
+ const reattach = async (nextPid, why = "the app restarted") => {
316
+ if (finished || nextPid === pid) return;
307
317
  const previous = pid;
308
318
  flushReaders();
309
319
  killChild(child);
310
320
  child = null;
321
+ pid = nextPid;
311
322
  writer.write({
312
323
  ...attribution,
313
324
  src: "device",
@@ -316,15 +327,18 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
316
327
  event: "collector_reattached",
317
328
  msg: `${why}: ${packageName} is now pid ${nextPid} on ${serial} (was ${previous}); reattaching the log stream`
318
329
  });
319
- pid = nextPid;
330
+ const clockOffsetMs = await readClockOffset();
331
+ if (finished || pid !== nextPid) return;
320
332
  try {
321
- child = attach(nextPid);
333
+ child = attach(nextPid, clockOffsetMs);
322
334
  } catch (err) {
323
335
  finish(1, "error", `device log collector could not reattach to pid ${nextPid}: ${describe(err)}`, "collector_failed");
324
336
  }
325
337
  };
338
+ const initialClockOffsetMs = await readClockOffset();
339
+ if (finished) return null;
326
340
  try {
327
- child = attach(pid);
341
+ child = attach(pid, initialClockOffsetMs);
328
342
  } catch (err) {
329
343
  finish(1, "error", `device log collector could not start: ${describe(err)}`, "collector_failed");
330
344
  return null;
@@ -334,6 +348,7 @@ async function runCollector({ slot = "default", platform, root, udid = null, app
334
348
  packageName,
335
349
  pid,
336
350
  intervalMs: pidWatchMs,
351
+ signal: shutdown.signal,
337
352
  resolve: pidOf || void 0,
338
353
  onChange: (nextPid) => reattach(nextPid)
339
354
  });
@@ -1,5 +1,5 @@
1
1
  import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
2
- import { t as NO_PROJECT_REFUSAL } from "./project-BUu6Is4k.mjs";
2
+ import { t as NO_PROJECT_REFUSAL } from "./project-Sui52ywT.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