stim 1.25.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 (182) hide show
  1. package/README.md +1 -1
  2. package/dist/{acquire-artifact-zA4S7RHE.mjs → acquire-artifact-BKN2Yuhg.mjs} +2 -2
  3. package/dist/{act-BbHS3oV8.mjs → act-ROviTF_t.mjs} +415 -118
  4. package/dist/{activity-BpjwrQXU.mjs → activity-Cd-ysFes.mjs} +6 -7
  5. package/dist/{agent-device-usage-output-Bnkerfod.mjs → agent-device-usage-output-C5nCKWp9.mjs} +5 -5
  6. package/dist/{android-CNZgRC-4.mjs → android--HBgpvpW.mjs} +5 -5
  7. package/dist/{android-BGwuK3Mc.mjs → android-Cd6w7_qw.mjs} +134 -57
  8. package/dist/{android-saBeB4lr.mjs → android-Deb9X3_Y.mjs} +37 -15
  9. package/dist/{android-Cjcj8MCw.mjs → android-DriNoAVy.mjs} +99 -47
  10. package/dist/{android-cas-BVqh2Zep.mjs → android-cas-D5e6ecUg.mjs} +4 -4
  11. package/dist/android-cas-compiler.mjs +1 -1
  12. package/dist/{android-project-CTYaETc0.d.mts → android-project-DUGMbq28.d.mts} +55 -1
  13. package/dist/api.d.mts +20 -7
  14. package/dist/api.mjs +42 -32
  15. package/dist/apk-signed-tail-BHQHx3Rm.mjs +142 -0
  16. package/dist/{artifact-Co8zixVx.mjs → artifact-0AGJYB9O.mjs} +28 -28
  17. package/dist/{artifact-DN8JNwqS.mjs → artifact-faemIZv5.mjs} +40 -30
  18. package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
  19. package/dist/{attempt-DW-mQqM7.mjs → attempt-ClyJlZPT.mjs} +4 -2
  20. package/dist/auto-placement-z-H5pJza.mjs +350 -0
  21. package/dist/{browser-web-CCgZsHmI.mjs → browser-web-slD8AvLp.mjs} +16 -17
  22. package/dist/{build-cache-CKCzxzxA.mjs → build-cache-gBJ-WKzA.mjs} +141 -37
  23. package/dist/{build-CAiw8Ezm.mjs → build-hS0QyFlQ.mjs} +38 -31
  24. package/dist/{build-plan-zCuHGlA8.mjs → build-plan-CBqYbzYM.mjs} +7 -6
  25. package/dist/{cache-manifest-BPXRONJz.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
  26. package/dist/cache-manifest.mjs +1 -1
  27. package/dist/{budget-HyShrIpL.mjs → ccache-BWTze1Ls.mjs} +634 -1514
  28. package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
  29. package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
  30. package/dist/{cli-C4w607Pz.mjs → cli-ftXDLto1.mjs} +24 -23
  31. package/dist/cli.mjs +1 -1
  32. package/dist/{client-BQsmyp_-.mjs → client-xsdxrhWA.mjs} +77 -116
  33. package/dist/collector-run.d.mts +10 -9
  34. package/dist/collector-run.mjs +42 -27
  35. package/dist/{command-output-BBvS1H6v.mjs → command-output-Dj-WT4BP.mjs} +1 -1
  36. package/dist/{config-BZhXY15H.mjs → config-Cn94Jc0g.mjs} +343 -18
  37. package/dist/{launch-DscF1QfM.mjs → dependencies-BGokZ-Ng.mjs} +330 -279
  38. package/dist/{dependency-state-BwNCYG5Q.mjs → dependency-state-C3OtgG94.mjs} +14 -7
  39. package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
  40. package/dist/{dev-client-CHoXXZeg.mjs → dev-client-BMca82xo.mjs} +2 -2
  41. package/dist/{device-F5-4z9ef.mjs → device-BJm0irrq.mjs} +16 -16
  42. package/dist/{device-capacity-ZYaRALv5.mjs → device-capacity-6LP7QsaA.mjs} +103 -25
  43. package/dist/device-host-worker.mjs +19 -21
  44. package/dist/{device-ios-DkHBrmvH.mjs → device-ios-534c14fz.mjs} +288 -28
  45. package/dist/{device-lease-run-ogEeJ62K.mjs → device-lease-run-DwsGfjUN.mjs} +5 -5
  46. package/dist/{device-pool-BIg8MU8l.mjs → device-pool-BnQqvs6o.mjs} +3 -3
  47. package/dist/{device-B9FqTBYW.mjs → device-tM41-TUq.mjs} +25 -24
  48. package/dist/{doctor-A_Nr_fDe.mjs → doctor-Dbx1ZpD2.mjs} +1 -1
  49. package/dist/{doctor-k3P3PizH.mjs → doctor-DyqE9n1J.mjs} +28 -16
  50. package/dist/{doctor-Bm8TVpGn.mjs → doctor-F-3VUUyN.mjs} +128 -35
  51. package/dist/{doctor-fingerprint-zlujA1Gs.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +9 -3
  52. package/dist/doctor-fingerprint.mjs +1 -1
  53. package/dist/{doctor-watchman-BovI1y3-.mjs → doctor-watchman-CxDbyrrt.mjs} +5 -5
  54. package/dist/{eas-build-CyDKNTBP.mjs → eas-build-CjNSWmjo.mjs} +4 -4
  55. package/dist/eas-fallback-9fqb46kW.mjs +87 -0
  56. package/dist/{eas-session-ledger-BMCA1gdO.mjs → eas-session-ledger-DrP4OuuM.mjs} +6 -6
  57. package/dist/{error-diagnostics-B1Mj_-7h.mjs → error-diagnostics-snej9k4j.mjs} +51 -25
  58. package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
  59. package/dist/{gc-eaz403W6.mjs → gc-BRwAY3qT.mjs} +2 -2
  60. package/dist/{gc-B9jcnmIk.mjs → gc-CGZ1Yg88.mjs} +218 -72
  61. package/dist/{guide-DR0K0xW9.mjs → guide-_rfEh_zM.mjs} +839 -222
  62. package/dist/{hosted-android-Bvb2-ZxD.mjs → hosted-android-BMKzUNnY.mjs} +4 -4
  63. package/dist/{hosted-client-rsRqysJc.mjs → hosted-client-D7Pk_Oo1.mjs} +13 -9
  64. package/dist/{hosted-logs-CWKGYWNX.mjs → hosted-logs-B1gqQuva.mjs} +18 -12
  65. package/dist/hosted-logs-sync-Dg3qrZmV.mjs +195 -0
  66. package/dist/{hosted-macos-d0pv9Tth.mjs → hosted-macos-B9w4H8hc.mjs} +6 -6
  67. package/dist/{hosted-native-BxTizGU2.mjs → hosted-native-CdgaiuyP.mjs} +17 -17
  68. package/dist/{idle-shutdown-BIyfl0Zj.mjs → idle-shutdown-Cbvo5KEh.mjs} +21 -9
  69. package/dist/{ios-BRVM8b0P.mjs → ios-B5HlVMhQ.mjs} +138 -55
  70. package/dist/{ios-Dvt97HgQ.mjs → ios-Bk4mWbtS.mjs} +8 -8
  71. package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
  72. package/dist/{ios-BQzvJlzw.mjs → ios-E26qSpkb.mjs} +94 -11
  73. package/dist/{ios-device-CKSvk0bu.mjs → ios-device-C_QkIf1Z.mjs} +3 -3
  74. package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
  75. package/dist/{ios-project-DCUDo06I.mjs → ios-project-D8Jcy_br.mjs} +22 -9
  76. package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
  77. package/dist/{ios-state-CT9nV5SP.mjs → ios-state-BZ03NFgF.mjs} +1 -1
  78. package/dist/{js-swap-Z9HbC4cj.mjs → js-swap-Dg2a945i.mjs} +8 -7
  79. package/dist/{launch-D0lPvFFu.mjs → launch-CRyBeNsA.mjs} +53 -44
  80. package/dist/lightened-BCsdAGj_.mjs +171 -0
  81. package/dist/{logs-BsIRre8x.mjs → logs-CC_-ZzEE.mjs} +10 -174
  82. package/dist/{logs-Crs9y34Z.mjs → logs-aJQb-RDg.mjs} +112 -38
  83. package/dist/{macos-CcUlJPMu.mjs → macos-BGmTpnv9.mjs} +1 -1
  84. package/dist/{macos-D477nfzH.mjs → macos-DlCBhMw5.mjs} +73 -39
  85. package/dist/macos-run.mjs +1 -1
  86. package/dist/maintenance-run.mjs +30 -13
  87. package/dist/{metro-1pJgCX4U.mjs → metro-CvyD-xwe.mjs} +4 -4
  88. package/dist/{metro-gateway-Bp9gJQAN.mjs → metro-gateway-BnHdqMO_.mjs} +3 -4
  89. package/dist/{named-ports-BVbn8SvC.mjs → named-ports-BCyMWA6b.mjs} +3 -3
  90. package/dist/{native-android-BvMizJn1.mjs → native-android-DlpxCyOP.mjs} +17 -18
  91. package/dist/{native-gradle-artifact-inputs-BJscK4vN.mjs → native-gradle-artifact-inputs-C13qT7R_.mjs} +5 -5
  92. package/dist/{native-runtime-B9w_Qyz3.mjs → native-runtime-DqaIBO5w.mjs} +9 -9
  93. package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
  94. package/dist/{native-xcode-inputs-Cv4l-obn.mjs → native-xcode-inputs-B1W8SrxB.mjs} +3 -3
  95. package/dist/{native-xcode-ios-DGrg90hE.mjs → native-xcode-ios-QPP0Rm68.mjs} +17 -18
  96. package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
  97. package/dist/offload-worker.d.mts +3 -1
  98. package/dist/offload-worker.mjs +34 -25
  99. package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
  100. package/dist/{ownership-jxxz-19m.mjs → ownership-Bx-0cku-.mjs} +3 -3
  101. package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
  102. package/dist/{phone-reverses-CYb7RRAx.mjs → phone-reverses-C9yAaKEv.mjs} +18 -4
  103. package/dist/{placement-log-DjOXJRIH.mjs → placement-log-BXUbiZM6.mjs} +3 -3
  104. package/dist/{plan-placement-BqKgKHCi.mjs → plan-placement-UxnQjv5Z.mjs} +36 -10
  105. package/dist/{ports-DtS1Amb0.mjs → ports-uUrghqWN.mjs} +3 -3
  106. package/dist/prebuild-BDpToDgR.mjs +1246 -0
  107. package/dist/{project-BiC68mIp.mjs → project-DYj-HVx6.mjs} +17 -18
  108. package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
  109. package/dist/pull-requests.mjs +1 -1
  110. package/dist/{react-native-android-DRYqoJc4.mjs → react-native-android-DDBccgJw.mjs} +56 -36
  111. package/dist/{react-native-build-CwZB-agu.mjs → react-native-build-DaK2IFyP.mjs} +9 -9
  112. package/dist/{react-native-doctor-BCrytK7h.mjs → react-native-doctor-B-Mw6DcR.mjs} +50 -9
  113. package/dist/{react-native-ios-Cr1buNFo.mjs → react-native-ios-DjYwUF9U.mjs} +45 -25
  114. package/dist/{recordings-BaoQ0t-J.mjs → recordings-C20iUZfp.mjs} +1 -1
  115. package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
  116. package/dist/{reload-Beftw2X3.mjs → reload-DJBeF_rC.mjs} +1 -1
  117. package/dist/{reload-FbSgMF8x.mjs → reload-fUdkH2_p.mjs} +16 -16
  118. package/dist/{remote-BuZj6AyU.mjs → remote-y6n99WMW.mjs} +22 -9
  119. package/dist/{result-CR2vk2cj.mjs → result-CTqBw2Te.mjs} +32 -21
  120. package/dist/{run-BtzE09Dl.mjs → run-DaCeNKRm.mjs} +3 -3
  121. package/dist/{selection-D5cxEl3t.mjs → selection-Bs8phwhN.mjs} +183 -62
  122. package/dist/{server-bare-CH9X0RLn.mjs → server-bare-BOh-iZEj.mjs} +2 -2
  123. package/dist/{server-command-CaBbDNU2.mjs → server-command-8CuA51Cv.mjs} +6 -6
  124. package/dist/{server-expo-Ck8EIidM.mjs → server-expo-ABQs2XFA.mjs} +4 -4
  125. package/dist/server-expo-Ba_Y21vB.mjs +2 -0
  126. package/dist/{settings-B5tCoq9N.mjs → settings-BDVI8Ivc.mjs} +331 -62
  127. package/dist/{settings-DzH9mGQZ.mjs → settings-CMHhQNwI.mjs} +24 -3
  128. package/dist/settings-payload-cm60Zhib.mjs +257 -0
  129. package/dist/settings-write-BdNRLlBn.mjs +185 -0
  130. package/dist/settings.schema.json +84 -39
  131. package/dist/{simslim-BjxszUAb.mjs → simslim-DCQwzoPy.mjs} +4 -3
  132. package/dist/{slot-launch-QeuJMlnJ.mjs → slot-launch-0l7RqSpr.mjs} +6 -6
  133. package/dist/{stage-D8xlRU2D.mjs → stage-F4cAfJGi.mjs} +2 -2
  134. package/dist/{start-C1JLjkNw.mjs → start-DcqnF9p8.mjs} +1 -1
  135. package/dist/{start-YMpNwLhh.mjs → start-DrPwER_2.mjs} +27 -23
  136. package/dist/{state-DMRNP7-4.mjs → state-BX1y5syV.mjs} +4 -5
  137. package/dist/{state-DPaM3u5K.mjs → state-CZxLyetD.mjs} +2 -3
  138. package/dist/{stats-CP7STzZw.mjs → stats-GxuCbles.mjs} +5 -5
  139. package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
  140. package/dist/{status-Fect2w9R.mjs → status-7ULDEJ1e.mjs} +1 -1
  141. package/dist/{status-CRLiJ-O_.mjs → status-BfnK9pUd.mjs} +25 -26
  142. package/dist/{status-cNw6i0_t.mjs → status-Bj7ZYvvc.mjs} +1 -1
  143. package/dist/{status-watch-Bc2J4TZn.mjs → status-watch-BfabQn03.mjs} +5 -5
  144. package/dist/status-worker.mjs +1 -1
  145. package/dist/{stim-desktop-DS0mzR8U.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
  146. package/dist/{stop-COP6PQqw.mjs → stop-CH79S3IZ.mjs} +5 -6
  147. package/dist/{stop-Db9Kh-UA.mjs → stop-D-EAr25B.mjs} +25 -22
  148. package/dist/{stop-Br7LKxBE.mjs → stop-x1Yu3He4.mjs} +2 -2
  149. package/dist/supervisor-run.d.mts +1 -0
  150. package/dist/supervisor-run.mjs +17 -18
  151. package/dist/{support-qKcbgmI5.mjs → support-Be0UeVZU.mjs} +10 -10
  152. package/dist/{support-Cxj9CmII.mjs → support-CNg_YsOk.mjs} +6 -6
  153. package/dist/{swiftpm-artifact-inputs-iY9fsmOc.mjs → swiftpm-artifact-inputs-uPqYvGBv.mjs} +4 -4
  154. package/dist/{swiftpm-macos-Bp_sn9P4.mjs → swiftpm-macos-Ch4YjY_A.mjs} +11 -12
  155. package/dist/toolchain-CbCG6C5Z.mjs +2413 -0
  156. package/dist/toolchain-JYAOquPg.mjs +2 -0
  157. package/dist/{trigger-CBMe2YLH.mjs → trigger-DMou-X7j.mjs} +3 -3
  158. package/dist/trigger-qp2ji5wE.mjs +2 -0
  159. package/dist/{warm-progress-BV3ZPmcY.mjs → warm-progress-C0RsbngN.mjs} +731 -728
  160. package/dist/{web-B4Yjyt1G.mjs → web-Cq_AQ4DK.mjs} +9 -10
  161. package/dist/web-Je6abcpz.mjs +2 -0
  162. package/dist/web-run.mjs +9 -9
  163. package/dist/windows-report.mjs +1 -1
  164. package/dist/{workspace-state-CPSp3mav.mjs → workspace-state-BjqdjnJR.mjs} +46 -8
  165. package/dist/{workspaces-C9w4aeXF.mjs → workspaces-DFbj07jp.mjs} +1801 -76
  166. package/dist/{worktree-CclFIe1Z.mjs → worktree-COAJ3-OD.mjs} +934 -511
  167. package/dist/{worktree-Ct9Gk3KL.mjs → worktree-JGUd_53L.mjs} +1 -1
  168. package/package.json +8 -8
  169. package/dist/ccache-h1FKhZeg.mjs +0 -143
  170. package/dist/created-devices-D2Aca-xu.mjs +0 -52
  171. package/dist/eas-fallback-gaZi-dJL.mjs +0 -381
  172. package/dist/hosted-ios-RtVcJH3u.mjs +0 -15
  173. package/dist/native-run-D5OJsGwA.mjs +0 -276
  174. package/dist/paths-DQtTgsBf.mjs +0 -42
  175. package/dist/prebuild-JUaqOLpc.mjs +0 -501
  176. package/dist/server-expo-C16Zf2k7.mjs +0 -2
  177. package/dist/settings-write-n0zwfohx.mjs +0 -360
  178. package/dist/toolchain-DB1aeqxO.mjs +0 -2
  179. package/dist/toolchain-VzLJzZ7O.mjs +0 -908
  180. package/dist/trigger-BLsHgAGR.mjs +0 -2
  181. package/dist/web-DS4UDWvf.mjs +0 -2
  182. package/dist/xcode-CiIIDnuD.mjs +0 -910
@@ -1,11 +1,12 @@
1
- import { l as WorkspaceProcessCleanupError } from "./exec-VFRpu1iA.mjs";
2
- import { H as deviceSlotPlatforms } from "./config-BZhXY15H.mjs";
3
- import { l as phaseLine } from "./command-output-BBvS1H6v.mjs";
4
- import { I as parseIosRemote, U as remoteEasFallbackSetting, W as remoteIosSetting, it as tunnelModeSetting, z as publicUrlSetting } from "./settings-B5tCoq9N.mjs";
5
- import "./budget-HyShrIpL.mjs";
6
- import { b as resolveSimulatorAppFlag } from "./support-qKcbgmI5.mjs";
7
- import { n as devicePlacementRecord } from "./placement-log-DjOXJRIH.mjs";
8
- import { r as devicePlacementLine } from "./eas-fallback-gaZi-dJL.mjs";
1
+ import { l as WorkspaceProcessCleanupError } from "./exec-aULwtNly.mjs";
2
+ import { H as deviceSlotPlatforms } from "./config-Cn94Jc0g.mjs";
3
+ import { l as phaseLine } from "./command-output-Dj-WT4BP.mjs";
4
+ import { B as publicUrlSetting, G as remoteIosSetting, L as parseIosRemote, W as remoteEasFallbackSetting, ot as tunnelModeSetting } from "./settings-BDVI8Ivc.mjs";
5
+ import "./ccache-BWTze1Ls.mjs";
6
+ import { ot as runCancellationSignal } from "./toolchain-CbCG6C5Z.mjs";
7
+ import { b as resolveSimulatorAppFlag } from "./support-Be0UeVZU.mjs";
8
+ import { n as devicePlacementRecord } from "./placement-log-BXUbiZM6.mjs";
9
+ import { n as devicePlacementLine } from "./auto-placement-z-H5pJza.mjs";
9
10
  import chalk from "chalk";
10
11
  //#region src/commands/ios/remote.ts
11
12
  function deviceRemoteConflict(remote, physical) {
@@ -25,6 +26,7 @@ function resolveIosRemote({ opts, settings, physical, recorded }) {
25
26
  } };
26
27
  return {
27
28
  machine,
29
+ ...target?.kind === "machine" && target.placement ? { placement: target.placement } : {},
28
30
  backend: !physical && target?.kind === "backend" ? target.backend : null,
29
31
  recorded
30
32
  };
@@ -68,7 +70,8 @@ function selectIosTarget({ root, slot, opts, settings, physical, appMode, metroC
68
70
  async function selectIosPlacement(args) {
69
71
  const selection = selectIosTarget(args);
70
72
  if ("failure" in selection || selection.machine !== "auto") return selection;
71
- const { root, slot, d, opts, deviceType, runtime, noWait, phase, log, release, appMode, metroCheck } = args;
73
+ const { root, slot, d, opts, deviceType, runtime, noWait, waitMs, phase, log, release, appMode, metroCheck } = args;
74
+ const signal = runCancellationSignal(args.operation) ?? args.operation?.signal;
72
75
  const viewer = resolveSimulatorAppFlag(opts.simulatorApp, args.physical, null);
73
76
  if ("refusal" in viewer) return { failure: viewer.refusal };
74
77
  const refusal = await args.validateSelectors();
@@ -86,11 +89,15 @@ async function selectIosPlacement(args) {
86
89
  root,
87
90
  slot,
88
91
  platform: "ios",
92
+ placement: selection.placement,
89
93
  ...localSims ? { localSims } : {},
90
94
  selectors: hostedIosSelectors(deviceType, runtime),
91
95
  appMode,
92
96
  buildMachine: opts.remoteBuild,
93
97
  noWait,
98
+ ...waitMs === void 0 ? {} : { waitMs },
99
+ onWait: (line) => phase("placement:", line),
100
+ signal,
94
101
  ...easFallback ? { eas: () => d.checkEasFallback({
95
102
  root,
96
103
  platform: "ios",
@@ -108,6 +115,7 @@ async function selectIosPlacement(args) {
108
115
  phase("placement:", devicePlacementLine(placed.placement, placed.skipped));
109
116
  log?.(devicePlacementRecord({
110
117
  platform: "ios",
118
+ selected: selection.placement,
111
119
  fromFlag: opts.remote !== void 0,
112
120
  easFallback,
113
121
  placed
@@ -137,6 +145,11 @@ async function selectIosPlacement(args) {
137
145
  devicePlacement: placed.placement
138
146
  };
139
147
  } catch (error) {
148
+ if (signal?.aborted) return { failure: {
149
+ code: "STIM_CANCELLED",
150
+ message: "The run was cancelled while it waited for a remote machine.",
151
+ remedy: "Run the command again when you want the app on a device."
152
+ } };
140
153
  return { failure: {
141
154
  code: error.code ?? "STIM_HOSTING_REFUSED",
142
155
  message: error.message,
@@ -1,20 +1,20 @@
1
- import { l as workspaceAgentDeviceDir } from "./paths-DQtTgsBf.mjs";
2
- import { H as deviceSlotPlatforms, p as getProject } from "./config-BZhXY15H.mjs";
3
- import { i as formatDuration, l as phaseLine } from "./command-output-BBvS1H6v.mjs";
4
- import { G as resolveAndroidLayout, H as remoteAndroidSetting, I as parseIosRemote, K as resolveCacheProviderConfig, Q as settingFile, a as SETTING_SHAPE_REMEDY, at as unknownSettingKeys, d as androidLayoutSetting, et as settingOriginScope, f as androidLayoutSettingError, p as cacheProviderSettingError, rt as settingsLayers, s as androidAvdConfigSettingError, tt as settingShapeErrors, u as androidDataPartitionSizeGbSettingError } from "./settings-B5tCoq9N.mjs";
5
- import { v as detectIsExpo } from "./project-BiC68mIp.mjs";
6
- import { a as workspaceLinkLine } from "./stim-desktop-DS0mzR8U.mjs";
7
- import { B as ownedAvdDeviceProfile, I as listInstalledSystemImages, K as ownedAvdSystemImage, N as listAvdDeviceProfilesAsync, Q as profileNeedsFoldFeature, X as pickDefaultSystemImage, at as systemImageSupportsFold, k as hostSystemImageArch, l as androidSystemImageAbi, t as DEFAULT_AVD_DEVICE_PROFILE, vt as parkedMaxSetting } from "./android-Cjcj8MCw.mjs";
8
- import { B as recordFinishedBuild, Gn as isEasAuthFailureText, Hn as cacheLevel, Vn as UPLOAD_TIMEOUT_MS, Wn as easAuthNote } from "./budget-HyShrIpL.mjs";
1
+ import { w as workspaceAgentDeviceDir } from "./workspace-state-BjqdjnJR.mjs";
2
+ import { H as deviceSlotPlatforms, p as getProject } from "./config-Cn94Jc0g.mjs";
3
+ import { i as formatDuration, l as phaseLine } from "./command-output-Dj-WT4BP.mjs";
4
+ import { J as resolveCacheProviderConfig, L as parseIosRemote, U as remoteAndroidSetting, _ as inertSettingWarning, a as SETTING_SHAPE_REMEDY, at as settingsLayers, d as androidLayoutSetting, et as settingFile, f as androidLayoutSettingError, nt as settingOriginScope, p as cacheProviderSettingError, q as resolveAndroidLayout, rt as settingShapeErrors, s as androidAvdConfigSettingError, st as unknownSettingKeys, u as androidDataPartitionSizeGbSettingError } from "./settings-BDVI8Ivc.mjs";
5
+ import { v as detectIsExpo } from "./project-DYj-HVx6.mjs";
6
+ import { a as workspaceLinkLine } from "./stim-desktop-CbWo21kb.mjs";
7
+ import { B as ownedAvdDeviceProfile, I as listInstalledSystemImages, K as ownedAvdSystemImage, N as listAvdDeviceProfilesAsync, Q as profileNeedsFoldFeature, X as pickDefaultSystemImage, at as systemImageSupportsFold, k as hostSystemImageArch, l as androidSystemImageAbi, t as DEFAULT_AVD_DEVICE_PROFILE, vt as parkedMaxSetting } from "./android-DriNoAVy.mjs";
8
+ import { Mn as isEasAuthFailureText, On as UPLOAD_TIMEOUT_MS, jn as easAuthNote, kn as cacheLevel, n as CCACHE_UNAVAILABLE, r as ccacheActivityLine } from "./ccache-BWTze1Ls.mjs";
9
+ import { q as recordFinishedBuild } from "./workspaces-DFbj07jp.mjs";
9
10
  import { d as optimizationBuildProfile, l as artifactCachePolicy, p as resolveOptimizations, u as compilerCacheFallbackMessage } from "./errors-DHm_U5gv.mjs";
10
- import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine } from "./ccache-h1FKhZeg.mjs";
11
- import { n as buildPlacementCandidates } from "./client-BQsmyp_-.mjs";
12
- import { c as readProductFlavors, s as productFlavorRefusal } from "./react-native-build-CwZB-agu.mjs";
13
- import { l as parseDeviceWait } from "./device-lease-run-ogEeJ62K.mjs";
14
- import { t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-ZYaRALv5.mjs";
15
- import { n as resolveAndroidCas, r as resolveAndroidCompilerCache } from "./android-cas-BVqh2Zep.mjs";
16
- import { r as isPhysicalDeviceRequest } from "./native-runtime-B9w_Qyz3.mjs";
17
- import { C as remoteAvdFlagRefusal, D as systemImageRefusal, E as resolveVariant, T as resolveSystemImage, a as PLATFORM, m as deviceProfileRefusal, v as foldableImageRefusal, w as resolveDeviceProfile, y as isReleaseVariant } from "./support-Cxj9CmII.mjs";
11
+ import { n as buildPlacementCandidates } from "./client-xsdxrhWA.mjs";
12
+ import { c as readProductFlavors, s as productFlavorRefusal } from "./react-native-build-DaK2IFyP.mjs";
13
+ import { l as parseDeviceWait } from "./device-lease-run-DwsGfjUN.mjs";
14
+ import { t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-6LP7QsaA.mjs";
15
+ import { n as resolveAndroidCas, r as resolveAndroidCompilerCache } from "./android-cas-D5e6ecUg.mjs";
16
+ import { r as isPhysicalDeviceRequest } from "./native-runtime-DqaIBO5w.mjs";
17
+ import { C as remoteAvdFlagRefusal, D as systemImageRefusal, E as resolveVariant, T as resolveSystemImage, a as PLATFORM, m as deviceProfileRefusal, v as foldableImageRefusal, w as resolveDeviceProfile, y as isReleaseVariant } from "./support-CNg_YsOk.mjs";
18
18
  import { buildDiagnostics } from "@stim-cli/core/state";
19
19
  import chalk from "chalk";
20
20
  //#region src/commands/android/plan.ts
@@ -83,7 +83,7 @@ function resolveAndroidBuildPlan({ settings, settingsContext, env, easProfile, v
83
83
  const layoutError = androidLayoutError(settings, root, bound, detectExpo);
84
84
  if (layoutError) return fail("STIM_BAD_ARG", layoutError, SETTING_SHAPE_REMEDY);
85
85
  const layout = resolveAndroidLayout(settings, root, bound);
86
- for (const key of unknownSettingKeys(settings)) warn("setting", `Warning: setting "${key}" is not read by Stim and will be ignored.`);
86
+ for (const key of unknownSettingKeys(settings)) warn("setting", inertSettingWarning(settings, key));
87
87
  let optimizations;
88
88
  try {
89
89
  optimizations = resolveOptimizations(settings, env);
@@ -197,6 +197,7 @@ async function resolveAndroidRunPlan({ settings, settingsContext, env, slot, sig
197
197
  } : machine ? {
198
198
  kind: "hosted",
199
199
  machine,
200
+ ...remoteTarget?.kind === "machine" && remoteTarget.placement ? { placement: remoteTarget.placement } : {},
200
201
  systemImage,
201
202
  deviceProfile
202
203
  } : remoteBackend ? {
@@ -308,7 +309,7 @@ function androidFacts({ root, slot, serial, avdName = null, deviceName = null, s
308
309
  ...devServer ? { devServer } : {}
309
310
  };
310
311
  }
311
- function lastBuildRecord({ devicePlacement, fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null, diagnostics = null, configuration = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
312
+ function lastBuildRecord({ devicePlacement, fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null, diagnostics = null, configuration = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null, message = null, remedy = null, deviceSerial = null }) {
312
313
  const record = {
313
314
  platform: PLATFORM,
314
315
  avdName: avdName ?? null,
@@ -333,6 +334,13 @@ function lastBuildRecord({ devicePlacement, fingerprint, cacheKey, cacheHit, cac
333
334
  if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
334
335
  const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
335
336
  if (recorded.length) record.diagnostics = recorded;
337
+ const device = deviceName ?? avdName;
338
+ const ledger = {
339
+ ...device && device !== deviceSerial ? { device: { name: device } } : {},
340
+ ...message ? { message } : {},
341
+ ...remedy ? { remedy } : {}
342
+ };
343
+ if (Object.keys(ledger).length) record.ledger = ledger;
336
344
  return record;
337
345
  }
338
346
  async function finishAndroidUpload(uploadPending, remote, phase) {
@@ -426,14 +434,16 @@ function cacheOutcome(cacheHit, providerName = null, offloadedTo = null) {
426
434
  if (cacheHit === "local") return "cache hit";
427
435
  return offloadedTo ? `built on ${offloadedTo}` : "built";
428
436
  }
429
- function persistLastBuild({ recordBuild = recordFinishedBuild, root, record, startedAt, durationMs, status, errorCode = null, diagnostics = null, out }) {
437
+ function persistLastBuild({ recordBuild = recordFinishedBuild, root, record, startedAt, durationMs, status, errorCode = null, diagnostics = null, message = null, remedy = null, out }) {
430
438
  const lastBuild = lastBuildRecord({
431
439
  ...record,
432
440
  startedAt,
433
441
  durationMs,
434
442
  status,
435
443
  errorCode,
436
- diagnostics
444
+ diagnostics,
445
+ message,
446
+ remedy
437
447
  });
438
448
  try {
439
449
  recordBuild(root, lastBuild);
@@ -451,7 +461,8 @@ function persistThrownBuild({ acquired, error, ...args }) {
451
461
  persistLastBuild({
452
462
  ...args,
453
463
  status: "failed",
454
- errorCode: typeof code === "string" ? code : void 0
464
+ errorCode: typeof code === "string" ? code : void 0,
465
+ message: error instanceof Error ? error.message : String(error)
455
466
  });
456
467
  }
457
468
  //#endregion
@@ -1,6 +1,6 @@
1
- import { D as ownership_claim_exports, S as process_identity_exports, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { a as macosRuntimeClaim, i as macosProcess, r as macosLogFile, s as updateMacosRecord } from "./state-DPaM3u5K.mjs";
3
- import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
1
+ import { D as ownership_claim_exports, S as process_identity_exports, t as getExecutor } from "./exec-aULwtNly.mjs";
2
+ import { a as macosRuntimeClaim, i as macosProcess, r as macosLogFile, s as updateMacosRecord } from "./state-CZxLyetD.mjs";
3
+ import { i as createNdjsonWriter } from "./ndjson-Dy2W4vRa.mjs";
4
4
  import { LOG_ROTATE_BYTES } from "@stim-cli/core";
5
5
  import { readMacosRecord } from "@stim-cli/core/state";
6
6
  import { StringDecoder } from "node:string_decoder";
@@ -1,11 +1,12 @@
1
- import { C as reportSignal, b as operationState } from "./exec-VFRpu1iA.mjs";
2
- import { v as withDirLock$1 } from "./paths-DQtTgsBf.mjs";
3
- import { $ as outdatedServer, X as endpoint, Z as findPeer$1, _ as loadConfig$1, at as setupRemedy, d as getConfigDir, et as parseMachine$1, nt as realIo, ot as tailscaleStatusAsync, st as readHostPermissions, tt as reachMachine } from "./config-BZhXY15H.mjs";
1
+ import { C as reportSignal, b as operationState } from "./exec-aULwtNly.mjs";
2
+ import { M as withDirLock$1 } from "./workspace-state-BjqdjnJR.mjs";
3
+ import { $ as endpoint$1, X as diagnoseOutcome, Z as diagnoseTailscale, _ as loadConfig$1, at as realIo, ct as setupRemedy, d as getConfigDir, dt as notOnTailnetDiagnosis, et as findPeer$1, ft as readHostPermissions, it as reachMachine, lt as tailscaleStatusAsync, nt as outdatedServer, rt as parseMachine$1, ut as diagnosisFinding } from "./config-Cn94Jc0g.mjs";
4
+ import { o as cocoapodsInstall } from "./toolchain-CbCG6C5Z.mjs";
4
5
  import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
5
6
  import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
6
7
  import { hostname } from "node:os";
7
8
  import { ambientContext, ambientEnv, withDirLockAsync } from "@stim-cli/core";
8
- import { MACHINE_CREDENTIALS_VERSION, OFFLOAD_MODES, acceptsShape, automaticMachineEnabled, buildMachinesFile, buildMachinesLock, cannotHost, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, isJsonObject, parseMachine, readBuildMachines, readDeviceHostMachines, settingDefinition } from "@stim-cli/core/state";
9
+ import { MACHINE_CREDENTIALS_VERSION, acceptsShape, automaticMachineEnabled, buildMachinesFile, buildMachinesLock, cannotHost, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, isJsonObject, parseMachine, placementWord, readBuildMachines, readDeviceHostMachines, settingDefinition } from "@stim-cli/core/state";
9
10
  import { InvalidArgumentError } from "commander";
10
11
  //#region src/device-host/machines.ts
11
12
  function note$1(title, detail, fix = null) {
@@ -126,7 +127,17 @@ async function inspectDeviceHostMachines({ fix, version = "<version>", tickets =
126
127
  machines: []
127
128
  };
128
129
  const status = await io.status();
129
- if (!isJsonObject(status)) return unavailable("tailscale-off", note$1("Remote machines are unreachable", "remote.machines names remote machines, but Tailscale is not running."));
130
+ if (!isJsonObject(status)) {
131
+ const diagnosis = await diagnoseTailscale(io);
132
+ return {
133
+ findings: [note$1("Remote machines are unreachable", `remote.machines names remote machines. ${diagnosis.message}`, diagnosis.remedy)],
134
+ machines: entries.map((machine) => ({
135
+ machine,
136
+ state: "tailscale-off",
137
+ diagnosis
138
+ }))
139
+ };
140
+ }
130
141
  const self = isJsonObject(status.Self) ? status.Self : {};
131
142
  const deviceName = (typeof self.HostName === "string" && self.HostName ? self.HostName : hostname()).replace(/[\p{Cc}\p{Cf}]/gu, "").trim().slice(0, 64) || "Mac";
132
143
  const inspected = {
@@ -146,20 +157,24 @@ async function inspectDeviceHostMachines({ fix, version = "<version>", tickets =
146
157
  }
147
158
  const current = await io.status();
148
159
  if (!isJsonObject(current)) {
160
+ const diagnosis = await diagnoseTailscale(io);
149
161
  inspected.machines.push({
150
162
  machine,
151
- state: "tailscale-off"
163
+ state: "tailscale-off",
164
+ diagnosis
152
165
  });
153
- inspected.findings.push(note$1(`Remote machine ${machine} is unreachable`, "Tailscale stopped before this connection."));
166
+ inspected.findings.push(diagnosisFinding("device-host-machine", machine, diagnosis));
154
167
  continue;
155
168
  }
156
169
  const peer = findPeer$1(current, parsed.name);
157
170
  if (peer === "missing" || peer === "ambiguous") {
171
+ const diagnosis = notOnTailnetDiagnosis(machine, peer === "ambiguous");
158
172
  inspected.machines.push({
159
173
  machine,
160
- state: "not-on-tailnet"
174
+ state: "not-on-tailnet",
175
+ diagnosis
161
176
  });
162
- inspected.findings.push(note$1(`Remote machine ${machine} is not on this tailnet`, peer === "missing" ? "No peer has that name." : "Several peers match that name."));
177
+ inspected.findings.push(diagnosisFinding("device-host-machine", machine, diagnosis));
163
178
  continue;
164
179
  }
165
180
  const nodeRoute = `${peer.nodeId}:${parsed.port}`;
@@ -186,7 +201,7 @@ async function inspectDeviceHostMachines({ fix, version = "<version>", tickets =
186
201
  const outcome = await reachMachine({
187
202
  machine,
188
203
  access: "device-host",
189
- endpoint: endpoint(peer, parsed.port),
204
+ endpoint: endpoint$1(peer, parsed.port),
190
205
  address: peer.dnsName,
191
206
  credential,
192
207
  other: () => readBuildMachines().find((each) => each.machine === machine),
@@ -251,16 +266,40 @@ async function inspectDeviceHostMachines({ fix, version = "<version>", tickets =
251
266
  const outdated = outdatedServer(machine, version, outcome.command);
252
267
  inspected.machines.push({
253
268
  ...known,
254
- state: "outdated"
269
+ state: "outdated",
270
+ diagnosis: {
271
+ layer: "compat",
272
+ code: "server-outdated",
273
+ title: "Server is outdated",
274
+ message: outdated.detail,
275
+ remedy: outdated.fix
276
+ }
255
277
  });
256
278
  inspected.findings.push(note$1(outdated.title, outdated.detail, outdated.fix));
257
279
  continue;
258
280
  }
281
+ if (outcome.state === "unreachable") {
282
+ const diagnosis = await diagnoseOutcome(io, {
283
+ entry: machine,
284
+ peer,
285
+ port: parsed.port,
286
+ target: endpoint$1(peer, parsed.port),
287
+ reason: outcome.reason,
288
+ transport: outcome.transport
289
+ });
290
+ inspected.machines.push({
291
+ ...known,
292
+ state: "unreachable",
293
+ diagnosis
294
+ });
295
+ inspected.findings.push(diagnosisFinding("device-host-machine", machine, diagnosis));
296
+ continue;
297
+ }
259
298
  inspected.machines.push({
260
299
  ...known,
261
300
  state: outcome.state
262
301
  });
263
- inspected.findings.push(outcome.state === "key-changed" ? note$1(`Remote machine ${machine} answered with a different server key`, "Stim refuses to connect to a stim-server that does not prove it holds the key pinned at approval.", `If that machine or its Stim home was replaced, remove ${machine} from remote.machines, run \`stim doctor --fix\`, then add it back and run \`stim doctor --fix\` again.`) : outcome.state === "lapsed" ? note$1(`Hosting request to ${machine} lapsed`, `${machine} did not approve this machine before its setup ticket expired at ${outcome.credential.expiresAt}.`, "Run `stim doctor --fix` to make a new ticket.") : outcome.state === "revoked" ? note$1(`Remote machine ${machine} no longer accepts this machine for device hosting`, `${outcome.reason} The pinned key is preserved.`, "Run `stim doctor --fix` to ask again.") : note$1(`Remote machine ${machine} did not confirm hosting access`, outcome.reason, `Check stim-server and its tailnet serve route on ${machine}, then run doctor again.`));
302
+ inspected.findings.push(outcome.state === "key-changed" ? note$1(`Remote machine ${machine} answered with a different server key`, "Stim refuses to connect to a stim-server that does not prove it holds the key pinned at approval.", `If that machine or its Stim home was replaced, remove ${machine} from remote.machines, run \`stim doctor --fix\`, then add it back and run \`stim doctor --fix\` again.`) : outcome.state === "lapsed" ? note$1(`Hosting request to ${machine} lapsed`, `${machine} did not approve this machine before its setup ticket expired at ${outcome.credential.expiresAt}.`, "Run `stim doctor --fix` to make a new ticket.") : note$1(`Remote machine ${machine} no longer accepts this machine for device hosting`, `${outcome.reason} The pinned key is preserved.`, "Run `stim doctor --fix` to ask again."));
264
303
  }
265
304
  return inspected;
266
305
  } finally {
@@ -317,7 +356,7 @@ const PROBLEM_TITLES = {
317
356
  xcode: "has another Xcode",
318
357
  "macos-sdk": "has another macOS SDK",
319
358
  "simulator-sdk": "has another simulator SDK",
320
- cocoapods: "has another CocoaPods",
359
+ cocoapods: "has no CocoaPods, or another version",
321
360
  bundler: "has no Bundler",
322
361
  runtime: "has no simulator for this project's iOS runtime",
323
362
  jdk: "runs another JDK major version",
@@ -329,7 +368,17 @@ const PROBLEM_TITLES = {
329
368
  busy: "is too busy to take builds",
330
369
  platform: "cannot build this platform"
331
370
  };
332
- function problemFix(code, entry) {
371
+ const NOTE_TITLES = {
372
+ ndk: "downloads this project's NDK on its first Android build",
373
+ "build-tools": "downloads this project's Android build-tools on its first Android build",
374
+ "compile-sdk": "downloads this project's Android compile platform on its first Android build"
375
+ };
376
+ function commandFix(problem, entry) {
377
+ return problem.commands?.length && problem.lead ? [`On ${entry}, ${problem.lead}:`, ...problem.commands].join("\n") : null;
378
+ }
379
+ function problemFix(problem, entry) {
380
+ const { code } = problem;
381
+ if (problem.followsFrom) return `Fix the ${problem.followsFrom} problem on ${entry} first; this follows from it.`;
333
382
  switch (code) {
334
383
  case "unreachable": return `Check that stim-server runs on ${entry} and that its tailscale serve route answers, then run \`stim doctor\` again. To keep it running there, run \`stim-server service install --serve\` on ${entry}.`;
335
384
  case "checkout": return "Offload syncs the files git lists; run Stim from a git checkout of the app.";
@@ -337,29 +386,53 @@ function problemFix(code, entry) {
337
386
  case "arch": return "Use a remote machine with the same CPU architecture as this machine.";
338
387
  case "xcode":
339
388
  case "simulator-sdk":
340
- case "macos-sdk": return `Install and select the same Xcode on ${entry} and this Mac (\`xcode-select -p\` on each).`;
341
- case "cocoapods": return `Install the same CocoaPods version on ${entry}, on the PATH its stim-server's login shell sets.`;
389
+ case "macos-sdk": return commandFix(problem, entry) ?? `Install and select the same Xcode on ${entry} and this Mac (\`xcode-select -p\` on each).`;
390
+ case "cocoapods": return commandFix(problem, entry) ?? `Install the same CocoaPods version on ${entry}, on the PATH its stim-server sets. A build sent there with --remote-build ${entry} still runs; a version that differs rewrites the COCOAPODS line of a committed Podfile.lock.`;
342
391
  case "bundler": return `Install Bundler (\`gem install bundler\`) on ${entry}, on the PATH its stim-server's login shell sets.`;
343
- case "runtime": return `Install that iOS simulator runtime on ${entry} with at least one iPhone simulator, or set ios.runtime here to one ${entry} has.`;
344
- case "jdk": return `Start stim-server on ${entry} with JAVA_HOME at a JDK of the same major version as this machine's.`;
392
+ case "runtime": return commandFix(problem, entry) ?? `Install that iOS simulator runtime on ${entry} with at least one iPhone simulator, or set ios.runtime here to one ${entry} has.`;
393
+ case "jdk": return commandFix(problem, entry) ?? `Start stim-server on ${entry} with JAVA_HOME at a JDK of the same major version as this machine's.`;
345
394
  case "android-sdk":
346
395
  case "ndk":
347
396
  case "build-tools":
348
- case "compile-sdk": return `Install the missing package with sdkmanager in the Android SDK stim-server on ${entry} uses (its ANDROID_HOME, else ~/Library/Android/sdk on macOS or ~/Android/Sdk on Linux).`;
397
+ case "compile-sdk": return commandFix(problem, entry) ?? `Install the missing package with sdkmanager in the Android SDK stim-server on ${entry} uses (its ANDROID_HOME, else ~/Library/Android/sdk on macOS or ~/Android/Sdk on Linux).`;
349
398
  case "disk": return `Free space on ${entry}'s worker root (server.workerRoot there).`;
350
399
  case "platform": return `iOS and macOS builds need a Mac; ${entry} can take Android builds only.`;
351
400
  case "busy": return `Builds stay on this machine until ${entry} has capacity. On ${entry}, server.maxLoadPerCore sets the load it accepts and concurrency.maxBuilds how many of its own builds it runs; it takes one offloaded build at a time.`;
352
401
  }
353
402
  }
354
403
  const TRANSIENT = /* @__PURE__ */ new Set(["unreachable", "busy"]);
355
- function offloadFindings(entry, problems) {
356
- return problems.map((problem) => ({
404
+ const UNPREDICTABLE = /* @__PURE__ */ new Set([
405
+ "unreachable",
406
+ "busy",
407
+ "disk",
408
+ "checkout",
409
+ "cocoapods"
410
+ ]);
411
+ /** Why a build on the machine named for it cannot work, from the toolchain differences found before this machine changes the checkout. */
412
+ function predictedRefusal(entry, problems) {
413
+ const known = problems.filter((problem) => !UNPREDICTABLE.has(problem.code));
414
+ if (known.length === 0) return null;
415
+ return {
416
+ reason: known.map((problem) => problem.reason).join("; "),
417
+ remedy: known.map((problem) => problemFix(problem, entry)).join("\n")
418
+ };
419
+ }
420
+ function offloadFindings(entry, problems, notes, operation) {
421
+ const selected = operation?.env.STIM_REMOTE_BUILD?.trim() || loadConfig$1()?.remote?.build;
422
+ const consequence = typeof selected === "string" && placementWord(selected) === "remote-only" ? "remote.build is remote-only, so automatic builds skip this machine and refuse rather than build on this Mac:" : "Builds fall back to this machine:";
423
+ return [...problems.map((problem) => ({
357
424
  code: `build-machine-${problem.code}`,
358
425
  level: TRANSIENT.has(problem.code) ? "note" : "cost",
359
426
  title: `Remote machine ${entry} ${PROBLEM_TITLES[problem.code]}`,
360
- detail: `Builds fall back to this machine: ${problem.reason}.`,
361
- fix: problemFix(problem.code, entry)
362
- }));
427
+ detail: `${consequence} ${problem.reason}.${problem.code === "cocoapods" ? ` A build sent there with --remote-build ${entry} still runs.` : ""}`,
428
+ fix: problemFix(problem, entry)
429
+ })), ...notes.map((each) => ({
430
+ code: `build-machine-${each.code}`,
431
+ level: "note",
432
+ title: `Remote machine ${entry} ${NOTE_TITLES[each.code] ?? "needs a first-build download"}`,
433
+ detail: `The build goes there anyway: ${each.reason}.`,
434
+ fix: commandFix(each, entry)
435
+ }))];
363
436
  }
364
437
  async function inspectMachine(entry, status, deviceName, fix, version, tickets, io, check, operation) {
365
438
  const parsed = parseMachine$1(entry);
@@ -372,13 +445,14 @@ async function inspectMachine(entry, status, deviceName, fix, version, tickets,
372
445
  };
373
446
  const peer = findPeer$1(status, parsed.name);
374
447
  if (peer === "missing" || peer === "ambiguous") {
375
- const detail = peer === "missing" ? "No peer on this tailnet has that name." : "Several peers match that name.";
448
+ const diagnosis = notOnTailnetDiagnosis(entry, peer === "ambiguous");
376
449
  return {
377
450
  report: {
378
451
  machine: entry,
379
- state: "not-on-tailnet"
452
+ state: "not-on-tailnet",
453
+ diagnosis
380
454
  },
381
- finding: note(`Remote machine ${entry} is not on this tailnet`, detail)
455
+ finding: diagnosisFinding("build-machine", entry, diagnosis)
382
456
  };
383
457
  }
384
458
  const credential = readBuildMachines().find((each) => each.machine === entry);
@@ -394,7 +468,7 @@ async function inspectMachine(entry, status, deviceName, fix, version, tickets,
394
468
  const outcome = await reachMachine({
395
469
  machine: entry,
396
470
  access: "build",
397
- endpoint: endpoint(peer, parsed.port),
471
+ endpoint: endpoint$1(peer, parsed.port),
398
472
  address: peer.dnsName,
399
473
  credential,
400
474
  other,
@@ -459,21 +533,40 @@ async function inspectMachine(entry, status, deviceName, fix, version, tickets,
459
533
  };
460
534
  case "outdated": {
461
535
  const outdated = outdatedServer(entry, version, outcome.command);
536
+ const diagnosis = {
537
+ layer: "compat",
538
+ code: "server-outdated",
539
+ title: "Server is outdated",
540
+ message: outdated.detail,
541
+ remedy: outdated.fix
542
+ };
462
543
  return {
463
544
  report: {
464
545
  ...paired,
465
- state: "outdated"
546
+ state: "outdated",
547
+ diagnosis
466
548
  },
467
549
  finding: note(outdated.title, outdated.detail, outdated.fix)
468
550
  };
469
551
  }
470
- case "unreachable": return {
471
- report: {
472
- ...paired,
473
- state: "unreachable"
474
- },
475
- finding: note(`Could not reach remote machine ${entry}`, outcome.reason, `Check that stim-server runs on ${entry}. To keep it running there, run \`stim-server service install --serve\` on ${entry}.`)
476
- };
552
+ case "unreachable": {
553
+ const diagnosis = await diagnoseOutcome(io, {
554
+ entry,
555
+ peer,
556
+ port: parsed.port,
557
+ target: endpoint$1(peer, parsed.port),
558
+ reason: outcome.reason,
559
+ transport: outcome.transport
560
+ });
561
+ return {
562
+ report: {
563
+ ...paired,
564
+ state: "unreachable",
565
+ diagnosis
566
+ },
567
+ finding: diagnosisFinding("build-machine", entry, diagnosis)
568
+ };
569
+ }
477
570
  }
478
571
  const permissions = readHostPermissions(outcome.result.host);
479
572
  const host = permissions ? { host: permissions } : {};
@@ -485,7 +578,7 @@ async function inspectMachine(entry, status, deviceName, fix, version, tickets,
485
578
  },
486
579
  finding: null
487
580
  };
488
- const { capacity, problems } = await check(outcome.credential);
581
+ const { capacity, problems, notes = [] } = await check(outcome.credential);
489
582
  return {
490
583
  report: {
491
584
  ...paired,
@@ -494,10 +587,11 @@ async function inspectMachine(entry, status, deviceName, fix, version, tickets,
494
587
  offloadable: problems.length === 0,
495
588
  reasons: problems.map((problem) => problem.reason),
496
589
  problems,
590
+ ...notes.length ? { notes } : {},
497
591
  ...capacity ? { capacity } : {}
498
592
  },
499
593
  finding: null,
500
- extra: offloadFindings(entry, problems)
594
+ extra: offloadFindings(entry, problems, notes, operation)
501
595
  };
502
596
  }
503
597
  /**
@@ -519,13 +613,17 @@ async function inspectBuildMachines({ fix, check = null, version = "<version>",
519
613
  machines: []
520
614
  };
521
615
  const status = await io.status();
522
- if (!isJsonObject(status)) return {
523
- findings: [note("Remote machines are unreachable", "remote.machines names remote machines, but Tailscale is not running.")],
524
- machines: entries.map((machine) => ({
525
- machine,
526
- state: "tailscale-off"
527
- }))
528
- };
616
+ if (!isJsonObject(status)) {
617
+ const diagnosis = await diagnoseTailscale(io);
618
+ return {
619
+ findings: [note("Remote machines are unreachable", `remote.machines names remote machines. ${diagnosis.message}`, diagnosis.remedy)],
620
+ machines: entries.map((machine) => ({
621
+ machine,
622
+ state: "tailscale-off",
623
+ diagnosis
624
+ }))
625
+ };
626
+ }
529
627
  const self = isJsonObject(status.Self) ? status.Self : {};
530
628
  const deviceName = (typeof self.HostName === "string" && self.HostName ? self.HostName : hostname()).replace(/[\p{Cc}\p{Cf}]/gu, "").trim().slice(0, 64) || "Mac";
531
629
  const inspection = {
@@ -547,20 +645,42 @@ const FINGERPRINT_MISMATCH_REMEDY = "The build Mac fingerprints the synced check
547
645
  function fingerprintMismatchRemedy(reason) {
548
646
  return reason.startsWith("fingerprint-mismatch: the checkout there ") ? FINGERPRINT_MISMATCH_REMEDY : void 0;
549
647
  }
648
+ const MISSING_PACKAGE_MANAGER = /^deps-failed: spawn (pnpm|yarn|npm) ENOENT/;
649
+ /** The remedy for a worker whose dependency install could not start its package manager; undefined for any other reason. */
650
+ function missingPackageManagerRemedy(machine, reason) {
651
+ const tool = MISSING_PACKAGE_MANAGER.exec(reason)?.[1];
652
+ if (!tool) return void 0;
653
+ return `${machine} has no ${tool} on the PATH of its stim-server service, and the app's lockfile needs it. ${tool === "npm" ? "Reinstall Node there, which ships npm" : `Install it with \`corepack enable ${tool}\` or \`npm install --global ${tool}\`, using sudo where Node is installed system-wide`}, then run the same command again, or rerun with --remote-build auto or --remote-build local.`;
654
+ }
655
+ const PODS_FAILED_PREFIX = "pod install failed: ";
656
+ /** The reason a failed worker job is reported with: a `pods-failed` code reads as a failed pod install. */
657
+ function workerFailureReason(code, message) {
658
+ return code === "pods-failed" ? `${PODS_FAILED_PREFIX}${String(message ?? "")}` : `${String(code ?? "failed")}: ${String(message ?? "")}`;
659
+ }
660
+ /** The remedy for a worker whose `pod install` failed, naming the install when it has no CocoaPods; undefined for any other reason. */
661
+ function podsFailedRemedy(machine, reason, localCocoapods) {
662
+ if (!reason.startsWith(PODS_FAILED_PREFIX)) return void 0;
663
+ const retry = "run the same command again, or rerun with --remote-build auto or --remote-build local";
664
+ if (!reason.includes("CocoaPods is not installed: no `pod` executable on PATH.")) return `Fix the pod install error on ${machine} (run pod install in its checkout under server.workerRoot there to see all of it), then ${retry}.`;
665
+ const { lead, commands } = cocoapodsInstall(localCocoapods);
666
+ return [
667
+ `On ${machine}, ${lead}:`,
668
+ ...commands,
669
+ `Then ${retry}.`
670
+ ].join("\n");
671
+ }
550
672
  var OffloadRefusal = class extends Error {
551
673
  code = "STIM_OFFLOAD_REFUSED";
552
674
  remedy;
553
- constructor(machine, reason, remedy = "Run stim doctor --fix to ask for build access if not paired; it prints the stim-server setup command a person runs on the worker to approve this machine. Check stim settings get remote.machines, or rerun with --remote-build auto or --remote-build local.") {
675
+ constructor(machine, reason, remedy = "Run stim doctor --fix to ask for build access if not paired; it prints the stim-server setup command a person runs on the worker to approve this machine. Check stim settings get remote.machines, or rerun with --remote-build auto, remote or local.") {
554
676
  super(reason.startsWith(`${machine}: `) ? reason : `${machine}: ${reason}`);
555
677
  this.remedy = remedy;
556
678
  }
557
679
  };
558
680
  function resolveBuildMachine(flag, env, setting) {
559
681
  const selected = flag ?? (env?.trim() || void 0) ?? setting ?? "auto";
560
- if (typeof selected !== "string" || !selected.trim() || !parseMachine(selected)) throw Object.assign(/* @__PURE__ */ new Error("--remote-build / remote.build must be auto, local, or a tailnet machine name."), { code: "STIM_BAD_ARG" });
561
- const trimmed = selected.trim();
562
- const reserved = trimmed.toLowerCase();
563
- return reserved === "auto" || reserved === "local" ? reserved : trimmed;
682
+ if (typeof selected !== "string" || !selected.trim() || !parseMachine(selected)) throw Object.assign(/* @__PURE__ */ new Error("--remote-build / remote.build must be local, auto, remote, remote-only, or a tailnet machine name."), { code: "STIM_BAD_ARG" });
683
+ return placementWord(selected) ?? selected.trim();
564
684
  }
565
685
  function parseBuildMachineOption(value) {
566
686
  try {
@@ -569,11 +689,18 @@ function parseBuildMachineOption(value) {
569
689
  throw new InvalidArgumentError(error.message);
570
690
  }
571
691
  }
572
- function requireLocalBuild(selected) {
573
- if (selected === "auto" && !automaticMachineEnabled("build", "local")) throw new OffloadRefusal("auto", "local is disabled in remote.buildPoolDisabled; enable it or select a machine explicitly");
692
+ function automaticBuild(selected) {
693
+ const word = placementWord(selected);
694
+ return word !== null && word !== "local";
695
+ }
696
+ function requireLocalBuild(selected, reason) {
697
+ const word = placementWord(selected);
698
+ const lead = reason ? `${reason}; ` : "";
699
+ if (word === "remote-only") throw new OffloadRefusal(selected, `${lead}remote-only never builds on this machine`);
700
+ if ((word === "auto" || word === "remote") && !automaticMachineEnabled("build", "local")) throw new OffloadRefusal(selected, `${lead}local is disabled in remote.buildPoolDisabled; enable it or select a machine explicitly`);
574
701
  }
575
702
  function namedBuildMachine(selected) {
576
- return selected !== "auto" && selected !== "local";
703
+ return placementWord(selected) === null;
577
704
  }
578
705
  function requireConfiguredMachine(selected, machines) {
579
706
  if (!namedBuildMachine(selected)) return selected;
@@ -590,16 +717,10 @@ const settingSource = (flag, env, setting) => flag !== void 0 ? "flag" : env?.tr
590
717
  /** The settings that decide where a build runs, with the layer each value came from, for this run's `--remote-build`. */
591
718
  function buildPlacementSettings(selected) {
592
719
  const flag = operationState(ambientContext()).buildMachineFlag;
593
- const remote = loadConfig$1()?.remote;
594
- const rawMode = ambientEnv().STIM_REMOTE_BUILD_MODE || remote?.buildMode;
595
720
  return [{
596
721
  key: "remote.build",
597
722
  value: selected,
598
- from: settingSource(flag, ambientEnv().STIM_REMOTE_BUILD, remote?.build)
599
- }, {
600
- key: "remote.buildMode",
601
- value: selected === "local" ? "off" : OFFLOAD_MODES.includes(rawMode) ? rawMode : "auto",
602
- from: settingSource(void 0, ambientEnv().STIM_REMOTE_BUILD_MODE, remote?.buildMode)
723
+ from: settingSource(flag, ambientEnv().STIM_REMOTE_BUILD, loadConfig$1()?.remote?.build)
603
724
  }];
604
725
  }
605
726
  function resolveBuildPlacement(flag) {
@@ -617,10 +738,10 @@ function resolveBuildPlacement(flag) {
617
738
  failure: {
618
739
  code: error.code,
619
740
  message: error.message,
620
- remedy: error instanceof OffloadRefusal ? error.remedy : "Pass --remote-build auto, local, or an entry from stim settings get remote.machines."
741
+ remedy: error instanceof OffloadRefusal ? error.remedy : "Pass --remote-build local, auto, remote, remote-only, or an entry from stim settings get remote.machines."
621
742
  }
622
743
  };
623
744
  }
624
745
  }
625
746
  //#endregion
626
- export { parseBuildMachineOption as a, resolveBuildPlacement as c, configuredMachines as d, hostingMachines as f, namedBuildMachine as i, inspectBuildMachines as l, buildPlacementSettings as n, requireLocalBuild as o, inspectDeviceHostMachines as p, fingerprintMismatchRemedy as r, resolveBuildMachine as s, OffloadRefusal as t, pairedMachines as u };
747
+ export { hostingMachines as _, missingPackageManagerRemedy as a, podsFailedRemedy as c, resolveBuildPlacement as d, workerFailureReason as f, configuredMachines as g, predictedRefusal as h, fingerprintMismatchRemedy as i, requireLocalBuild as l, pairedMachines as m, automaticBuild as n, namedBuildMachine as o, inspectBuildMachines as p, buildPlacementSettings as r, parseBuildMachineOption as s, OffloadRefusal as t, resolveBuildMachine as u, inspectDeviceHostMachines as v };
@@ -1,5 +1,5 @@
1
- import { O as __commonJSMin, k as __require, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { J as resolveProjectSettings } from "./settings-B5tCoq9N.mjs";
1
+ import { O as __commonJSMin, k as __require, t as getExecutor } from "./exec-aULwtNly.mjs";
2
+ import { X as resolveProjectSettings } from "./settings-BDVI8Ivc.mjs";
3
3
  import { c as registerMetroStore, f as resolveMetroSharedCache, n as supervisorError, r as appendCacheStore, s as metroStoreRoot } from "./errors-DHm_U5gv.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { isAbsolute, join, relative, sep } from "node:path";