stim 1.24.0 → 1.26.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 (162) hide show
  1. package/README.md +1 -1
  2. package/dist/{acquire-artifact-CEs02U2o.mjs → acquire-artifact-DVsvSwf7.mjs} +1 -1
  3. package/dist/{act-Cyvm8xYc.mjs → act-C-BqJEpu.mjs} +158 -36
  4. package/dist/{activity-Dq3ZcdD8.mjs → activity-Lnb_EoRY.mjs} +4 -5
  5. package/dist/{agent-device-usage-output-CccomeE0.mjs → agent-device-usage-output-DbXy5tg8.mjs} +4 -4
  6. package/dist/{android-CX5IcRuf.mjs → android-B5P81yI-.mjs} +1 -1
  7. package/dist/{android-DcztblCT.mjs → android-CSbLRD53.mjs} +5 -5
  8. package/dist/{android-BZppyPe_.mjs → android-CiNQw3kq.mjs} +81 -52
  9. package/dist/{android-882m4hxX.mjs → android-DTAcRwBC.mjs} +81 -34
  10. package/dist/{android-cas-BtCOrNqb.mjs → android-cas-BTVhZ0Qs.mjs} +4 -4
  11. package/dist/{android-project-DVWyCbWU.d.mts → android-project-DUGMbq28.d.mts} +61 -3
  12. package/dist/api.d.mts +8 -5
  13. package/dist/api.mjs +27 -27
  14. package/dist/apk-signed-tail-B46U9hXc.mjs +142 -0
  15. package/dist/{artifact-BR5VNArK.mjs → artifact-BxREhAaV.mjs} +25 -19
  16. package/dist/{artifact-Bdt_n9Jc.mjs → artifact-CsAP6AGK.mjs} +36 -21
  17. package/dist/{attempt-DW-mQqM7.mjs → attempt-ClyJlZPT.mjs} +4 -2
  18. package/dist/{browser-web-ycg9qWB8.mjs → browser-web-rYPyqhTf.mjs} +11 -12
  19. package/dist/{budget-dPGuhNai.mjs → budget-k2mZGvvk.mjs} +242 -38
  20. package/dist/{build-CaF574eS.mjs → build-DPhApsjV.mjs} +28 -24
  21. package/dist/{build-cache-HFUQ9eLz.mjs → build-cache-DrXNCy3T.mjs} +123 -23
  22. package/dist/{build-plan-JsDUq4w1.mjs → build-plan-DrMMdayj.mjs} +5 -5
  23. package/dist/{cache-manifest-BPXRONJz.mjs → cache-manifest-BEZ9Bpl1.mjs} +1 -1
  24. package/dist/cache-manifest.mjs +1 -1
  25. package/dist/{ccache-CCn1S6qG.mjs → ccache-Bx5TbxwG.mjs} +6 -6
  26. package/dist/{cli-xqAidP7O.mjs → cli-BBKFGOFl.mjs} +19 -19
  27. package/dist/cli.mjs +1 -1
  28. package/dist/{client-18-ZowoT.mjs → client-D9CaRks-.mjs} +55 -71
  29. package/dist/collector-run.mjs +4 -4
  30. package/dist/{command-output-DxC0k2rk.mjs → command-output-BF5AR2dL.mjs} +1 -1
  31. package/dist/{config-BZhXY15H.mjs → config-BktkY_zC.mjs} +321 -15
  32. package/dist/{launch-BVlyQw3T.mjs → dependencies-Dw6wfQdv.mjs} +259 -256
  33. package/dist/{dependency-state-C56ll9hY.mjs → dependency-state-DFB41vfr.mjs} +1 -1
  34. package/dist/{dev-client-w_fok0Ek.mjs → dev-client-DXR_tPVY.mjs} +2 -2
  35. package/dist/{device-BktRGdjS.mjs → device-BK-zwyd_.mjs} +64 -33
  36. package/dist/{device-4RUugw5X.mjs → device-BcYeHSFu.mjs} +14 -14
  37. package/dist/{device-capacity-Ic-kdmEV.mjs → device-capacity-DCSvUF0l.mjs} +10 -17
  38. package/dist/device-host-worker.mjs +11 -13
  39. package/dist/{device-ios-DzpSlZyd.mjs → device-ios-BLGfXQeK.mjs} +68 -25
  40. package/dist/{device-lease-run-DUtkbqBQ.mjs → device-lease-run-BmvIl7bI.mjs} +5 -5
  41. package/dist/{device-pool-CgBHk401.mjs → device-pool-Dluix4H3.mjs} +3 -3
  42. package/dist/{doctor-DZgpqR6J.mjs → doctor-Bhg1ii70.mjs} +14 -14
  43. package/dist/{doctor-BZ6oxNum.mjs → doctor-Cp-BhzTS.mjs} +1 -1
  44. package/dist/{doctor-C33AzVfR.mjs → doctor-OnwP94ne.mjs} +81 -26
  45. package/dist/{doctor-fingerprint-zlujA1Gs.mjs → doctor-fingerprint-D3a04Mhu.mjs} +8 -2
  46. package/dist/doctor-fingerprint.mjs +1 -1
  47. package/dist/{doctor-watchman-B453A231.mjs → doctor-watchman-BStK05nt.mjs} +4 -4
  48. package/dist/{eas-build-CxKUNHsb.mjs → eas-build-Dsj93iM9.mjs} +2 -2
  49. package/dist/{eas-fallback-LMxk9Kw0.mjs → eas-fallback-FwkeqqGi.mjs} +13 -12
  50. package/dist/{eas-session-ledger-Ck6YXPAO.mjs → eas-session-ledger-B5vygTiD.mjs} +5 -5
  51. package/dist/{error-diagnostics-BkKCZq4P.mjs → error-diagnostics-BOOm9Db7.mjs} +8 -8
  52. package/dist/{errors-ccaPc4ox.mjs → errors-DHm_U5gv.mjs} +2 -1
  53. package/dist/{gc-DDWEAj0w.mjs → gc-C_79zvz4.mjs} +2 -2
  54. package/dist/{gc-yVKpAOKM.mjs → gc-ldgr-hXU.mjs} +74 -43
  55. package/dist/{guide-Bggftwc5.mjs → guide-D7K0X6KG.mjs} +374 -78
  56. package/dist/{hosted-android-D4dweBof.mjs → hosted-android-Bk54ej6n.mjs} +3 -3
  57. package/dist/{hosted-client-BBTVe3X6.mjs → hosted-client-fHO8yqzc.mjs} +5 -5
  58. package/dist/{hosted-ios-Sn0djzg8.mjs → hosted-ios-D55QhYaD.mjs} +1 -1
  59. package/dist/{hosted-logs-CYIZ5ubJ.mjs → hosted-logs-BfbmDM4M.mjs} +17 -11
  60. package/dist/hosted-logs-sync-B0pvmOk-.mjs +195 -0
  61. package/dist/{hosted-macos-CXjsUNBR.mjs → hosted-macos-CPl0OZ9h.mjs} +5 -5
  62. package/dist/{hosted-native-Doxbfzem.mjs → hosted-native-CpDB3-PO.mjs} +6 -7
  63. package/dist/{idle-shutdown-BInjLKqm.mjs → idle-shutdown-FfxL1KdG.mjs} +22 -9
  64. package/dist/{ios-BItP6lkn.mjs → ios-B7-lToDu.mjs} +8 -8
  65. package/dist/{ios-CVUFFZ6C.mjs → ios-WxpDJ5T1.mjs} +129 -14
  66. package/dist/{ios-device-BI38NFFH.mjs → ios-device-CsyryvpT.mjs} +1 -1
  67. package/dist/{ios-B1FXRCMX.mjs → ios-ftxdQbJS.mjs} +84 -51
  68. package/dist/{ios-project-KYqeJURj.mjs → ios-project-Ty5pHl9O.mjs} +6 -6
  69. package/dist/{ios-state-DlElquYD.mjs → ios-state-Cw7-WQf2.mjs} +1 -1
  70. package/dist/{js-swap-BvrQvXHY.mjs → js-swap-BMhXYVDS.mjs} +4 -4
  71. package/dist/{launch-SfzGH_s9.mjs → launch-DOp8RjDz.mjs} +32 -27
  72. package/dist/{logs-DXE32kyb.mjs → logs-dQDki6Tt.mjs} +9 -173
  73. package/dist/{logs-ovlU7m7N.mjs → logs-s1dRIG1E.mjs} +85 -36
  74. package/dist/{macos-B3BveDrU.mjs → macos-B0VEV3Gf.mjs} +1 -1
  75. package/dist/{macos-CCfhb-jT.mjs → macos-DBBPNnIA.mjs} +18 -19
  76. package/dist/macos-run.mjs +1 -1
  77. package/dist/maintenance-run.mjs +28 -11
  78. package/dist/{metro-Bu8LBfzS.mjs → metro-CjC10t6E.mjs} +2 -2
  79. package/dist/{metro-gateway-DtsOy-0P.mjs → metro-gateway-B6_PgD0L.mjs} +2 -3
  80. package/dist/{named-ports-BWDuU5oQ.mjs → named-ports-BG0j1X4g.mjs} +2 -2
  81. package/dist/{native-android-96BBizbq.mjs → native-android-CL2NGiik.mjs} +17 -17
  82. package/dist/{native-gradle-artifact-inputs-BcLYBZil.mjs → native-gradle-artifact-inputs-btSUulme.mjs} +3 -3
  83. package/dist/{native-run-BmH7U8pr.mjs → native-run-BfIDFKLH.mjs} +2 -3
  84. package/dist/{native-runtime-DgtJkzIa.mjs → native-runtime-Dq3RBcON.mjs} +6 -7
  85. package/dist/{native-xcode-inputs-irplbQb0.mjs → native-xcode-inputs-BW7H8JGu.mjs} +2 -2
  86. package/dist/{native-xcode-ios-BY-6hh6M.mjs → native-xcode-ios-CBXJAxfC.mjs} +18 -18
  87. package/dist/offload-worker.d.mts +7 -2
  88. package/dist/offload-worker.mjs +34 -23
  89. package/dist/{ownership-DxlZGDcV.mjs → ownership-BjYvMNX_.mjs} +2 -2
  90. package/dist/{phone-reverses-BdsdesVF.mjs → phone-reverses-lmj6kcPm.mjs} +3 -3
  91. package/dist/{placement-log-DUvqqsB-.mjs → placement-log-DIFPQAXp.mjs} +1 -1
  92. package/dist/{plan-placement-4axc0Hs7.mjs → plan-placement-IiiSQhtz.mjs} +3 -3
  93. package/dist/{ports-D-E_OiAO.mjs → ports-C2_w1Z0Z.mjs} +3 -3
  94. package/dist/prebuild-gmouvmJZ.mjs +1247 -0
  95. package/dist/{project-Dz-hWkb-.mjs → project-BUu6Is4k.mjs} +15 -16
  96. package/dist/{react-native-android-DOinxgwB.mjs → react-native-android-Cgg99REN.mjs} +48 -33
  97. package/dist/{react-native-build-AuCu-aAP.mjs → react-native-build-oNwqF5Wb.mjs} +8 -8
  98. package/dist/{react-native-doctor-2ivJUmwZ.mjs → react-native-doctor-BhA3KUte.mjs} +49 -8
  99. package/dist/{react-native-ios-D5zTIuH8.mjs → react-native-ios-B-nf4rjN.mjs} +40 -25
  100. package/dist/{recordings-CdPwYwvs.mjs → recordings-BldzVKq0.mjs} +1 -1
  101. package/dist/{reload-Ck9RJeSq.mjs → reload-C9OduiNc.mjs} +1 -1
  102. package/dist/{reload-C1TTVesC.mjs → reload-CCR7KC_l.mjs} +14 -14
  103. package/dist/{remote-DEZ7AOVq.mjs → remote-C8S7FlPF.mjs} +16 -7
  104. package/dist/{result-DqBrb12U.mjs → result-7F5hEwQJ.mjs} +17 -17
  105. package/dist/{run-BIwoU44q.mjs → run-BqB0v3pt.mjs} +1 -1
  106. package/dist/{selection-BLtvaqxc.mjs → selection-BNPBZ6T5.mjs} +157 -44
  107. package/dist/{server-bare-Z1ToVLPn.mjs → server-bare-A75rDIdD.mjs} +55 -3
  108. package/dist/{server-command-C0pmjNdG.mjs → server-command-CssKFOD7.mjs} +4 -4
  109. package/dist/{server-expo-Tt_hLRpy.mjs → server-expo-eQfOdydb.mjs} +8 -6
  110. package/dist/server-expo-wvcj5tiZ.mjs +2 -0
  111. package/dist/{settings-RKwY33wv.mjs → settings-CosW5X-S.mjs} +59 -61
  112. package/dist/{settings-kkt0vP4w.mjs → settings-OaGQF-ri.mjs} +1 -1
  113. package/dist/{settings-write--gj6MACV.mjs → settings-write-QjYfSrjF.mjs} +5 -5
  114. package/dist/settings.schema.json +71 -6
  115. package/dist/{simslim-CdWKT3vA.mjs → simslim-Bax1qcxu.mjs} +22 -6
  116. package/dist/{slot-launch-A1BgotaM.mjs → slot-launch-CYCEhfBY.mjs} +6 -6
  117. package/dist/{stage-ERTMh88n.mjs → stage-jKQ7CP_B.mjs} +1 -1
  118. package/dist/{start-Bmg_qmHi.mjs → start-C_wefNKB.mjs} +1 -1
  119. package/dist/{start-BKGrEhzG.mjs → start-_BdJ32cZ.mjs} +9 -10
  120. package/dist/{state-B1ig0Kqy.mjs → state-C1i2nMOP.mjs} +2 -3
  121. package/dist/{state-BfAltYJP.mjs → state-C4OdpOTF.mjs} +1 -2
  122. package/dist/{stats-B-ckuiUg.mjs → stats-tEpEEH-u.mjs} +4 -4
  123. package/dist/{status-Pw-807f0.mjs → status-B9M7x4CZ.mjs} +1 -1
  124. package/dist/{status-Fect2w9R.mjs → status-CRXz-Gtj.mjs} +1 -1
  125. package/dist/{status-DfFp6a76.mjs → status-DQrqodLj.mjs} +22 -23
  126. package/dist/{status-watch-XC7F-AMf.mjs → status-watch-B5wDIH_o.mjs} +4 -4
  127. package/dist/status-worker.mjs +1 -1
  128. package/dist/{stim-desktop-DS0mzR8U.mjs → stim-desktop-6Dqp-gjX.mjs} +1 -1
  129. package/dist/{stop-BFu7X_Do.mjs → stop-CmdNhGlC.mjs} +2 -2
  130. package/dist/{stop-CL1kDHds.mjs → stop-DRqQVqDJ.mjs} +74 -53
  131. package/dist/{stop-DhclRwOO.mjs → stop-ySNQHXMG.mjs} +4 -5
  132. package/dist/supervisor-run.d.mts +1 -0
  133. package/dist/supervisor-run.mjs +15 -16
  134. package/dist/{support-B3tzVhKn.mjs → support-BGSCBoib.mjs} +4 -4
  135. package/dist/{support-B1W-hmC2.mjs → support-CVOCp0Ft.mjs} +15 -12
  136. package/dist/{swiftpm-artifact-inputs-BWYPj9Sn.mjs → swiftpm-artifact-inputs-CfUzt_0Z.mjs} +1 -1
  137. package/dist/{swiftpm-macos-BVCP5mO4.mjs → swiftpm-macos-x6HPpl_2.mjs} +10 -10
  138. package/dist/toolchain-DoavrvIA.mjs +2 -0
  139. package/dist/toolchain-J4J8MrAr.mjs +2107 -0
  140. package/dist/trigger-DzJu208Q.mjs +2 -0
  141. package/dist/{trigger-CBMe2YLH.mjs → trigger-KVaWWNyn.mjs} +1 -1
  142. package/dist/{warm-progress-ol0ZypEu.mjs → warm-progress-DvhTX_eu.mjs} +3 -4
  143. package/dist/web-BFLueSh-.mjs +2 -0
  144. package/dist/{web-BH7peScT.mjs → web-Bihbf7-u.mjs} +8 -9
  145. package/dist/web-run.mjs +4 -4
  146. package/dist/{workspace-state-CeBpIZgr.mjs → workspace-state-pUg3_RRA.mjs} +45 -7
  147. package/dist/{workspaces-CSV2Orf4.mjs → workspaces-g2lhdBXF.mjs} +17 -17
  148. package/dist/{worktree-Dw8kfacb.mjs → worktree-BKuklFh_.mjs} +34 -31
  149. package/dist/{worktree-DEDUzO_L.mjs → worktree-Bm4cb-nU.mjs} +1 -1
  150. package/package.json +8 -8
  151. package/shim/bundle-response.cjs +53 -1
  152. package/shim/bundle-response.d.cts +1 -1
  153. package/shim/expo-metro-config.cjs +23 -1
  154. package/dist/created-devices-D2Aca-xu.mjs +0 -52
  155. package/dist/paths-DQtTgsBf.mjs +0 -42
  156. package/dist/prebuild-DmVCf5xb.mjs +0 -501
  157. package/dist/server-expo-CEntXzRw.mjs +0 -2
  158. package/dist/toolchain-BjgKdoEf.mjs +0 -2
  159. package/dist/toolchain-D3bmRMia.mjs +0 -897
  160. package/dist/trigger-BLsHgAGR.mjs +0 -2
  161. package/dist/web-BdOFlTJr.mjs +0 -2
  162. package/dist/xcode-DHu41qQ4.mjs +0 -910
