stim 1.26.0 → 1.27.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 (171) hide show
  1. package/dist/{acquire-artifact-DVsvSwf7.mjs → acquire-artifact-BKN2Yuhg.mjs} +2 -2
  2. package/dist/{act-C-BqJEpu.mjs → act-ROviTF_t.mjs} +297 -122
  3. package/dist/{activity-Lnb_EoRY.mjs → activity-Cd-ysFes.mjs} +6 -6
  4. package/dist/{agent-device-usage-output-DbXy5tg8.mjs → agent-device-usage-output-C5nCKWp9.mjs} +5 -5
  5. package/dist/{android-CSbLRD53.mjs → android--HBgpvpW.mjs} +5 -5
  6. package/dist/{android-CiNQw3kq.mjs → android-Cd6w7_qw.mjs} +96 -43
  7. package/dist/{android-B5P81yI-.mjs → android-Deb9X3_Y.mjs} +37 -15
  8. package/dist/{android-DTAcRwBC.mjs → android-DriNoAVy.mjs} +23 -18
  9. package/dist/{android-cas-BTVhZ0Qs.mjs → android-cas-D5e6ecUg.mjs} +4 -4
  10. package/dist/android-cas-compiler.mjs +1 -1
  11. package/dist/api.d.mts +13 -3
  12. package/dist/api.mjs +39 -29
  13. package/dist/{apk-signed-tail-B46U9hXc.mjs → apk-signed-tail-BHQHx3Rm.mjs} +2 -2
  14. package/dist/{artifact-BxREhAaV.mjs → artifact-0AGJYB9O.mjs} +18 -23
  15. package/dist/{artifact-CsAP6AGK.mjs → artifact-faemIZv5.mjs} +19 -24
  16. package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
  17. package/dist/auto-placement-z-H5pJza.mjs +350 -0
  18. package/dist/{browser-web-rYPyqhTf.mjs → browser-web-slD8AvLp.mjs} +16 -16
  19. package/dist/{build-cache-DrXNCy3T.mjs → build-cache-gBJ-WKzA.mjs} +43 -21
  20. package/dist/{build-DPhApsjV.mjs → build-hS0QyFlQ.mjs} +35 -31
  21. package/dist/{build-plan-DrMMdayj.mjs → build-plan-CBqYbzYM.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-BWTze1Ls.mjs} +560 -1603
  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-ftXDLto1.mjs} +24 -23
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-D9CaRks-.mjs → client-xsdxrhWA.mjs} +48 -62
  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-Dj-WT4BP.mjs} +1 -1
  33. package/dist/{config-BktkY_zC.mjs → config-Cn94Jc0g.mjs} +23 -4
  34. package/dist/{dependencies-Dw6wfQdv.mjs → dependencies-BGokZ-Ng.mjs} +108 -60
  35. package/dist/{dependency-state-DFB41vfr.mjs → dependency-state-C3OtgG94.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-BMca82xo.mjs} +2 -2
  38. package/dist/{device-BcYeHSFu.mjs → device-BJm0irrq.mjs} +16 -16
  39. package/dist/{device-capacity-DCSvUF0l.mjs → device-capacity-6LP7QsaA.mjs} +101 -16
  40. package/dist/device-host-worker.mjs +19 -19
  41. package/dist/{device-ios-BLGfXQeK.mjs → device-ios-534c14fz.mjs} +251 -23
  42. package/dist/{device-lease-run-BmvIl7bI.mjs → device-lease-run-DwsGfjUN.mjs} +5 -5
  43. package/dist/{device-pool-Dluix4H3.mjs → device-pool-BnQqvs6o.mjs} +3 -3
  44. package/dist/{device-BK-zwyd_.mjs → device-tM41-TUq.mjs} +25 -24
  45. package/dist/{doctor-Cp-BhzTS.mjs → doctor-Dbx1ZpD2.mjs} +1 -1
  46. package/dist/{doctor-Bhg1ii70.mjs → doctor-DyqE9n1J.mjs} +28 -16
  47. package/dist/{doctor-OnwP94ne.mjs → doctor-F-3VUUyN.mjs} +76 -32
  48. package/dist/{doctor-fingerprint-D3a04Mhu.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +1 -1
  49. package/dist/doctor-fingerprint.mjs +1 -1
  50. package/dist/{doctor-watchman-BStK05nt.mjs → doctor-watchman-CxDbyrrt.mjs} +5 -5
  51. package/dist/{eas-build-Dsj93iM9.mjs → eas-build-CjNSWmjo.mjs} +4 -4
  52. package/dist/eas-fallback-9fqb46kW.mjs +87 -0
  53. package/dist/{eas-session-ledger-B5vygTiD.mjs → eas-session-ledger-DrP4OuuM.mjs} +6 -6
  54. package/dist/{error-diagnostics-BOOm9Db7.mjs → error-diagnostics-snej9k4j.mjs} +51 -25
  55. package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
  56. package/dist/{gc-C_79zvz4.mjs → gc-BRwAY3qT.mjs} +2 -2
  57. package/dist/{gc-ldgr-hXU.mjs → gc-CGZ1Yg88.mjs} +160 -45
  58. package/dist/{guide-D7K0X6KG.mjs → guide-_rfEh_zM.mjs} +580 -183
  59. package/dist/{hosted-android-Bk54ej6n.mjs → hosted-android-BMKzUNnY.mjs} +4 -4
  60. package/dist/{hosted-client-fHO8yqzc.mjs → hosted-client-D7Pk_Oo1.mjs} +12 -8
  61. package/dist/{hosted-logs-BfbmDM4M.mjs → hosted-logs-B1gqQuva.mjs} +8 -8
  62. package/dist/{hosted-logs-sync-B0pvmOk-.mjs → hosted-logs-sync-Dg3qrZmV.mjs} +5 -5
  63. package/dist/{hosted-macos-CPl0OZ9h.mjs → hosted-macos-B9w4H8hc.mjs} +6 -6
  64. package/dist/{hosted-native-CpDB3-PO.mjs → hosted-native-CdgaiuyP.mjs} +17 -16
  65. package/dist/{idle-shutdown-FfxL1KdG.mjs → idle-shutdown-Cbvo5KEh.mjs} +7 -8
  66. package/dist/{ios-ftxdQbJS.mjs → ios-B5HlVMhQ.mjs} +92 -37
  67. package/dist/{ios-B7-lToDu.mjs → ios-Bk4mWbtS.mjs} +8 -8
  68. package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
  69. package/dist/{ios-WxpDJ5T1.mjs → ios-E26qSpkb.mjs} +27 -11
  70. package/dist/{ios-device-CsyryvpT.mjs → ios-device-C_QkIf1Z.mjs} +3 -3
  71. package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
  72. package/dist/{ios-project-Ty5pHl9O.mjs → ios-project-D8Jcy_br.mjs} +22 -9
  73. package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
  74. package/dist/{ios-state-Cw7-WQf2.mjs → ios-state-BZ03NFgF.mjs} +1 -1
  75. package/dist/{js-swap-BMhXYVDS.mjs → js-swap-Dg2a945i.mjs} +8 -7
  76. package/dist/{launch-DOp8RjDz.mjs → launch-CRyBeNsA.mjs} +42 -38
  77. package/dist/lightened-BCsdAGj_.mjs +171 -0
  78. package/dist/{logs-dQDki6Tt.mjs → logs-CC_-ZzEE.mjs} +7 -7
  79. package/dist/{logs-s1dRIG1E.mjs → logs-aJQb-RDg.mjs} +46 -21
  80. package/dist/{macos-B0VEV3Gf.mjs → macos-BGmTpnv9.mjs} +1 -1
  81. package/dist/{macos-DBBPNnIA.mjs → macos-DlCBhMw5.mjs} +73 -38
  82. package/dist/macos-run.mjs +1 -1
  83. package/dist/maintenance-run.mjs +7 -7
  84. package/dist/{metro-CjC10t6E.mjs → metro-CvyD-xwe.mjs} +4 -4
  85. package/dist/{metro-gateway-B6_PgD0L.mjs → metro-gateway-BnHdqMO_.mjs} +3 -3
  86. package/dist/{named-ports-BG0j1X4g.mjs → named-ports-BCyMWA6b.mjs} +3 -3
  87. package/dist/{native-android-CL2NGiik.mjs → native-android-DlpxCyOP.mjs} +17 -18
  88. package/dist/{native-gradle-artifact-inputs-btSUulme.mjs → native-gradle-artifact-inputs-C13qT7R_.mjs} +5 -5
  89. package/dist/{native-runtime-Dq3RBcON.mjs → native-runtime-DqaIBO5w.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-B1W8SrxB.mjs} +3 -3
  92. package/dist/{native-xcode-ios-CBXJAxfC.mjs → native-xcode-ios-QPP0Rm68.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-Bx-0cku-.mjs} +3 -3
  97. package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
  98. package/dist/{phone-reverses-lmj6kcPm.mjs → phone-reverses-C9yAaKEv.mjs} +18 -4
  99. package/dist/{placement-log-DIFPQAXp.mjs → placement-log-BXUbiZM6.mjs} +3 -3
  100. package/dist/{plan-placement-IiiSQhtz.mjs → plan-placement-UxnQjv5Z.mjs} +36 -10
  101. package/dist/{ports-C2_w1Z0Z.mjs → ports-uUrghqWN.mjs} +3 -3
  102. package/dist/{prebuild-gmouvmJZ.mjs → prebuild-BDpToDgR.mjs} +16 -17
  103. package/dist/{project-BUu6Is4k.mjs → project-DYj-HVx6.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-DDBccgJw.mjs} +32 -26
  107. package/dist/{react-native-build-oNwqF5Wb.mjs → react-native-build-DaK2IFyP.mjs} +9 -9
  108. package/dist/{react-native-doctor-BhA3KUte.mjs → react-native-doctor-B-Mw6DcR.mjs} +6 -6
  109. package/dist/{react-native-ios-B-nf4rjN.mjs → react-native-ios-DjYwUF9U.mjs} +23 -17
  110. package/dist/{recordings-BldzVKq0.mjs → recordings-C20iUZfp.mjs} +1 -1
  111. package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
  112. package/dist/{reload-C9OduiNc.mjs → reload-DJBeF_rC.mjs} +1 -1
  113. package/dist/{reload-CCR7KC_l.mjs → reload-fUdkH2_p.mjs} +16 -16
  114. package/dist/{remote-C8S7FlPF.mjs → remote-y6n99WMW.mjs} +22 -9
  115. package/dist/{result-7F5hEwQJ.mjs → result-CTqBw2Te.mjs} +32 -21
  116. package/dist/{run-BqB0v3pt.mjs → run-DaCeNKRm.mjs} +3 -3
  117. package/dist/{selection-BNPBZ6T5.mjs → selection-Bs8phwhN.mjs} +37 -29
  118. package/dist/{server-bare-A75rDIdD.mjs → server-bare-BOh-iZEj.mjs} +2 -2
  119. package/dist/{server-command-CssKFOD7.mjs → server-command-8CuA51Cv.mjs} +6 -6
  120. package/dist/{server-expo-eQfOdydb.mjs → server-expo-ABQs2XFA.mjs} +4 -4
  121. package/dist/server-expo-Ba_Y21vB.mjs +2 -0
  122. package/dist/{settings-CosW5X-S.mjs → settings-BDVI8Ivc.mjs} +331 -62
  123. package/dist/{settings-OaGQF-ri.mjs → settings-CMHhQNwI.mjs} +24 -3
  124. package/dist/settings-payload-cm60Zhib.mjs +257 -0
  125. package/dist/settings-write-BdNRLlBn.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-0l7RqSpr.mjs} +6 -6
  129. package/dist/{stage-jKQ7CP_B.mjs → stage-F4cAfJGi.mjs} +2 -2
  130. package/dist/{start-C_wefNKB.mjs → start-DcqnF9p8.mjs} +1 -1
  131. package/dist/{start-_BdJ32cZ.mjs → start-DrPwER_2.mjs} +27 -22
  132. package/dist/{state-C1i2nMOP.mjs → state-BX1y5syV.mjs} +4 -4
  133. package/dist/{state-C4OdpOTF.mjs → state-CZxLyetD.mjs} +2 -2
  134. package/dist/{stats-tEpEEH-u.mjs → stats-GxuCbles.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-BfnK9pUd.mjs} +25 -25
  138. package/dist/{status-B9M7x4CZ.mjs → status-Bj7ZYvvc.mjs} +1 -1
  139. package/dist/{status-watch-B5wDIH_o.mjs → status-watch-BfabQn03.mjs} +5 -5
  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-ySNQHXMG.mjs → stop-CH79S3IZ.mjs} +5 -5
  143. package/dist/{stop-DRqQVqDJ.mjs → stop-D-EAr25B.mjs} +21 -20
  144. package/dist/{stop-CmdNhGlC.mjs → stop-x1Yu3He4.mjs} +2 -2
  145. package/dist/supervisor-run.mjs +17 -17
  146. package/dist/{support-CVOCp0Ft.mjs → support-Be0UeVZU.mjs} +10 -10
  147. package/dist/{support-BGSCBoib.mjs → support-CNg_YsOk.mjs} +6 -6
  148. package/dist/{swiftpm-artifact-inputs-CfUzt_0Z.mjs → swiftpm-artifact-inputs-uPqYvGBv.mjs} +4 -4
  149. package/dist/{swiftpm-macos-x6HPpl_2.mjs → swiftpm-macos-Ch4YjY_A.mjs} +11 -12
  150. package/dist/{toolchain-J4J8MrAr.mjs → toolchain-CbCG6C5Z.mjs} +321 -15
  151. package/dist/{toolchain-DoavrvIA.mjs → toolchain-JYAOquPg.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-C0RsbngN.mjs} +731 -727
  155. package/dist/{web-Bihbf7-u.mjs → web-Cq_AQ4DK.mjs} +9 -9
  156. package/dist/web-Je6abcpz.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-BjqdjnJR.mjs} +3 -3
  160. package/dist/{workspaces-g2lhdBXF.mjs → workspaces-DFbj07jp.mjs} +1795 -70
  161. package/dist/{worktree-BKuklFh_.mjs → worktree-COAJ3-OD.mjs} +934 -514
  162. package/dist/{worktree-Bm4cb-nU.mjs → worktree-JGUd_53L.mjs} +1 -1
  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