@@ -1,13 +1,14 @@
1
1
  import { c as throwIfCancelled, t as getExecutor, x as withDrainingCancellation } from "./exec-VFRpu1iA.mjs";
2
- import { i as sharedBuildCache } from "./paths-DQtTgsBf.mjs";
2
+ import { y as sharedBuildCache } from "./workspace-state-pUg3_RRA.mjs";
3
3
  import { a as killOnAbort, c as gitQuiet, o as git, r as childEnvironment, s as gitAsync } from "./operation-exec-CUZifp6Z.mjs";
4
- import { m as defaultAndroidLayout } from "./settings-RKwY33wv.mjs";
5
- import { r as register } from "./cache-manifest-BPXRONJz.mjs";
4
+ import { m as defaultAndroidLayout } from "./settings-CosW5X-S.mjs";
5
+ import { r as register } from "./cache-manifest-BEZ9Bpl1.mjs";
6
+ import { r as writeSignedTail, t as computeSignedTail } from "./apk-signed-tail-B46U9hXc.mjs";
6
7
  import { createHash } from "node:crypto";
7
8
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
8
9
  import { join } from "node:path";
9
10
  import { artifactIn, buildCacheKey, resolveArtifact, storeArtifactAsync } from "@stim-cli/core";
10
- import { isAbsolute as isAbsolute$1, join as join$1, posix as posix$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
11
+ import { basename as basename$1, isAbsolute as isAbsolute$1, join as join$1, posix as posix$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
11
12
  import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
12
13
  import { readdir, writeFile } from "node:fs/promises";
13
14
  import { isDeepStrictEqual } from "util";
@@ -293,6 +294,58 @@ function androidProjectFingerprintOptions(projectRoot, layout, exists = existsSy
293
294
  ].map((dir) => `${moduleRel}/${dir}/**/*`)
294
295
  };
295
296
  }
297
+ const LOCKFILES = [
298
+ "pnpm-lock.yaml",
299
+ "yarn.lock",
300
+ "package-lock.json",
301
+ "bun.lock",
302
+ "bun.lockb"
303
+ ];
304
+ /**
305
+ * The patches of a monorepo's install root, which @expo/fingerprint does not see: its patch sourcer reads only the
306
+ * app's own `patches/`, and its default preset hashes an installed package by name and version, so a patch applied
307
+ * from the workspace root would leave the key unchanged.
308
+ */
309
+ function workspacePatchSources(projectRoot) {
310
+ let dir = resolve$1(projectRoot);
311
+ for (;;) {
312
+ if (LOCKFILES.some((name) => existsSync$1(join$1(dir, name)))) break;
313
+ const parent = resolve$1(dir, "..");
314
+ if (parent === dir || existsSync$1(join$1(dir, ".git"))) return [];
315
+ dir = parent;
316
+ }
317
+ const sources = ["patches", ".yarn/patches"].filter((name) => (name === "patches" ? dir !== resolve$1(projectRoot) : true) && existsSync$1(join$1(dir, name))).map((name) => ({
318
+ type: "dir",
319
+ filePath: relative$1(projectRoot, join$1(dir, name)).split(sep$1).join("/"),
320
+ reasons: ["workspacePatches"]
321
+ }));
322
+ const patched = pnpmPatchedDependencies(join$1(dir, "pnpm-lock.yaml"));
323
+ if (patched) sources.push({
324
+ type: "contents",
325
+ id: "pnpmPatchedDependencies",
326
+ contents: patched,
327
+ reasons: ["workspacePatches"]
328
+ });
329
+ return sources;
330
+ }
331
+ /** The lockfile's `patchedDependencies` block, which pnpm rewrites with each patch's hash wherever the patch lives. */
332
+ function pnpmPatchedDependencies(lockfile) {
333
+ let text;
334
+ try {
335
+ text = readFileSync$1(lockfile, "utf8");
336
+ } catch {
337
+ return null;
338
+ }
339
+ const lines = text.split(/\r?\n/);
340
+ const start = lines.indexOf("patchedDependencies:");
341
+ if (start === -1) return null;
342
+ const block = [];
343
+ for (const line of lines.slice(start + 1)) {
344
+ if (line && !/^\s/.test(line)) break;
345
+ if (line.trim()) block.push(line.trim());
346
+ }
347
+ return block.length ? block.join("\n") : null;
348
+ }
296
349
  /**
297
350
  * The bundle output and, with `ios.projectPath` '.', the top-level entries that git ignores here for an iOS
298
351
  * fingerprint, as the paths a build worker needs to ignore the same ones: it has no .git/info/exclude or global
@@ -319,7 +372,12 @@ async function fingerprintOptions(projectRoot, { platform, iosProjectPath = "ios
319
372
  const ignoredAtAppRoot = (names) => new Set([...ignoredHere(names)].filter((name) => !trackedPaths.includes(name)));
320
373
  const platforms = platform && FINGERPRINT_PLATFORMS.has(platform) ? { platforms: [platform] } : void 0;
321
374
  const ios = platform === "ios" ? iosProjectFingerprintOptions(projectRoot, iosProjectPath, { ignored: (_, names) => ignoredAtAppRoot(names) }) : androidLayout?.custom ? androidProjectFingerprintOptions(projectRoot, androidLayout) : {};
322
- if (ios.extraSources) ios.extraSources = [...(await loadConfigAsync(projectRoot, true))?.extraSources ?? [], ...ios.extraSources];
375
+ const patches = workspacePatchSources(projectRoot);
376
+ if (ios.extraSources || patches.length) ios.extraSources = [
377
+ ...(await loadConfigAsync(projectRoot, true))?.extraSources ?? [],
378
+ ...ios.extraSources ?? [],
379
+ ...patches
380
+ ];
323
381
  const bundleOutput = platform === "android" ? [] : [...ignoredHere(Object.keys(BUNDLE_OUTPUT_IGNORES), true)].map((path) => BUNDLE_OUTPUT_IGNORES[path]);
324
382
  return {
325
383
  ...platforms,
@@ -345,14 +403,13 @@ async function fingerprintProject(projectRoot, { createFingerprint = expoFingerp
345
403
  sources: Array.isArray(result?.sources) ? result.sources : []
346
404
  };
347
405
  }
348
- /** The env files @expo/env loads for the config, in the mode @expo/fingerprint's config loader sets. */
406
+ /** The env files @expo/env loads for the config: @expo/fingerprint 0.21 evaluates it in development mode. */
349
407
  function expoEnvFiles(env = {}) {
350
408
  if (/^(1|true)$/i.test(env.EXPO_NO_DOTENV ?? "")) return [];
351
- const mode = env.NODE_ENV || "development";
352
409
  return [
353
- `.env.${mode}.local`,
354
- ...mode === "test" ? [] : [".env.local"],
355
- `.env.${mode}`,
410
+ ".env.development.local",
411
+ ".env.local",
412
+ ".env.development",
356
413
  ".env"
357
414
  ];
358
415
  }