@@ -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-Dbx1ZpD2.mjs")],
9
+ ["worktree", () => import("./worktree-JGUd_53L.mjs")],
10
+ ["start", () => import("./start-DcqnF9p8.mjs")],
11
+ ["ports", () => import("./ports-uUrghqWN.mjs")],
12
+ ["stop", () => import("./stop-x1Yu3He4.mjs")],
13
+ ["ios", () => import("./ios-Bk4mWbtS.mjs")],
14
+ ["android", () => import("./android--HBgpvpW.mjs")],
15
+ ["web", () => import("./web-Je6abcpz.mjs")],
16
+ ["macos", () => import("./macos-BGmTpnv9.mjs")],
17
+ ["reload", () => import("./reload-DJBeF_rC.mjs")],
18
+ ["device", () => import("./device-BJm0irrq.mjs")],
19
+ ["logs", () => import("./logs-aJQb-RDg.mjs")],
20
+ ["settings", () => import("./settings-CMHhQNwI.mjs")],
21
+ ["status", () => import("./status-Bj7ZYvvc.mjs")],
22
+ ["stats", () => import("./stats-GxuCbles.mjs")],
23
+ ["gc", () => import("./gc-BRwAY3qT.mjs")],
24
+ ["guide", () => import("./guide-_rfEh_zM.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-ftXDLto1.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-BWTze1Ls.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-CbCG6C5Z.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-Bs8phwhN.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,
@@ -962,7 +951,7 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
962
951
  * Asks every paired machine for an offer in parallel and keeps the connection to the one `pickOffer` chooses, or
963
952
  * returns why none takes the build. A named selection probes only its credential and skips auto load gating.
964
953
  */
965
- async function chooseBuildMachine({ projectRoot, target, mode, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, gradleArtifact, reactNativeArtifact, swiftpmArtifact, cacheOnly = false }) {
954
+ async function chooseBuildMachine({ projectRoot, target, here, note, machines = pairedMachines(), selected = "auto", onCandidates, artifact, gradleArtifact, reactNativeArtifact, swiftpmArtifact, cacheOnly = false }) {
966
955
  const started = Date.now();
967
956
  let identity;
968
957
  try {
@@ -1001,9 +990,8 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1001
990
  ...swiftpmQuery ? { swiftpmArtifact: swiftpmQuery } : {}
1002
991
  })));
1003
992
  const { order, reasons, candidates } = pickOffer({
1004
- localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local"),
993
+ localEnabled: buildPlacementCandidates(selected).localEnabled,
1005
994
  selected,
1006
- mode,
1007
995
  here,
1008
996
  target,
1009
997
  artifact: swiftpmQuery ? "swiftpm" : reactNativeQuery ? `react-native-${reactNativeQuery.platform}` : gradleQuery ? "native-gradle" : artifact,
@@ -1031,13 +1019,12 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1031
1019
  });
1032
1020
  return {
1033
1021
  ...first,
1034
- mode,
1022
+ selected,
1035
1023
  here,
1036
1024
  target,
1037
1025
  offerMs: Date.now() - started,
1038
1026
  identity,
1039
1027
  runnersUp: rest,
1040
- automatic: selected === "auto",
1041
1028
  cacheOnly,
1042
1029
  ...gradleQuery ? { gradleArtifact: gradleQuery } : {},
1043
1030
  ...reactNativeQuery ? { reactNativeArtifact: reactNativeQuery } : {},
@@ -1383,11 +1370,10 @@ async function offloadBuild(input) {
1383
1370
  });
1384
1371
  if ("failure" in probe) return fail(probe.failure);
1385
1372
  const placement = pickOffer({
1386
- mode: choice.mode,
1387
1373
  here: choice.here,
1388
1374
  target: choice.target,
1389
- selected: choice.automatic ? "auto" : choice.machine,
1390
- localEnabled: !choice.automatic || automaticMachineEnabled("build", "local"),
1375
+ selected: choice.selected,
1376
+ localEnabled: buildPlacementCandidates(choice.selected).localEnabled,
1391
1377
  offers: [{
1392
1378
  machine: choice.machine,
1393
1379
  offer: probe.offer
@@ -1463,7 +1449,7 @@ async function offloadBuild(input) {
1463
1449
  return true;
1464
1450
  };
1465
1451
  for (;;) {
1466
- if (choice.automatic && !automaticMachineEnabled("build", choice.machine)) {
1452
+ if (!namedBuildMachine(choice.selected) && !automaticMachineEnabled("build", choice.machine)) {
1467
1453
  const reason = `${choice.machine} is disabled in remote.buildPoolDisabled`;
1468
1454
  if (moveOn(reason)) continue;
1469
1455
  return fail(reason);
@@ -1498,7 +1484,7 @@ async function offloadBuild(input) {
1498
1484
  workerStarted = Date.now();
1499
1485
  early = [];
1500
1486
  choice.connection.onProgress((event) => job === null ? early.push(event) : handle(event));
1501
- if (choice.automatic) requireAutomaticMachine("build", choice.machine);
1487
+ if (!namedBuildMachine(choice.selected)) requireAutomaticMachine("build", choice.machine);
1502
1488
  checkCancelled();
1503
1489
  const reply = await choice.connection.request("build.start", {
1504
1490
  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-BjqdjnJR.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-Deb9X3_Y.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-Bx-0cku-.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-DYj-HVx6.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,8 +1,8 @@
1
- import { C as reportSignal, D as ownership_claim_exports, S as process_identity_exports, T as trackReportResource, l as WorkspaceProcessCleanupError, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { t as runOperationFile } from "./operation-exec-CUZifp6Z.mjs";
1
+ import { C as reportSignal, D as ownership_claim_exports, S as process_identity_exports, T as trackReportResource, l as WorkspaceProcessCleanupError, t as getExecutor } from "./exec-aULwtNly.mjs";
2
+ import { t as runOperationFile } from "./operation-exec-Dp4FuIGR.mjs";
3
3
  import { join } from "node:path";
4
4
  import { ambientEnv, configDir, ensurePrivateDir } from "@stim-cli/core";
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";
5
+ import { allMetroPorts, cannotHost, clientIdentity, configCorruptRepair, endpoint, endpoint as endpoint$1, findEnclosingWorktreeRoot, findPeer, findPeer as findPeer$1, getConcurrencyLimits, getConfigPath, getConfigPath as getConfigPath$1, getProject, getProjectSettings, getRepoSettings, isJsonObject, isPathPrefix as isPathPrefix$1, 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";
6
6
  import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, normalize, parse, sep as sep$1 } from "path";
7
7
  import { request } from "node:https";
8
8
  import { WebSocket } from "ws";
@@ -548,6 +548,25 @@ async function diagnoseOutcome(io, input) {
548
548
  pinged
549
549
  });
550
550
  }
551
+ /**
552
+ * The diagnosis `stim doctor` gives for a machine that resolved to a tailnet peer but did not connect, without
553
+ * doctor's `tailscale ping`: the connection has already waited out its timeout. Reads `tailscale status` only here,
554
+ * after the failure. Null when Tailscale no longer lists the machine.
555
+ */
556
+ async function diagnoseConnectFailure(machine, failure, signal) {
557
+ const parsed = parseMachine(machine);
558
+ if (!parsed) return null;
559
+ const peer = findPeer(await tailscaleStatusAsync(signal), parsed.name);
560
+ if (typeof peer === "string") return null;
561
+ return diagnoseOutcome({ startup: peerStartup }, {
562
+ entry: machine,
563
+ peer,
564
+ port: parsed.port,
565
+ target: endpoint(peer, parsed.port),
566
+ reason: failure.failure,
567
+ ...failure.transport ? { transport: failure.transport } : {}
568
+ });
569
+ }
551
570
  /** Why `status` is null, as a diagnosis of the Tailscale layer; falls back to the daemon being unavailable. */
552
571
  async function diagnoseTailscale(io) {
553
572
  const reading = readTailscale(io.rawStatus ? await io.rawStatus() : null);
@@ -1258,4 +1277,4 @@ function allConsolePortsAndSerials({ isMounted = isOnMountedVolume } = {}) {
1258
1277
  return result;
1259
1278
  }
1260
1279
  //#endregion
1261
- export { findPeer$1 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, endpoint as Q, volumeRootFor as R, removeProject as S, setSupervisor as T, parseDeviceSlotKey as U, deviceSlotKey as V, parseDeviceSlotOption as W, diagnoseTailscale as X, diagnoseOutcome as Y, doctorIo as Z, loadConfig$1 as _, clearDevice as a, resolveEndpoint as at, releaseAndroidConsolePort as b, ensureConfig as c, tailscaleStatusAsync as ct, getConfigDir as d, readHostPermissions as dt, openAuthenticated as et, getConfigPath$1 as f, isPathPrefix as g, getRepoSettings as h, clearAndroidBootPending as i, realIo as it, acquireAvdClaim as j, writeConfigSetting as k, findEnclosingWorktreeRoot as l, diagnosisFinding as lt, getProjectSettings as m, allMetroPorts as n, parseMachine$1 as nt, clearSupervisor as o, sayHello as ot, getProject as p, validateDeviceSlot as q, claimMetroPort as r, reachMachine as rt, configCorruptRepair as s, setupRemedy as st, allConsolePortsAndSerials as t, outdatedServer as tt, getConcurrencyLimits as u, notOnTailnetDiagnosis as ut, recordIosSchemeApprovals as v, setDevice as w, releaseMetroPort as x, refuseRelativeStimPaths as y, assignSlotDevice as z };
1280
+ export { endpoint$1 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, doctorIo as Q, volumeRootFor as R, removeProject as S, setSupervisor as T, parseDeviceSlotKey as U, deviceSlotKey as V, parseDeviceSlotOption as W, diagnoseOutcome as X, diagnoseConnectFailure as Y, diagnoseTailscale as Z, loadConfig$1 as _, clearDevice as a, realIo as at, releaseAndroidConsolePort as b, ensureConfig as c, setupRemedy as ct, getConfigDir as d, notOnTailnetDiagnosis as dt, findPeer$1 as et, getConfigPath$1 as f, readHostPermissions as ft, isPathPrefix$1 as g, getRepoSettings as h, clearAndroidBootPending as i, reachMachine as it, acquireAvdClaim as j, writeConfigSetting as k, findEnclosingWorktreeRoot as l, tailscaleStatusAsync as lt, getProjectSettings as m, allMetroPorts as n, outdatedServer as nt, clearSupervisor as o, resolveEndpoint as ot, getProject as p, validateDeviceSlot as q, claimMetroPort as r, parseMachine$1 as rt, configCorruptRepair as s, sayHello as st, allConsolePortsAndSerials as t, openAuthenticated as tt, getConcurrencyLimits as u, diagnosisFinding as ut, recordIosSchemeApprovals as v, setDevice as w, releaseMetroPort as x, refuseRelativeStimPaths as y, assignSlotDevice as z };