@@ -457,12 +514,29 @@ async function storeBuild(platform, key, buildPath, rootOrOptions = {}) {
457
514
  }),
458
515
  overwrite: Boolean(options.overwrite),
459
516
  writeMetadata: async (staging) => {
517
+ if (platform === "android" && buildPath.endsWith(".apk")) try {
518
+ const tail = await computeSignedTail(join$1(staging, basename$1(buildPath)), (file, args) => getExecutor().runFileAsync(file, args, {
519
+ timeoutMs: 12e4,
520
+ ...env ? childEnvironment(env) : {},
521
+ onSpawn: killOnAbort(signal),
522
+ declareFor: options.context
523
+ }));
524
+ if (tail) await writeSignedTail(staging, tail);
525
+ } catch {
526
+ throwIfCancelled(signal, "build cache copy");
527
+ }
460
528
  if (Array.isArray(options.sources)) try {
461
529
  await writeFile(join$1(staging, SOURCES_FILE), JSON.stringify(options.sources.map(withoutContents)));
462
530
  } catch {}
463
531
  if (options.assetManifest) try {
464
532
  await writeFile(join$1(staging, ASSET_MANIFEST_FILE), JSON.stringify(options.assetManifest));
465
533
  } catch {}
534
+ if (options.readAppId) try {
535
+ const appId = await options.readAppId(buildPath);
536
+ if (appId) await writeFile(join$1(staging, APP_ID_FILE), JSON.stringify({ appId }));
537
+ } catch {
538
+ throwIfCancelled(signal, "build cache copy");
539
+ }
466
540
  }
467
541
  }));
468
542
  } catch (error) {
@@ -496,12 +570,13 @@ function prepareProviderDownloadDir(dir, registeredBy) {
496
570
  });
497
571
  } catch {}
498
572
  }
499
- function filesystemBuildCapability({ root, context, sources, assetManifest, resolve = resolveBuild, store = storeBuild } = {}) {
573
+ function filesystemBuildCapability({ root, context, sources, assetManifest, readAppId, resolve = resolveBuild, store = storeBuild } = {}) {
500
574
  const stored = {
501
575
  ...context === void 0 ? {} : { context },
502
576
  ...root === void 0 ? {} : { root },
503
577
  ...sources === void 0 ? {} : { sources },
504
- ...assetManifest === void 0 ? {} : { assetManifest }
578
+ ...assetManifest === void 0 ? {} : { assetManifest },
579
+ ...readAppId === void 0 ? {} : { readAppId }
505
580
  };
506
581
  return {
507
582
  resolve: ({ platform, key }) => root === void 0 ? resolve(platform, key) : resolve(platform, key, root),
@@ -529,6 +604,7 @@ function providerUploadOutcome(result, name, env) {
529
604
  };
530
605
  }
531
606
  const SOURCES_FILE = "fingerprint-sources.json";
607
+ const APP_ID_FILE = "app-id.json";
532
608
  function withoutContents(source) {
533
609
  return source.type === "contents" ? {
534
610
  ...source,
@@ -543,6 +619,16 @@ function storedSources(platform, key, root = sharedBuildCache()) {
543
619
  return null;
544
620
  }
545
621
  }
622
+ /** The bundle id or Android package read from the entry's artifact when it was stored, or null for older entries. */
623
+ function storedAppId(platform, key, root = sharedBuildCache()) {
624
+ try {
625
+ const parsed = JSON.parse(readFileSync$1(join$1(entryDir(platform, key, root), APP_ID_FILE), "utf-8"));
626
+ if (parsed && typeof parsed === "object" && "appId" in parsed && typeof parsed.appId === "string" && parsed.appId) return parsed.appId;
627
+ return null;
628
+ } catch {
629
+ return null;
630
+ }
631
+ }
546
632
  function storedAssetManifest(platform, key, root = sharedBuildCache()) {
547
633
  try {
548
634
  return parseAssetManifest(readFileSync$1(join$1(entryDir(platform, key, root), ASSET_MANIFEST_FILE), "utf-8"));
@@ -570,6 +656,28 @@ function diffItemChange(item) {
570
656
  reasons: sourceReasons(source)
571
657
  };
572
658
  }
659
+ /** The installed package a source path lies in: the name after its last `node_modules/`. */
660
+ function packageIn(path) {
661
+ return [...path.matchAll(/(?:^|\/)node_modules\/((?:@[^/]+\/)?[^/]+)/g)].at(-1)?.[1] ?? null;
662
+ }
663
+ /** A package that moved, such as a version bump of a pnpm store directory, is one change rather than a removal and an addition. */
664
+ function mergeMovedPackages(changes) {
665
+ const added = /* @__PURE__ */ new Map();
666
+ for (const change of changes) {
667
+ const pkg = change.change === "added" ? packageIn(change.name) : null;
668
+ if (pkg && !added.has(pkg)) added.set(pkg, change);
669
+ }
670
+ const moved = /* @__PURE__ */ new Set();
671
+ const kept = changes.filter((change) => {
672
+ const pkg = change.change === "removed" ? packageIn(change.name) : null;
673
+ const counterpart = pkg ? added.get(pkg) : void 0;
674
+ if (!counterpart || moved.has(counterpart)) return true;
675
+ moved.add(counterpart);
676
+ return false;
677
+ });
678
+ for (const change of moved) change.change = "changed";
679
+ return kept;
680
+ }
573
681
  function compareSourceLists(previous, current) {
574
682
  const previousByName = /* @__PURE__ */ new Map();
575
683
  for (const source of previous) {
@@ -603,7 +711,7 @@ function compareSourceLists(previous, current) {
603
711
  change: "removed",
604
712
  reasons: before.reasons
605
713
  });
606
- return changes;
714
+ return mergeMovedPackages(changes);
607
715
  }
608
716
  function diffFingerprintSources({ previous, previousHash = null, current, differ = null }) {
609
717
  if (typeof differ === "function") try {
@@ -615,16 +723,8 @@ function diffFingerprintSources({ previous, previousHash = null, current, differ
615
723
  hash: current.hash
616
724
  });
617
725
  if (Array.isArray(items)) {
618
- const changes = [];
619
726
  const seen = /* @__PURE__ */ new Set();
620
- for (const item of items) {
621
- const change = diffItemChange(item);
622
- if (change !== null && !seen.has(change.name)) {
623
- seen.add(change.name);
624
- changes.push(change);
625
- }
626
- }
627
- return changes;
727
+ return mergeMovedPackages(items.map(diffItemChange).filter((change) => change !== null)).filter((change) => !seen.has(change.name) && Boolean(seen.add(change.name)));
628
728
  }
629
729
  } catch {}
630
730
  return compareSourceLists(previous, current.sources);
@@ -732,4 +832,4 @@ function fingerprintDiffRecord({ changed, previousHash, hash }) {
732
832
  };
733
833
  }
734
834
  //#endregion
735
- export { trackedFingerprintPaths as C, captureAssetManifest as D, assetDiffReason as E, compareAssetManifests as O, storedSources as S, untrackedNativeFiles as T, providerUploadOutcome as _, configInputsChanged as a, storeBuild as b, expoConfigContents as c, fingerprintProject as d, gitignoredFingerprintInputs as f, providerDownloadPath as g, prepareProviderDownloadDir as h, compareSourceLists as i, readAssetManifest as k, filesystemBuildCapability as l, inputsChangedDuringBuild as m, buildCacheKey as n, diffFingerprintSources as o, ignoredFingerprintPaths as p, changedDuringBuildLine as r, entryDir as s, artifactIn as t, fingerprintDiffRecord as u, refingerprintAfterMutation as v, untrackedMissLine as w, storedAssetManifest as x, resolveBuild as y };
835
+ export { assetDiffReason as A, storeBuild as C, trackedFingerprintPaths as D, storedSources as E, compareAssetManifests as M, readAssetManifest as N, untrackedMissLine as O, resolveBuild as S, storedAssetManifest as T, packageIn as _, configInputsChanged as a, providerUploadOutcome as b, expoConfigContents as c, fingerprintDiffRecord as d, fingerprintOptions as f, inputsChangedDuringBuild as g, ignoredFingerprintPaths as h, compareSourceLists as i, captureAssetManifest as j, untrackedNativeFiles as k, expoEnvFiles as l, gitignoredFingerprintInputs as m, buildCacheKey as n, diffFingerprintSources as o, fingerprintProject as p, changedDuringBuildLine as r, entryDir as s, artifactIn as t, filesystemBuildCapability as u, prepareProviderDownloadDir as v, storedAppId as w, refingerprintAfterMutation as x, providerDownloadPath as y };
@@ -1,9 +1,9 @@
1
1
  import { T as trackReportResource } from "./exec-VFRpu1iA.mjs";
2
- import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-DxC0k2rk.mjs";
3
- import { Ht as makeTemporaryDirectory, Wt as removeTemporaryEntryAsync } from "./settings-RKwY33wv.mjs";
4
- import { L as estimateBuild, Un as easAuthNote, q as readStats } from "./budget-dPGuhNai.mjs";
5
- import { s as entryDir, t as artifactIn } from "./build-cache-HFUQ9eLz.mjs";
6
- import { l as predictBuildMiss, o as staleNativeDirRefusal } from "./prebuild-DmVCf5xb.mjs";
2
+ import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-BF5AR2dL.mjs";
3
+ import { Gt as removeTemporaryEntryAsync, Ut as makeTemporaryDirectory } from "./settings-CosW5X-S.mjs";
4
+ import { Jn as easAuthNote, V as estimateBuild, Z as readStats } from "./budget-k2mZGvvk.mjs";
5
+ import { s as entryDir, t as artifactIn } from "./build-cache-DrXNCy3T.mjs";
6
+ import { l as predictBuildMiss, o as staleNativeDirRefusal } from "./prebuild-gmouvmJZ.mjs";
7
7
  import chalk from "chalk";
8
8
  import { PROVIDER_LOAD_TIMEOUT_ENV, PROVIDER_LOAD_TIMEOUT_MS, buildResolveTimeoutMs, resolveTieredBuild, timeoutFromEnv } from "@stim-cli/cache";
9
9
  //#region src/commands/build-plan.ts
@@ -1,4 +1,4 @@
1
- import { d as getConfigDir } from "./config-BZhXY15H.mjs";
1
+ import { d as getConfigDir } from "./config-BktkY_zC.mjs";
2
2
  import { cacheDirRefusal, readCacheManifest, updateCacheManifest } from "@stim-cli/core";
3
3
  import { join, resolve } from "path";
4
4
  import { existsSync } from "fs";
@@ -1,2 +1,2 @@
1
- import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-BPXRONJz.mjs";
1
+ import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-BEZ9Bpl1.mjs";
2
2
  export { manifestPath, readManifest, register, registeredCaches, unregister };
@@ -1,10 +1,10 @@
1
1
  import { t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { a as sharedCcache, m as workspaceLogsDir } from "./paths-DQtTgsBf.mjs";
3
- import { _ as loadConfig } from "./config-BZhXY15H.mjs";
4
- import { l as phaseLine } from "./command-output-DxC0k2rk.mjs";
5
- import { m as defaultAndroidLayout } from "./settings-RKwY33wv.mjs";
6
- import { r as register } from "./cache-manifest-BPXRONJz.mjs";
7
- import { o as machineNumber } from "./budget-dPGuhNai.mjs";
2
+ import { b as sharedCcache, k as workspaceLogsDir } from "./workspace-state-pUg3_RRA.mjs";
3
+ import { _ as loadConfig } from "./config-BktkY_zC.mjs";
4
+ import { l as phaseLine } from "./command-output-BF5AR2dL.mjs";
5
+ import { m as defaultAndroidLayout } from "./settings-CosW5X-S.mjs";
6
+ import { r as register } from "./cache-manifest-BEZ9Bpl1.mjs";
7
+ import { o as machineNumber } from "./budget-k2mZGvvk.mjs";
8
8
  import { readFileSync, realpathSync } from "node:fs";
9
9
  import { isAbsolute, join, relative } from "node:path";
10
10
  import chalk from "chalk";
@@ -1,27 +1,27 @@
1
1
  import { E as debugLog } from "./exec-VFRpu1iA.mjs";
2
- import { y as refuseRelativeStimPaths } from "./config-BZhXY15H.mjs";
2
+ import { y as refuseRelativeStimPaths } from "./config-BktkY_zC.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { runId } 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-BZ6oxNum.mjs")],
9
- ["worktree", () => import("./worktree-DEDUzO_L.mjs")],
10
- ["start", () => import("./start-Bmg_qmHi.mjs")],
11
- ["ports", () => import("./ports-D-E_OiAO.mjs")],
12
- ["stop", () => import("./stop-BFu7X_Do.mjs")],
13
- ["ios", () => import("./ios-BItP6lkn.mjs")],
14
- ["android", () => import("./android-DcztblCT.mjs")],
15
- ["web", () => import("./web-BdOFlTJr.mjs")],
16
- ["macos", () => import("./macos-B3BveDrU.mjs")],
17
- ["reload", () => import("./reload-Ck9RJeSq.mjs")],
18
- ["device", () => import("./device-4RUugw5X.mjs")],
19
- ["logs", () => import("./logs-ovlU7m7N.mjs")],
20
- ["settings", () => import("./settings-kkt0vP4w.mjs")],
21
- ["status", () => import("./status-Pw-807f0.mjs")],
22
- ["stats", () => import("./stats-B-ckuiUg.mjs")],
23
- ["gc", () => import("./gc-DDWEAj0w.mjs")],
24
- ["guide", () => import("./guide-Bggftwc5.mjs")]
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")]
25
25
  ]);
26
26
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
27
27
  const program = new Command();
@@ -52,7 +52,7 @@ try {
52
52
  }));
53
53
  }
54
54
  try {
55
- const { triggerMaintenance } = await import("./trigger-BLsHgAGR.mjs");
55
+ const { triggerMaintenance } = await import("./trigger-DzJu208Q.mjs");
56
56
  triggerMaintenance(action.name());
57
57
  } catch {}
58
58
  });
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-xqAidP7O.mjs");
7
+ } else import("./cli-BBKFGOFl.mjs");
8
8
  //#endregion
9
9
  export {};
@@ -1,69 +1,24 @@
1
1
  import { C as reportSignal, E as debugLog, b as operationState, c as throwIfCancelled, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { Q as openAuthenticated, _ as loadConfig$1, it as sayHello, rt as resolveEndpoint } from "./config-BZhXY15H.mjs";
2
+ import { _ as loadConfig$1, at as resolveEndpoint, et as openAuthenticated, ot as sayHello } from "./config-BktkY_zC.mjs";
3
3
  import { o as git, s as gitAsync } from "./operation-exec-CUZifp6Z.mjs";
4
- import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
5
- import { Q as emptyCaches, Sr as discoverCaches, it as planCacheEmptying } from "./budget-dPGuhNai.mjs";
4
+ import { Dr as discoverCaches, E as maintenanceLogger, ct as planCacheEmptying, nt as emptyCaches } from "./budget-k2mZGvvk.mjs";
6
5
  import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
7
- import { d as runCancellationSignal } from "./native-run-BmH7U8pr.mjs";
8
- import { n as CCACHE_UNAVAILABLE, t as CCACHE_NOT_RUN } from "./ccache-CCn1S6qG.mjs";
9
- import { n as COMPILATION_CACHE_UNAVAILABLE, t as COMPILATION_CACHE_NOT_RUN } from "./xcode-DHu41qQ4.mjs";
6
+ import { d as runCancellationSignal } from "./native-run-BfIDFKLH.mjs";
10
7
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
11
- import { a as iosToolchainAsync, d as toolchainMismatches, f as workerToolchain, g as readRubyVersion } from "./toolchain-D3bmRMia.mjs";
12
- import { i as namedBuildMachine, t as OffloadRefusal, u as pairedMachines } from "./selection-BLtvaqxc.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";
13
11
  import { n as fingerprintNativeInputs, r as manifestDigest } from "./native-inputs-TRTTTRxt.mjs";
14
12
  import { a as sourceManifest, i as nativeTransferManifest, n as gitVisiblePaths, r as nativeFileDigest, t as checkNativeTransferMembership } from "./native-source-D-4Dh4JU.mjs";
15
13
  import { createHash, webcrypto } from "node:crypto";
16
- import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
14
+ import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, writeSync } from "node:fs";
17
15
  import { isDeepStrictEqual } from "node:util";
18
16
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
19
- import { LOG_ROTATE_BYTES, ambientContext, dependencyLockfile, reactNativeArtifactIdentity, reactNativeArtifactQuery, rotatedLogPath, swiftpmArtifactQuery, withDirLock } from "@stim-cli/core";
20
- import { MAINTENANCE_LOG_NAME, OFFLOAD_MODES, automaticMachineEnabled, isJsonObject, maintenanceDir, maintenanceNdjsonFile, requireAutomaticMachine, runId, saturation, workspaceLogsDir } from "@stim-cli/core/state";
17
+ 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";
21
19
  import { WebSocket } from "ws";
22
20
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
23
21
  import { access, lstat, readFile, readlink, realpath } from "node:fs/promises";
24
- //#region src/maintenance/log.ts
25
- function maintenanceLogger(settings, pass, trigger) {
26
- const file = maintenanceNdjsonFile();
27
- const rotated = rotatedLogPath(file);
28
- withDirLock(`${file}.lock`, () => {
29
- try {
30
- if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
31
- } catch {}
32
- });
33
- const writer = createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
34
- return {
35
- write(event, level, msg, fields = {}) {
36
- if (level === "debug" && !settings.logChecks) return null;
37
- const record = {
38
- ...fields,
39
- ts: Date.now(),
40
- src: "maintenance",
41
- level,
42
- msg,
43
- event,
44
- pass,
45
- trigger,
46
- mode: settings.mode === "on" ? "on" : "report"
47
- };
48
- if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
49
- if (typeof fields.workspace === "string" && [
50
- "maintenance_action",
51
- "maintenance_failure",
52
- "maintenance_skip"
53
- ].includes(event)) {
54
- const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
55
- try {
56
- if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
57
- } finally {
58
- workspace.close();
59
- }
60
- }
61
- return record;
62
- },
63
- close: () => writer.close()
64
- };
65
- }
66
- //#endregion
67
22
  //#region src/cache/compilation-cache-corruption.ts
68
23
  const COMPILATION_CACHE_CORRUPT = "STIM_COMPILATION_CACHE_CORRUPT";
69
24
  async function emptyCompilationCache(dir) {
@@ -387,9 +342,10 @@ async function reactNativeArtifactToolchain(platform, root, iosDirectory) {
387
342
  os: process.platform
388
343
  } : null;
389
344
  }
390
- const { stimBuild, os, arch, jdk, androidSdk } = workerToolchain(null, "gradle");
391
- return stimBuild && jdk && androidSdk ? {
345
+ const { stimBuild, compat, os, arch, jdk, androidSdk } = workerToolchain(null, "gradle");
346
+ return stimBuild && compat !== void 0 && jdk && androidSdk ? {
392
347
  stimBuild,
348
+ compat,
393
349
  os,
394
350
  arch,
395
351
  jdk,
@@ -540,8 +496,10 @@ function matchingArtifact(offer, identity) {
540
496
  }
541
497
  const gb = (bytes) => (bytes / 1024 ** 3).toFixed(1);
542
498
  /** Every reason a machine's offer cannot take this build, in either mode; empty when it can. */
543
- function offerProblems(offer, target) {
499
+ function offerProblems(offer, target, named = false) {
544
500
  const problems = toolchainMismatches(target, offer.toolchain);
501
+ const pods = !named && target.platform === "ios" && !problems.some(({ code }) => code === "platform") ? cocoapodsDifference(target, offer.toolchain) : null;
502
+ if (pods) problems.push(pods);
545
503
  const capacity = offer.capacity;
546
504
  const { running, max, diskFreeBytes, minDiskFreeBytes, declined } = capacity;
547
505
  if (diskFreeBytes !== null && diskFreeBytes < minDiskFreeBytes) problems.push({
@@ -601,7 +559,7 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
601
559
  return;
602
560
  }
603
561
  if (cacheOnly) return skip(machine, "artifact-miss", "no matching completed artifact");
604
- const problems = offerProblems(offer, target);
562
+ const problems = offerProblems(offer, target, namedBuildMachine(selected));
605
563
  if (problems.length) return skip(machine, problemCode(problems[0]), problems.map((problem) => problem.reason).join("; "), problems.map((problem) => problem.code));
606
564
  const load = offer.capacity.loadPerCore;
607
565
  if (selected === "auto" && localEnabled && mode === "auto" && !slotsFull) {
@@ -614,10 +572,11 @@ function pickOffer({ mode, here, offers, target, localEnabled = true, selected =
614
572
  score,
615
573
  load: typeof load === "number" ? load : Number.POSITIVE_INFINITY
616
574
  });
575
+ const notes = toolchainNotes(target, offer.toolchain).map((each) => each.reason);
617
576
  candidates.push({
618
577
  machine,
619
578
  code: "accepted",
620
- msg: typeof load === "number" ? `can take the build (load ${load}/core there)` : "can take the build"
579
+ msg: [typeof load === "number" ? `can take the build (load ${load}/core there)` : "can take the build", ...notes].join("; ")
621
580
  });
622
581
  });
623
582
  ranked.sort((a, b) => b.score - a.score || a.load - b.load);
@@ -970,8 +929,8 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
970
929
  ...identity.dependencies && connection.supports("build-dependency-cache") ? { dependencies: identity.dependencies } : {},
971
930
  ...native ? { native } : identity.rubyVersion ? { rubyVersion: identity.rubyVersion } : {},
972
931
  ...native === "xcode" && identity.artifact && connection.supports("build-artifact-cache") ? { artifact: identity.artifact } : {},
973
- ...identity.swiftpmArtifact && connection.supports("swiftpm-peer-cache") ? { swiftpmArtifact: identity.swiftpmArtifact } : {},
974
- ...identity.reactNativeArtifact && connection.supports("react-native-peer-cache") ? { reactNativeArtifact: identity.reactNativeArtifact } : {},
932
+ ...identity.swiftpmArtifact && queriesPeerCache(connection, "swiftpm-peer-cache") ? { swiftpmArtifact: identity.swiftpmArtifact } : {},
933
+ ...identity.reactNativeArtifact && queriesPeerCache(connection, "react-native-peer-cache") ? { reactNativeArtifact: identity.reactNativeArtifact } : {},
975
934
  ...native === "gradle" && identity.gradleArtifact && connection.supports("native-gradle-peer-cache") ? { gradleArtifact: identity.gradleArtifact } : {}
976
935
  }, offerMs);
977
936
  const failure = replyError(reply);
@@ -993,7 +952,7 @@ async function probeMachine(credential, identity, { connectMs = CONNECT_TIMEOUT_
993
952
  return {
994
953
  credential,
995
954
  connection,
996
- offer: identity.swiftpmArtifact && !connection.supports("swiftpm-peer-cache") || identity.reactNativeArtifact && !connection.supports("react-native-peer-cache") || native === "gradle" && (!identity.gradleArtifact || !connection.supports("native-gradle-peer-cache")) ? {
955
+ offer: identity.swiftpmArtifact && !queriesPeerCache(connection, "swiftpm-peer-cache") || identity.reactNativeArtifact && !queriesPeerCache(connection, "react-native-peer-cache") || native === "gradle" && (!identity.gradleArtifact || !connection.supports("native-gradle-peer-cache")) ? {
997
956
  ...offer,
998
957
  artifact: null
999
958
  } : offer
@@ -1022,7 +981,7 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1022
981
  const swiftpmQuery = swiftpmArtifact?.artifactInputs ? swiftpmArtifactQuery({
1023
982
  project: identity.project,
1024
983
  sourceDigest: manifestDigest(await sourceManifest(identity.repoRoot, true, runCancellationSignal(ambientContext()) ?? ambientContext()?.signal)),
1025
- stimBuild: target.local.stimBuild,
984
+ compat: target.local.compat,
1026
985
  inputs: swiftpmArtifact.artifactInputs,
1027
986
  build: {
1028
987
  product: swiftpmArtifact.product,
@@ -1085,6 +1044,17 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1085
1044
  ...swiftpmQuery ? { swiftpmArtifact: swiftpmQuery } : {}
1086
1045
  };
1087
1046
  }
1047
+ function startJdk(choice) {
1048
+ const { target, connection } = choice;
1049
+ return target.platform === "android" && target.local.jdk && connection.supports("build-jdk") ? { jdk: target.local.jdk } : {};
1050
+ }
1051
+ function startCompat(choice) {
1052
+ return choice.connection.supports("build-compat") ? { compat: choice.target.local.compat } : {};
1053
+ }
1054
+ /** Peer artifact queries carry `compat`, which a stim-server without `build-compat` refuses. */
1055
+ function queriesPeerCache(connection, feature) {
1056
+ return connection.supports(feature) && connection.supports("build-compat");
1057
+ }
1088
1058
  function macosBuildParameters(request, peerCache) {
1089
1059
  return {
1090
1060
  ...request.cacheArtifact === true && peerCache ? { cacheArtifact: true } : {},
@@ -1120,13 +1090,13 @@ async function peerArtifact(choice, request, fingerprint) {
1120
1090
  assetCatalog: request.assetCatalog ?? null
1121
1091
  }
1122
1092
  }))) throw new Error("The SwiftPM artifact query does not match the build request.");
1123
- if (!choice.connection.supports("swiftpm-peer-cache") || manifestDigest(await sourceManifest(choice.identity.repoRoot, true, runCancellationSignal(ambientContext()) ?? ambientContext()?.signal)) !== swiftpm.sourceDigest) return null;
1093
+ if (!queriesPeerCache(choice.connection, "swiftpm-peer-cache") || manifestDigest(await sourceManifest(choice.identity.repoRoot, true, runCancellationSignal(ambientContext()) ?? ambientContext()?.signal)) !== swiftpm.sourceDigest) return null;
1124
1094
  return matchingArtifact(choice.offer, "swiftpm");
1125
1095
  }
1126
1096
  const reactNative = choice.reactNativeArtifact;
1127
1097
  if (reactNative) {
1128
1098
  if (typeof fingerprint !== "string" || !isDeepStrictEqual(reactNative, reactNativeBuildQuery(request, fingerprint, choice.identity.project, choice.target.local))) throw new Error("The React Native artifact query does not match the build request.");
1129
- return choice.connection.supports("react-native-peer-cache") ? matchingArtifact(choice.offer, `react-native-${reactNative.platform}`) : null;
1099
+ return queriesPeerCache(choice.connection, "react-native-peer-cache") ? matchingArtifact(choice.offer, `react-native-${reactNative.platform}`) : null;
1130
1100
  }
1131
1101
  const query = choice.gradleArtifact;
1132
1102
  if (query) {
@@ -1550,18 +1520,20 @@ async function offloadBuild(input) {
1550
1520
  ...choice.connection.supports("native-gradle-artifact-cache") ? { cache: native.cache } : {}
1551
1521
  }
1552
1522
  } } : {},
1553
- ...request.platform === "macos" ? macosBuildParameters(request, choice.connection.supports("swiftpm-peer-cache")) : {
1523
+ ...request.platform === "macos" ? macosBuildParameters(request, queriesPeerCache(choice.connection, "swiftpm-peer-cache")) : {
1554
1524
  configuration: request.platform === "ios" ? request.configuration : null,
1555
1525
  scheme: request.platform === "ios" ? request.scheme : null,
1556
1526
  iosProjectPath: request.platform === "ios" ? request.iosProjectPath ?? null : null,
1557
1527
  runtime: request.platform === "ios" ? request.runtime : null,
1558
1528
  packageName: packageName(join(identity.repoRoot, identity.project)),
1559
1529
  isExpo: request.isExpo,
1560
- ...!native && request.cacheArtifact === true && choice.connection.supports("react-native-peer-cache") ? { cacheArtifact: true } : {},
1530
+ ...!native && request.cacheArtifact === true && queriesPeerCache(choice.connection, "react-native-peer-cache") ? { cacheArtifact: true } : {},
1561
1531
  optimizations: request.platform === "ios" && isJsonObject(request.optimizations) ? request.optimizations : null,
1562
1532
  ...request.platform === "android" ? { android: request.android } : {}
1563
1533
  },
1564
- stimBuild: choice.target.local.stimBuild
1534
+ stimBuild: choice.target.local.stimBuild,
1535
+ ...startCompat(choice),
1536
+ ...startJdk(choice)
1565
1537
  });
1566
1538
  checkCancelled();
1567
1539
  if ("result" in reply) {
@@ -1585,7 +1557,7 @@ async function offloadBuild(input) {
1585
1557
  const { connection, machine } = choice;
1586
1558
  connection.onProgress(null);
1587
1559
  const workerMs = cacheHit ? 0 : Date.now() - workerStarted;
1588
- if (result.ok !== true) return keepCorruptCacheMessage(fail(`${String(result.code ?? "failed")}: ${String(result.message ?? "")}`), result);
1560
+ if (result.ok !== true) return keepCorruptCacheMessage(fail(workerFailureReason(result.code, result.message)), result);
1589
1561
  if (!cacheHit && native && (result.sourceDigest !== sourceDigest || result.fingerprint !== expectedFingerprint)) return fail("The worker returned a different native source or artifact identity.");
1590
1562
  if (native?.provider === "gradle" && !ANDROID_PACKAGE.test(String(result.androidPackage ?? ""))) return fail("The worker returned no verified native APK package.");
1591
1563
  const artifact = result.artifact;
@@ -1736,6 +1708,16 @@ function machineProblems(offer, targets) {
1736
1708
  }
1737
1709
  return problems;
1738
1710
  }
1711
+ /** What a build on a machine that would take it does beyond the match, for each of `targets`, labeled like `machineProblems`. */
1712
+ function machineNotes(offer, targets) {
1713
+ const notes = [];
1714
+ if (machineProblems(offer, targets).length) return notes;
1715
+ for (const target of targets) for (const note of toolchainNotes(target, offer.toolchain)) notes.push(targets.length > 1 ? {
1716
+ ...note,
1717
+ reason: `${PLATFORM_LABEL[target.platform]}: ${note.reason}`
1718
+ } : note);
1719
+ return notes;
1720
+ }
1739
1721
  const DOCTOR_CONNECT_MS = 5e3;
1740
1722
  const DOCTOR_OFFER_MS = 8e3;
1741
1723
  const PLATFORM_LABEL = {
@@ -1793,11 +1775,13 @@ function offloadCheck(projectRoot, targets) {
1793
1775
  };
1794
1776
  probe.connection.close();
1795
1777
  resolved ??= targets();
1778
+ const judged = await resolved;
1796
1779
  return {
1797
1780
  capacity: probe.offer.capacity,
1798
- problems: machineProblems(probe.offer, await resolved)
1781
+ problems: machineProblems(probe.offer, judged),
1782
+ notes: machineNotes(probe.offer, judged)
1799
1783
  };
1800
1784
  };
1801
1785
  }
1802
1786
  //#endregion
1803
- export { COMPILATION_CACHE_CORRUPT as C, setRemoteLogSink as S, maintenanceLogger as T, nativeGradleLocalSourceDigest as _, nativeTransferRefusal as a, validateGradleManifest as b, offloadPlacement as c, simulatorRuntime as d, reactNativeArtifactReceipt as f, gradleStateDirectories as g, gradleOffloadInputs as h, closeOffload as i, placementLoad as l, reactNativeBuildQuery as m, buildPlacementCandidates as n, offloadBuild as o, reactNativeArtifactToolchain as p, chooseBuildMachine as r, offloadCheck as s, BuildConnection as t, remotePhaseText as u, nativeGradleOutputs as v, clearCorruptCompilationCache as w, verifyGradleTransfer as x, nativeGradleTransfer as y };
1787
+ export { COMPILATION_CACHE_CORRUPT as C, setRemoteLogSink as S, nativeGradleLocalSourceDigest as _, nativeTransferRefusal as a, validateGradleManifest as b, offloadPlacement as c, simulatorRuntime as d, reactNativeArtifactReceipt as f, gradleStateDirectories as g, gradleOffloadInputs as h, closeOffload as i, placementLoad as l, reactNativeBuildQuery as m, buildPlacementCandidates as n, offloadBuild as o, reactNativeArtifactToolchain as p, chooseBuildMachine as r, offloadCheck as s, BuildConnection as t, remotePhaseText as u, nativeGradleOutputs as v, clearCorruptCompilationCache as w, verifyGradleTransfer as x, nativeGradleTransfer as y };
@@ -1,11 +1,11 @@
1
1
  import { S as process_identity_exports } from "./exec-VFRpu1iA.mjs";
2
- import { m as workspaceLogsDir } from "./paths-DQtTgsBf.mjs";
3
- import { V as deviceSlotKey, q as validateDeviceSlot } from "./config-BZhXY15H.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";
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-CX5IcRuf.mjs";
5
+ import { c as watchAppPid, i as parseLogcatLine, o as startAndroidLogcat, s as waitForAppPid, t as androidClockOffset } from "./android-B5P81yI-.mjs";
6
6
  import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
7
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-DxlZGDcV.mjs";
8
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-BjYvMNX_.mjs";
9
9
  import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-ENC4sRPA.mjs";
10
10
  import { existsSync } from "node:fs";
11
11
  import { isAbsolute, join, resolve } from "node:path";
@@ -1,5 +1,5 @@
1
1
  import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
2
- import { t as NO_PROJECT_REFUSAL } from "./project-Dz-hWkb-.mjs";
2
+ import { t as NO_PROJECT_REFUSAL } from "./project-BUu6Is4k.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