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
@@ -8,7 +8,7 @@ import { readFileSync as readFileSync$1 } from "fs";
8
8
  import { Command } from "commander";
9
9
  import "@expo/fingerprint";
10
10
  import { CacheProviderConfig, loadCacheProvider } from "@stim-cli/cache";
11
- import { BuildReactNativeArtifactQuery, BuildSwiftpmArtifactQuery, GradleOffloadInputs, HelloResult } from "@stim-cli/core/protocol";
11
+ import { BuildReactNativeArtifactQuery, BuildSwiftpmArtifactQuery, GradleOffloadInputs, HelloResult, RemoteDiagnosis } from "@stim-cli/core/protocol";
12
12
  import { ChildProcess } from "node:child_process";
13
13
  //#region src/engine/build-facts.d.ts
14
14
  type CacheHitLevel = "local" | "remote" | false;
@@ -221,31 +221,79 @@ interface AndroidBuildPlan {
221
221
  //#region src/offload/toolchain.d.ts
222
222
  /** What must be identical on this Mac and a remote Mac for an iOS simulator build to come out the same. */
223
223
  interface IosToolchain {
224
- /** A digest of Stim's built code, so both sides prove they run the same Stim. */
224
+ /** A digest of Stim's built code, compared only with a remote machine that reports no `compat`. */
225
225
  stimBuild: string | null;
226
+ /** The Stim build compatibility version both sides must share. */
227
+ compat: number;
226
228
  arch: string;
227
229
  xcode: string | null;
228
230
  simulatorSdk: string | null;
229
231
  cocoapods: string | null;
230
232
  }
233
+ /** An Xcode app in `/Applications`, with the license and first-launch checks of its developer directory when they ran. */
234
+ interface XcodeApp {
235
+ path: string;
236
+ version: string | null;
237
+ build: string | null;
238
+ license?: boolean;
239
+ firstLaunch?: boolean;
240
+ }
231
241
  /** A remote machine's toolchain, the simulator runtimes it can build for, and its JDK and Android SDK packages. */
232
- interface WorkerToolchain extends IosToolchain {
242
+ interface WorkerToolchain extends Omit<IosToolchain, "compat"> {
243
+ /** Absent from a stim-server older than build compatibility versions. */
244
+ compat?: number;
233
245
  /** The OS stim-server runs on, as Node names it; absent from a stim-server older than this field. */
234
246
  os?: string;
235
247
  macosSdk: string | null;
236
248
  bundler: string | null;
237
249
  runtimes: string[];
250
+ /** The developer directory `xcode-select -p` prints, null when it prints none; absent from a stim-server older than this field. */
251
+ developerDir?: string | null;
252
+ /** The Xcode apps in `/Applications`; their license and first-launch checks run only while `xcode` is null. */
253
+ xcodeApps?: XcodeApp[];
238
254
  jdk: string | null;
255
+ /** The majors of every JDK found on the machine, `jdk` included; absent from a stim-server older than this field. */
256
+ jdks?: string[];
239
257
  androidSdk: {
240
258
  ndk: string[];
241
259
  buildTools: string[];
242
260
  platforms: string[];
243
261
  } | null;
262
+ /** Whether that SDK has its licenses accepted, so Gradle can download a missing package; absent from a stim-server older than this field. */
263
+ androidLicenses?: boolean;
264
+ /** The SDK directory `androidSdk` was read from, for the commands that install into it; absent from a stim-server older than this field. */
265
+ androidHome?: string;
244
266
  }
245
267
  /** One reason a remote machine cannot take this build now, with a stable `code` for doctor's JSON. */
246
268
  interface OffloadProblem {
247
269
  code: "unreachable" | "checkout" | "stim-build" | "arch" | "xcode" | "macos-sdk" | "simulator-sdk" | "cocoapods" | "bundler" | "runtime" | "jdk" | "android-sdk" | "ndk" | "build-tools" | "compile-sdk" | "disk" | "busy" | "platform";
248
270
  reason: string;
271
+ /** Shell commands that clear it, to run on the remote machine, and what they do, as the end of "On <machine>, ...". */
272
+ commands?: string[];
273
+ lead?: string;
274
+ /** The problem whose fix also clears this one, so it carries no fix of its own. */
275
+ followsFrom?: OffloadProblem["code"];
276
+ }
277
+ //#endregion
278
+ //#region src/offload/diagnosis.d.ts
279
+ type Transport = {
280
+ kind: "http";
281
+ status: number;
282
+ } | {
283
+ kind: "refused";
284
+ } | {
285
+ kind: "silent";
286
+ } | {
287
+ kind: "tls";
288
+ message: string;
289
+ } | {
290
+ kind: "other";
291
+ message: string;
292
+ };
293
+ /** What a peer's `/health` says about a server that answered 503 (see `peerHealth` in stim-server). */
294
+ interface PeerStartup {
295
+ state: "pending" | "degraded";
296
+ cause?: "home-unreadable" | "start-failed";
249
297
  }
250
298
  //#endregion
251
299
  //#region src/offload/tailnet.d.ts
@@ -287,11 +335,18 @@ type HelloReply = {
287
335
  };
288
336
  } | {
289
337
  failed: string;
338
+ transport?: Transport;
290
339
  };
291
340
  interface TailnetMachineIo {
292
341
  /** `tailscale status --json`, or null when Tailscale is not running. */
293
342
  status: () => unknown;
294
343
  hello: (endpoint: Endpoint, auth: MachineAuth) => Promise<HelloReply>;
344
+ /** `tailscale status --json` whatever its backend state, or null when no command answered; says why `status` is null. */
345
+ rawStatus?: () => unknown;
346
+ /** The `startup` of the peer's `/health` after a 503, or null when it says none. */
347
+ startup?: (endpoint: Endpoint) => Promise<PeerStartup | null>;
348
+ /** Whether `tailscale ping` gets an answer from the peer's address. */
349
+ ping?: (address: string) => Promise<boolean>;
295
350
  }
296
351
  type GeneratedTickets = Map<string, {
297
352
  ticket: string;
@@ -307,6 +362,7 @@ type GeneratedTickets = Map<string, {
307
362
  interface BuildMachineReport {
308
363
  machine: string;
309
364
  state: "invalid" | "tailscale-off" | "not-on-tailnet" | "key-changed" | "not-asked" | "pending" | "approved" | "revoked" | "lapsed" | "outdated" | "unreachable";
365
+ diagnosis?: RemoteDiagnosis;
310
366
  dnsName?: string;
311
367
  deviceId?: string;
312
368
  requestedAt?: string;
@@ -317,6 +373,8 @@ interface BuildMachineReport {
317
373
  reasons?: string[];
318
374
  /** The same reasons with the code of each, in the same order. */
319
375
  problems?: OffloadProblem[];
376
+ /** What a build there does beyond the match, such as downloading an SDK package; none of it stops the build. */
377
+ notes?: OffloadProblem[];
320
378
  /** The machine's reported capacity, when it answered an offer. */
321
379
  capacity?: Record<string, unknown>;
322
380
  }
package/dist/api.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as IosFacts, a as BuildMachinesInspection, d as DoctorPlatform, f as Finding, g as CompilationCacheActivity, h as CcacheActivity, m as AndroidFacts, n as WebLaunched, o as GeneratedTickets, s as TailnetMachineIo, u as BudgetReport } from "./android-project-DVWyCbWU.mjs";
1
+ import { _ as IosFacts, a as BuildMachinesInspection, d as DoctorPlatform, f as Finding, g as CompilationCacheActivity, h as CcacheActivity, m as AndroidFacts, n as WebLaunched, o as GeneratedTickets, s as TailnetMachineIo, u as BudgetReport } from "./android-project-DUGMbq28.mjs";
2
2
  import { a as WorkspaceLaunchPlatform } from "./ios-CDvlmUs7.mjs";
3
3
  import "./exec-DnYc4HGH.mjs";
4
4
  import "./pull-request-eODyIqZF.mjs";
@@ -8,7 +8,7 @@ import { AgentDeviceUsage, ArchivedWorkspace, BuildPlanPayload, MacosBuild, Maco
8
8
  import { statSync } from "fs";
9
9
  import { Command } from "commander";
10
10
  import { ToolchainEntry } from "@stim-cli/core/toolchain";
11
- import { HelloResult, PlatformBuildOptions, PlatformRunOptions } from "@stim-cli/core/protocol";
11
+ import { HelloResult, PlatformBuildOptions, PlatformRunOptions, RemoteDiagnosis } from "@stim-cli/core/protocol";
12
12
  //#region src/engine/device-lease.d.ts
13
13
  type LeasePlatform = "ios" | "android";
14
14
  interface ReleasedLease {
@@ -19,7 +19,7 @@ interface ReleasedLease {
19
19
  }
20
20
  //#endregion
21
21
  //#region src/commands/gc/results.d.ts
22
- type GcResultKind = "archive" | "device" | "parkedDevice" | "parkedHostedDevice" | "idleDevice" | "deviceRecord" | "workspaceOutputs" | "recording" | "workspaceDirectory" | "project" | "buildLock" | "buildSlot" | "deviceLease" | "easSession" | "worktree" | "cache" | "statusCache" | "tempLeftover" | "trash" | "watchmanRoot" | "watchman" | "gradleDaemon" | "gradleVersion" | "kotlinDaemon";
22
+ type GcResultKind = "archive" | "device" | "parkedDevice" | "parkedHostedDevice" | "idleDevice" | "deviceRecord" | "workspaceOutputs" | "recording" | "workspaceDirectory" | "project" | "buildLock" | "buildSlot" | "deviceLease" | "easSession" | "worktree" | "cache" | "statusCache" | "tempLeftover" | "trash" | "watchmanRoot" | "watchman" | "gradleDaemon" | "gradleVersion" | "kotlinDaemon" | "devServer" | "workspaceLogs" | "ledgerEntry" | "easLedgerEntry";
23
23
  type GcResultStatus = "done" | "kept" | "failed";
24
24
  interface GcResult {
25
25
  kind: GcResultKind;
@@ -214,6 +214,7 @@ interface StimVersionReport {
214
214
  interface MachineReport {
215
215
  machine: string;
216
216
  state: "invalid" | "tailscale-off" | "not-on-tailnet" | "key-changed" | "not-asked" | "pending" | "approved" | "revoked" | "lapsed" | "outdated" | "unreachable" | "credentials-unavailable" | "busy";
217
+ diagnosis?: RemoteDiagnosis;
217
218
  dnsName?: string;
218
219
  deviceId?: string;
219
220
  requestedAt?: string;
@@ -779,6 +780,8 @@ interface RunGcOptions {
779
780
  delete?: boolean;
780
781
  worktrees?: boolean;
781
782
  json?: boolean;
783
+ /** False reports worktree build-state sizes only from the disk-usage cache: a stale one is unmeasured (null), and no `du` runs for it. */
784
+ measureBuildState?: boolean;
782
785
  }
783
786
  interface GcRefusal {
784
787
  code: string;
@@ -801,7 +804,7 @@ type GcPayload = {
801
804
  results: GcResult[];
802
805
  inventory: GcInventory | null;
803
806
  } | GcRefusal;
804
- type GcReadOptions = Pick<RunGcOptions, "olderThan" | "cache" | "worktrees">;
807
+ type GcReadOptions = Pick<RunGcOptions, "olderThan" | "cache" | "worktrees" | "measureBuildState">;
805
808
  //#endregion
806
809
  //#region src/commands/reload.d.ts
807
810
  type ReloadPlatform = WorkspaceLaunchPlatform | "web";
@@ -951,7 +954,7 @@ type StimGcOptions = GcReadOptions & StimReadOptions;
951
954
  type StimGcReport = Exclude<GcPayload, {
952
955
  code: string;
953
956
  }>;
954
- type StimGcMutationOptions = StimGcOptions & {
957
+ type StimGcMutationOptions = Omit<StimGcOptions, "measureBuildState"> & {
955
958
  delete?: boolean;
956
959
  /** Shuts down owned devices idle for at least this many milliseconds, including without `delete`. */
957
960
  idleMs?: number;
package/dist/api.mjs CHANGED
@@ -1,31 +1,30 @@
1
1
  import { D as ownership_claim_exports, T as trackReportResource, b as operationState, c as throwIfCancelled, l as WorkspaceProcessCleanupError, s as cancelledError, w as runReport } from "./exec-VFRpu1iA.mjs";
2
- import { d as workspaceDir, m as workspaceLogsDir$1, r as ensureWorkspaceStorageAsync } from "./paths-DQtTgsBf.mjs";
3
- import { E as upsertProject, O as withConfigLockAsync$1, p as getProject, q as validateDeviceSlot, y as refuseRelativeStimPaths } from "./config-BZhXY15H.mjs";
4
- import { l as phaseLine } from "./command-output-DxC0k2rk.mjs";
5
- import { a as recordWorkspaceUseAsync } from "./workspace-state-CeBpIZgr.mjs";
6
- import { J as resolveProjectSettingsAsync, Nt as repoRootAsync, a as SETTING_SHAPE_REMEDY, et as settingShapeErrors, it as unknownSettingKeys, p as cacheProviderSettingError } from "./settings-RKwY33wv.mjs";
7
- import { c as projectProblem, f as projectRegistry, i as findProjectRoot$1, r as findCommandWorkspaceAsync, t as NO_PROJECT_REFUSAL } from "./project-Dz-hWkb-.mjs";
8
- import { n as macosDir } from "./state-BfAltYJP.mjs";
9
- import { c as ensureHomeIdentity, s as workspaceShareURL } from "./stim-desktop-DS0mzR8U.mjs";
2
+ import { E as workspaceDir, a as recordWorkspaceUseAsync, k as workspaceLogsDir$1, v as ensureWorkspaceStorageAsync } from "./workspace-state-pUg3_RRA.mjs";
3
+ import { E as upsertProject, O as withConfigLockAsync$1, p as getProject, q as validateDeviceSlot, y as refuseRelativeStimPaths } from "./config-BktkY_zC.mjs";
4
+ import { l as phaseLine } from "./command-output-BF5AR2dL.mjs";
5
+ import { Pt as repoRootAsync, Y as resolveProjectSettingsAsync, a as SETTING_SHAPE_REMEDY, at as unknownSettingKeys, p as cacheProviderSettingError, tt as settingShapeErrors } from "./settings-CosW5X-S.mjs";
6
+ import { c as projectProblem, f as projectRegistry, i as findProjectRoot$1, r as findCommandWorkspaceAsync, t as NO_PROJECT_REFUSAL } from "./project-BUu6Is4k.mjs";
7
+ import { n as macosDir } from "./state-C4OdpOTF.mjs";
8
+ import { c as ensureHomeIdentity, s as workspaceShareURL } from "./stim-desktop-6Dqp-gjX.mjs";
10
9
  import { r as createNdjsonWriter } from "./ndjson-CgE_o3Dl.mjs";
11
- import { B as recordFinishedBuild, H as startBuildProgress, U as tapBuildLog } from "./budget-dPGuhNai.mjs";
12
- import { d as runCancellationSignal, f as withNativeBuildRun } from "./native-run-BmH7U8pr.mjs";
13
- import { c as resolveBuildPlacement } from "./selection-BLtvaqxc.mjs";
14
- import { c as stopWorkspaceNow } from "./stop-CL1kDHds.mjs";
15
- import { r as runReload } from "./reload-C1TTVesC.mjs";
16
- import { c as startDevServer } from "./start-BKGrEhzG.mjs";
17
- import { s as recordDoctorCheck } from "./doctor-watchman-B453A231.mjs";
18
- import { a as readDoctorReport } from "./doctor-DZgpqR6J.mjs";
19
- import { h as warmWorktreeTarget, m as removeWorktreeTarget } from "./worktree-Dw8kfacb.mjs";
20
- import { i as readGcReport, n as executeGc, o as withGcMaintenanceClaim } from "./gc-yVKpAOKM.mjs";
21
- import { r as readWorkspaceLogs, t as followWorkspaceLogs } from "./logs-DXE32kyb.mjs";
10
+ import { K as startBuildProgress, W as recordFinishedBuild, q as tapBuildLog } from "./budget-k2mZGvvk.mjs";
11
+ import { d as runCancellationSignal, f as withNativeBuildRun } from "./native-run-BfIDFKLH.mjs";
12
+ import { l as resolveBuildPlacement } from "./selection-BNPBZ6T5.mjs";
13
+ import { c as stopWorkspaceNow } from "./stop-DRqQVqDJ.mjs";
14
+ import { r as runReload } from "./reload-CCR7KC_l.mjs";
15
+ import { c as startDevServer } from "./start-_BdJ32cZ.mjs";
16
+ import { s as recordDoctorCheck } from "./doctor-watchman-BStK05nt.mjs";
17
+ import { a as readDoctorReport } from "./doctor-Bhg1ii70.mjs";
18
+ import { h as warmWorktreeTarget, m as removeWorktreeTarget } from "./worktree-BKuklFh_.mjs";
19
+ import { i as readGcReport, n as executeGc, o as withGcMaintenanceClaim } from "./gc-ldgr-hXU.mjs";
20
+ import { r as readWorkspaceLogs, t as followWorkspaceLogs } from "./logs-dQDki6Tt.mjs";
22
21
  import { t as readProjectStats } from "./stats-report-n2U5plhk.mjs";
23
- import { n as buildAndroidOperation, t as buildIosOperation } from "./build-CaF574eS.mjs";
24
- import { a as readAndroidBuildPlan, i as runAndroidOperation } from "./android-BZppyPe_.mjs";
25
- import { i as readIosBuildPlan, r as runIosOperation } from "./ios-B1FXRCMX.mjs";
26
- import { a as buildMacosBundle, i as planMacos, n as runMacos } from "./macos-CCfhb-jT.mjs";
27
- import { t as runWeb } from "./web-BH7peScT.mjs";
28
- import { i as SettingsRefusal, o as readSettingsContext, s as readSettingsPayload, t as mutateSetting } from "./settings-write--gj6MACV.mjs";
22
+ import { n as buildAndroidOperation, t as buildIosOperation } from "./build-DPhApsjV.mjs";
23
+ import { a as readAndroidBuildPlan, i as runAndroidOperation } from "./android-CiNQw3kq.mjs";
24
+ import { i as readIosBuildPlan, r as runIosOperation } from "./ios-ftxdQbJS.mjs";
25
+ import { a as buildMacosBundle, i as planMacos, n as runMacos } from "./macos-DBBPNnIA.mjs";
26
+ import { t as runWeb } from "./web-Bihbf7-u.mjs";
27
+ import { i as SettingsRefusal, o as readSettingsContext, s as readSettingsPayload, t as mutateSetting } from "./settings-write-QjYfSrjF.mjs";
29
28
  import { randomBytes } from "node:crypto";
30
29
  import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync } from "node:fs";
31
30
  import { stripVTControlCharacters } from "node:util";
@@ -317,7 +316,7 @@ function createStim(options) {
317
316
  }), () => {});
318
317
  return task;
319
318
  }),
320
- gc: ({ signal, olderThan, cache, worktrees } = {}) => {
319
+ gc: ({ signal, olderThan, cache, worktrees, measureBuildState } = {}) => {
321
320
  if (olderThan !== void 0 && !Number.isSafeInteger(olderThan)) return Promise.reject(new StimError({
322
321
  code: "STIM_BAD_ARG",
323
322
  message: "olderThan must be a whole number of days."
@@ -326,7 +325,8 @@ function createStim(options) {
326
325
  const result = await readGcReport({
327
326
  olderThan,
328
327
  cache,
329
- worktrees
328
+ worktrees,
329
+ measureBuildState
330
330
  }, {
331
331
  operation: context,
332
332
  easLedgerRoot: join(context.env.HOME || context.env.USERPROFILE || homedir(), ".stim", "machine", "eas")
@@ -0,0 +1,142 @@
1
+ import { y as sharedBuildCache } from "./workspace-state-pUg3_RRA.mjs";
2
+ import { E as findBuildTool } from "./android-DTAcRwBC.mjs";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { closeSync, fstatSync, openSync, readFileSync, readSync, realpathSync, renameSync, rmSync } from "node:fs";
5
+ import { basename, dirname, join } from "node:path";
6
+ import { writeFile } from "node:fs/promises";
7
+ //#region src/engine/apk-signed-tail.ts
8
+ const SIGNED_TAIL_FILE = "apk-signed-tail.json";
9
+ const EOCD_SIGNATURE = 101010256;
10
+ const EOCD_MIN_BYTES = 22;
11
+ const EOCD_SEARCH_BYTES = 65557;
12
+ const SIGNING_BLOCK_FOOTER_BYTES = 24;
13
+ const SIGNING_BLOCK_MAGIC = "APK Sig Block 42";
14
+ const SIGNATURE_SCHEME_IDS = /* @__PURE__ */ new Set([1896449818, 4031998144]);
15
+ const SHA256_HEX = /^[0-9a-f]{64}$/;
16
+ const VERIFIED_V2_OR_V3 = /^Verified using v[23] scheme \(APK Signature Scheme v[23]\): true\s*$/m;
17
+ /**
18
+ * The offset where an APK's v2 or v3 signing block starts, or null when the file has no such block, is ZIP64, or is
19
+ * malformed. https://source.android.com/docs/security/features/apksigning/v2#apk-signing-block
20
+ */
21
+ function signingBlockOffset(size, read) {
22
+ if (size < EOCD_MIN_BYTES) return null;
23
+ const searched = Math.min(size, EOCD_SEARCH_BYTES);
24
+ const end = read(size - searched, searched);
25
+ let eocd = -1;
26
+ for (let i = end.length - EOCD_MIN_BYTES; i >= 0; i--) if (end.readUInt32LE(i) === EOCD_SIGNATURE && i + EOCD_MIN_BYTES + end.readUInt16LE(i + 20) === end.length) {
27
+ eocd = i;
28
+ break;
29
+ }
30
+ if (eocd < 0) return null;
31
+ const directoryOffset = end.readUInt32LE(eocd + 16);
32
+ if (directoryOffset === 4294967295 || directoryOffset < 32) return null;
33
+ const footer = read(directoryOffset - SIGNING_BLOCK_FOOTER_BYTES, SIGNING_BLOCK_FOOTER_BYTES);
34
+ if (footer.subarray(8).toString("latin1") !== SIGNING_BLOCK_MAGIC) return null;
35
+ const blockSize = footer.readBigUInt64LE(0);
36
+ if (blockSize < BigInt(SIGNING_BLOCK_FOOTER_BYTES) || blockSize + 8n > BigInt(directoryOffset)) return null;
37
+ const start = directoryOffset - Number(blockSize) - 8;
38
+ const pairs = read(start, Number(blockSize) + 8 - SIGNING_BLOCK_FOOTER_BYTES);
39
+ if (pairs.readBigUInt64LE(0) !== blockSize) return null;
40
+ let position = 8;
41
+ while (position + 12 <= pairs.length) {
42
+ const length = pairs.readBigUInt64LE(position);
43
+ if (length < 4n || length > BigInt(pairs.length - position - 8)) return null;
44
+ if (SIGNATURE_SCHEME_IDS.has(pairs.readUInt32LE(position + 8))) return start;
45
+ position += 8 + Number(length);
46
+ }
47
+ return null;
48
+ }
49
+ function readSignedTail(apkPath) {
50
+ let fd = null;
51
+ try {
52
+ fd = openSync(apkPath, "r");
53
+ const open = fd;
54
+ const size = fstatSync(open).size;
55
+ const read = (position, length) => {
56
+ const buffer = Buffer.alloc(length);
57
+ if (readSync(open, buffer, 0, length, position) !== length) throw new Error("short read");
58
+ return buffer;
59
+ };
60
+ const tailOffset = signingBlockOffset(size, read);
61
+ if (tailOffset === null) return null;
62
+ const tailSha256 = createHash("sha256").update(read(tailOffset, size - tailOffset)).digest("hex");
63
+ return {
64
+ file: basename(apkPath),
65
+ size,
66
+ tailOffset,
67
+ tailSha256
68
+ };
69
+ } catch {
70
+ return null;
71
+ } finally {
72
+ if (fd !== null) try {
73
+ closeSync(fd);
74
+ } catch {}
75
+ }
76
+ }
77
+ const apksignerPath = () => findBuildTool(["apksigner"])?.path ?? null;
78
+ async function computeSignedTail(apkPath, run, findSigner = apksignerPath) {
79
+ const tail = readSignedTail(apkPath);
80
+ if (!tail) return null;
81
+ const signer = findSigner();
82
+ if (!signer) return null;
83
+ try {
84
+ if (!VERIFIED_V2_OR_V3.test(String(await run(signer, [
85
+ "verify",
86
+ "--verbose",
87
+ apkPath
88
+ ])))) return null;
89
+ } catch {
90
+ return null;
91
+ }
92
+ const after = readSignedTail(apkPath);
93
+ return after && after.size === tail.size && after.tailSha256 === tail.tailSha256 ? tail : null;
94
+ }
95
+ function recordedSignedTail(apkPath) {
96
+ try {
97
+ const parsed = JSON.parse(readFileSync(join(dirname(apkPath), SIGNED_TAIL_FILE), "utf-8"));
98
+ if (!parsed || typeof parsed !== "object" || !("file" in parsed) || !("size" in parsed) || !("tailOffset" in parsed) || !("tailSha256" in parsed)) return null;
99
+ const { file, size, tailOffset, tailSha256 } = parsed;
100
+ if (file !== basename(apkPath) || typeof size !== "number" || typeof tailOffset !== "number" || typeof tailSha256 !== "string" || !SHA256_HEX.test(tailSha256) || !Number.isSafeInteger(size) || !Number.isSafeInteger(tailOffset) || tailOffset < 0 || tailOffset >= size) return null;
101
+ const current = readSignedTail(apkPath);
102
+ if (!current || current.size !== size || current.tailOffset !== tailOffset || current.tailSha256 !== tailSha256) return null;
103
+ return {
104
+ file,
105
+ size,
106
+ tailOffset,
107
+ tailSha256
108
+ };
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+ async function writeSignedTail(dir, tail) {
114
+ const target = join(dir, SIGNED_TAIL_FILE);
115
+ const temporary = `${target}.${randomUUID()}.tmp`;
116
+ try {
117
+ await writeFile(temporary, JSON.stringify(tail));
118
+ renameSync(temporary, target);
119
+ } catch (error) {
120
+ rmSync(temporary, { force: true });
121
+ throw error;
122
+ }
123
+ }
124
+ function inBuildCacheEntry(apkPath) {
125
+ try {
126
+ return realpathSync(dirname(dirname(apkPath))) === realpathSync(join(sharedBuildCache(), "android"));
127
+ } catch {
128
+ return false;
129
+ }
130
+ }
131
+ async function signedTailFor(apkPath, run, findSigner) {
132
+ const recorded = recordedSignedTail(apkPath);
133
+ if (recorded || !inBuildCacheEntry(apkPath)) return recorded;
134
+ const computed = await computeSignedTail(apkPath, run, findSigner);
135
+ if (!computed) return null;
136
+ try {
137
+ await writeSignedTail(dirname(apkPath), computed);
138
+ } catch {}
139
+ return computed;
140
+ }
141
+ //#endregion
142
+ export { signedTailFor as n, writeSignedTail as r, computeSignedTail as t };
@@ -1,17 +1,17 @@
1
1
  import { D as ownership_claim_exports, c as throwIfCancelled, x as withDrainingCancellation } from "./exec-VFRpu1iA.mjs";
2
- import { d as workspaceDir } from "./paths-DQtTgsBf.mjs";
3
- import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-DxC0k2rk.mjs";
4
- import { Un as easAuthNote, Wn as isEasAuthFailureText, zn as RESOLVE_TIMEOUT_MS } from "./budget-dPGuhNai.mjs";
5
- import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-BmH7U8pr.mjs";
6
- import { g as providerDownloadPath, h as prepareProviderDownloadDir } from "./build-cache-HFUQ9eLz.mjs";
7
- import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine, t as CCACHE_NOT_RUN } from "./ccache-CCn1S6qG.mjs";
8
- import { c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, u as remotePhaseText } from "./client-18-ZowoT.mjs";
9
- import { i as namedBuildMachine, o as requireLocalBuild, r as fingerprintMismatchRemedy, t as OffloadRefusal } from "./selection-BLtvaqxc.mjs";
10
- import { f as formatDiagnostic } from "./react-native-build-AuCu-aAP.mjs";
11
- import { u as skippedMissReason } from "./prebuild-DmVCf5xb.mjs";
12
- import { t as buildPlacementRecord } from "./placement-log-DUvqqsB-.mjs";
13
- import { n as settleArtifactUploads, t as acquireArtifact } from "./acquire-artifact-CEs02U2o.mjs";
14
- import { a as PLATFORM, h as displayPath } from "./support-B3tzVhKn.mjs";
2
+ import { E as workspaceDir } from "./workspace-state-pUg3_RRA.mjs";
3
+ import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-BF5AR2dL.mjs";
4
+ import { Jn as easAuthNote, Wn as RESOLVE_TIMEOUT_MS, Yn as isEasAuthFailureText } from "./budget-k2mZGvvk.mjs";
5
+ import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-BfIDFKLH.mjs";
6
+ import { v as prepareProviderDownloadDir, y as providerDownloadPath } from "./build-cache-DrXNCy3T.mjs";
7
+ import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine, t as CCACHE_NOT_RUN } from "./ccache-Bx5TbxwG.mjs";
8
+ import { c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, u as remotePhaseText } from "./client-D9CaRks-.mjs";
9
+ import { i as namedBuildMachine, r as fingerprintMismatchRemedy, s as requireLocalBuild, t as OffloadRefusal } from "./selection-BNPBZ6T5.mjs";
10
+ import { f as formatDiagnostic } from "./react-native-build-oNwqF5Wb.mjs";
11
+ import { u as skippedMissReason } from "./prebuild-gmouvmJZ.mjs";
12
+ import { t as buildPlacementRecord } from "./placement-log-DIFPQAXp.mjs";
13
+ import { n as settleArtifactUploads, t as acquireArtifact } from "./acquire-artifact-DVsvSwf7.mjs";
14
+ import { a as PLATFORM, h as displayPath } from "./support-BGSCBoib.mjs";
15
15
  import { t as AndroidRecipeRefusal } from "./android-project-BCAAmMwz.mjs";
16
16
  import { rmSync } from "node:fs";
17
17
  import { join } from "node:path";
@@ -28,7 +28,7 @@ function fail(code, message, remedy, extra = {}) {
28
28
  extra
29
29
  };
30
30
  }
31
- async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe, targetOffloadRefusal, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { acquireLock, releaseLock, waitForBuild, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, acquireSlot, releaseSlot, now }) {
31
+ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe, targetOffloadRefusal, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { acquireLock, releaseLock, waitForBuild, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, storedAppId: entryAppId, acquireSlot, releaseSlot, now }) {
32
32
  const { phase, out, stats, step, miss, hit: lateHit, place, waitingOn, waitingFor } = progress;
33
33
  let fallbackMachine = null;
34
34
  let hereReason = "no remote machine is paired";
@@ -780,18 +780,24 @@ async function acquireAndroidArtifact({ context, root, buildLog, writer, recipe,
780
780
  now
781
781
  }
782
782
  });
783
- if (!acquired.ok) return {
784
- ok: false,
785
- failure: acquired.failure,
786
- ccache: ccacheActivity
787
- };
783
+ if (!acquired.ok) {
784
+ recipe.fingerprintCheck?.()?.cancel();
785
+ return {
786
+ ok: false,
787
+ failure: acquired.failure,
788
+ ccache: ccacheActivity
789
+ };
790
+ }
788
791
  return {
789
792
  ok: true,
790
793
  artifact: {
791
794
  apkPath: acquired.artifact,
792
795
  handoff,
793
796
  androidPackage,
797
+ apkPackage: record.cacheHit && storeKey ? entryAppId(PLATFORM, storeKey) : null,
798
+ fingerprintCheck: recipe.fingerprintCheck?.() ?? null,
794
799
  release: async () => {
800
+ recipe.fingerprintCheck?.()?.cancel();
795
801
  await settleArtifactUploads(providerUpload, uploadPending);
796
802
  acquired.release();
797
803
  },
@@ -1,17 +1,17 @@
1
1
  import { D as ownership_claim_exports, c as throwIfCancelled, x as withDrainingCancellation } from "./exec-VFRpu1iA.mjs";
2
- import { d as workspaceDir } from "./paths-DQtTgsBf.mjs";
3
- import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-DxC0k2rk.mjs";
4
- import { Un as easAuthNote, Wn as isEasAuthFailureText, zn as RESOLVE_TIMEOUT_MS } from "./budget-dPGuhNai.mjs";
5
- import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-BmH7U8pr.mjs";
6
- import { _ as providerUploadOutcome, g as providerDownloadPath, h as prepareProviderDownloadDir } from "./build-cache-HFUQ9eLz.mjs";
7
- import { o as compilationCacheActivityLine, t as COMPILATION_CACHE_NOT_RUN } from "./xcode-DHu41qQ4.mjs";
8
- import { C as COMPILATION_CACHE_CORRUPT, c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, u as remotePhaseText, w as clearCorruptCompilationCache } from "./client-18-ZowoT.mjs";
9
- import { i as namedBuildMachine, o as requireLocalBuild, r as fingerprintMismatchRemedy, t as OffloadRefusal } from "./selection-BLtvaqxc.mjs";
10
- import { S as xcodeFailureReport, p as printDiagnostics } from "./support-B1W-hmC2.mjs";
11
- import { u as skippedMissReason } from "./prebuild-DmVCf5xb.mjs";
12
- import { t as buildPlacementRecord } from "./placement-log-DUvqqsB-.mjs";
13
- import { n as settleArtifactUploads, t as acquireArtifact } from "./acquire-artifact-CEs02U2o.mjs";
14
- import { r as finishIosUpload, t as IosRecipeRefusal } from "./ios-project-KYqeJURj.mjs";
2
+ import { E as workspaceDir } from "./workspace-state-pUg3_RRA.mjs";
3
+ import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-BF5AR2dL.mjs";
4
+ import { Jn as easAuthNote, Wn as RESOLVE_TIMEOUT_MS, Yn as isEasAuthFailureText } from "./budget-k2mZGvvk.mjs";
5
+ import { d as runCancellationSignal, r as cancelledFailure } from "./native-run-BfIDFKLH.mjs";
6
+ import { b as providerUploadOutcome, v as prepareProviderDownloadDir, w as storedAppId, y as providerDownloadPath } from "./build-cache-DrXNCy3T.mjs";
7
+ import { P as compilationCacheActivityLine, k as COMPILATION_CACHE_NOT_RUN } from "./toolchain-J4J8MrAr.mjs";
8
+ import { C as COMPILATION_CACHE_CORRUPT, c as offloadPlacement, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, r as chooseBuildMachine, s as offloadCheck, u as remotePhaseText, w as clearCorruptCompilationCache } from "./client-D9CaRks-.mjs";
9
+ import { i as namedBuildMachine, o as podsFailedRemedy, p as predictedRefusal, r as fingerprintMismatchRemedy, s as requireLocalBuild, t as OffloadRefusal } from "./selection-BNPBZ6T5.mjs";
10
+ import { S as xcodeFailureReport, p as printDiagnostics } from "./support-CVOCp0Ft.mjs";
11
+ import { f as settleFingerprintCheck, u as skippedMissReason } from "./prebuild-gmouvmJZ.mjs";
12
+ import { t as buildPlacementRecord } from "./placement-log-DIFPQAXp.mjs";
13
+ import { n as settleArtifactUploads, t as acquireArtifact } from "./acquire-artifact-DVsvSwf7.mjs";
14
+ import { r as finishIosUpload, t as IosRecipeRefusal } from "./ios-project-Ty5pHl9O.mjs";
15
15
  import { rmSync } from "node:fs";
16
16
  import { join } from "node:path";
17
17
  import { machineCapacity } from "@stim-cli/core/state";
@@ -354,6 +354,13 @@ async function acquireIosArtifact({ context, root, logFile, recipe, physical, co
354
354
  if (mode !== "off") phase("build", `placement: here (${placement.reason})`);
355
355
  return null;
356
356
  }
357
+ const named = machines.find((each) => each.machine === buildMachine);
358
+ const offload = recipe.offload;
359
+ if (placement.code === "named" && named && offload && runtime) {
360
+ const { problems } = await offloadCheck(root, async () => [await offload.target(runtime)])(named);
361
+ const predicted = predictedRefusal(buildMachine, problems);
362
+ if (predicted) throw new OffloadRefusal(buildMachine, predicted.reason, predicted.remedy);
363
+ }
357
364
  return {
358
365
  cacheOnly: false,
359
366
  mode,
@@ -364,14 +371,17 @@ async function acquireIosArtifact({ context, root, logFile, recipe, physical, co
364
371
  machines
365
372
  };
366
373
  }
374
+ let localCocoapods = null;
367
375
  /** Asks the paired machines once the post-mutation key is known; null builds here. */
368
376
  async function chooseMachine(candidate) {
369
377
  const offload = recipe.offload;
370
378
  if (!offload) return null;
371
379
  let asked = [];
380
+ const target = await offload.target(candidate.runtime);
381
+ localCocoapods = target.platform === "ios" ? target.local.cocoapods : null;
372
382
  const choice = await chooseBuildMachine({
373
383
  projectRoot: root,
374
- target: await offload.target(candidate.runtime),
384
+ target,
375
385
  mode: candidate.mode,
376
386
  here: candidate.here,
377
387
  note: (line) => note(chalk.dim(phaseLine("build", `offload: ${line}`))),
@@ -484,7 +494,7 @@ async function acquireIosArtifact({ context, root, logFile, recipe, physical, co
484
494
  fallBack(`${choice.machine}: ${why}`, `offload failed: ${why}`, {
485
495
  code: corrupt === void 0 ? "offload-failed" : COMPILATION_CACHE_CORRUPT,
486
496
  machine: choice.machine,
487
- remedy: outcome.ok ? void 0 : fingerprintMismatchRemedy(outcome.reason)
497
+ remedy: outcome.ok ? void 0 : fingerprintMismatchRemedy(outcome.reason) ?? podsFailedRemedy(choice.machine, outcome.reason, localCocoapods)
488
498
  });
489
499
  logWriter().write({
490
500
  src: "build",
@@ -778,18 +788,21 @@ async function acquireIosArtifact({ context, root, logFile, recipe, physical, co
778
788
  logFile,
779
789
  deps: d
780
790
  });
781
- if (!acquired.ok) return {
782
- ok: false,
783
- failure: acquired.failure,
784
- compilationCache
785
- };
791
+ if (!acquired.ok) {
792
+ recipe.fingerprintCheck?.()?.cancel();
793
+ return {
794
+ ok: false,
795
+ failure: acquired.failure,
796
+ compilationCache
797
+ };
798
+ }
786
799
  appPath = acquired.artifact;
787
800
  return {
788
801
  ok: true,
789
802
  artifact: {
790
803
  handoff,
791
804
  path: appPath,
792
- bundleId,
805
+ bundleId: bundleId ?? (cacheHit && storeKey ? storedAppId("ios", storeKey) : null),
793
806
  cache: {
794
807
  identity: storeHash && storeKey ? {
795
808
  fingerprint: storeHash,
@@ -822,8 +835,10 @@ async function acquireIosArtifact({ context, root, logFile, recipe, physical, co
822
835
  if (outcome.warn) note(chalk.yellow(phaseLine("cache", outcome.line)));
823
836
  else phase("cache", outcome.line);
824
837
  }
838
+ await settleFingerprintCheck(recipe.fingerprintCheck?.() ?? null, "ios", (line) => note(chalk.yellow(phaseLine("fingerprint", line))), (record) => logWriter().write(record));
825
839
  return abandonedRemote || uploadWasAbandoned;
826
840
  },
841
+ cancelFingerprintCheck: () => recipe.fingerprintCheck?.()?.cancel(),
827
842
  release: async () => {
828
843
  await settleArtifactUploads(providerUpload, uploadPending);
829
844
  acquired.release();
@@ -10,13 +10,15 @@ function due(state, settings, now, attemptedAt) {
10
10
  pressure: settings.pressureCheckMinutes * 6e4,
11
11
  size: settings.sizeCheckMinutes * 6e4,
12
12
  worktree: settings.removeFinishedWorktrees ? settings.worktreeCheckMinutes * 6e4 : Infinity,
13
- sweep: settings.sweepHours > 0 ? settings.sweepHours * 36e5 : Infinity
13
+ sweep: settings.sweepHours > 0 ? settings.sweepHours * 36e5 : Infinity,
14
+ idle: settings.idleCheckMinutes * 6e4
14
15
  };
15
16
  return [
16
17
  "pressure",
17
18
  "size",
18
19
  "worktree",
19
- "sweep"
20
+ "sweep",
21
+ "idle"
20
22
  ].filter((check) => {
21
23
  if (intervalMs[check] === Infinity || elapsed(state?.deferredAt?.[check]) < DEFERRED_RETRY_MS) return false;
22
24
  return elapsed(state?.lastAt[check]) >= intervalMs[check];
@@ -1,18 +1,17 @@
1
1
  import { D as ownership_claim_exports, S as process_identity_exports, c as throwIfCancelled, l as WorkspaceProcessCleanupError, s as cancelledError, t as getExecutor, u as withWorkspaceProcessLock } from "./exec-VFRpu1iA.mjs";
2
- import { d as workspaceDir, m as workspaceLogsDir$1 } from "./paths-DQtTgsBf.mjs";
3
- import { p as getProject } from "./config-BZhXY15H.mjs";
4
- import { l as phaseLine } from "./command-output-DxC0k2rk.mjs";
5
- import { l as withWorkspaceStateLockAsync, r as readWorkspaceState$1 } from "./workspace-state-CeBpIZgr.mjs";
6
- import { a as SETTING_SHAPE_REMEDY, at as webSettings, j as metroPortSetting } from "./settings-RKwY33wv.mjs";
7
- import { b as isPackageResolvable, v as detectIsExpo } from "./project-Dz-hWkb-.mjs";
8
- import { d as resolveProjectMetro } from "./metro-Bu8LBfzS.mjs";
2
+ import { E as workspaceDir, k as workspaceLogsDir$1, l as withWorkspaceStateLockAsync, r as readWorkspaceState$1 } from "./workspace-state-pUg3_RRA.mjs";
3
+ import { p as getProject } from "./config-BktkY_zC.mjs";
4
+ import { l as phaseLine } from "./command-output-BF5AR2dL.mjs";
5
+ import { M as metroPortSetting, a as SETTING_SHAPE_REMEDY, ot as webSettings } from "./settings-CosW5X-S.mjs";
6
+ import { b as isPackageResolvable, v as detectIsExpo } from "./project-BUu6Is4k.mjs";
7
+ import { d as resolveProjectMetro } from "./metro-CjC10t6E.mjs";
9
8
  import { s as readNdjsonGenerations$1 } from "./ndjson-CgE_o3Dl.mjs";
10
- import { f as webLogFile, m as webSupervisorLogFile, o as readWebRecord, s as updateWebRecord } from "./state-B1ig0Kqy.mjs";
11
- import { nn as readMetroRecords } from "./budget-dPGuhNai.mjs";
12
- import { D as teardownBrowserHeld, g as resolveSupervisorTarget } from "./workspaces-CSV2Orf4.mjs";
13
- import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-BWDuU5oQ.mjs";
9
+ import { f as webLogFile, m as webSupervisorLogFile, o as readWebRecord, s as updateWebRecord } from "./state-C1i2nMOP.mjs";
10
+ import { sn as readMetroRecords } from "./budget-k2mZGvvk.mjs";
11
+ import { D as teardownBrowserHeld, g as resolveSupervisorTarget } from "./workspaces-g2lhdBXF.mjs";
12
+ import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-BG0j1X4g.mjs";
14
13
  import { n as sendToOwnedPage, t as liveWebRecord } from "./page-CzEA_-5_.mjs";
15
- import { o as resolveWorkspaceMetroPort } from "./start-BKGrEhzG.mjs";
14
+ import { o as resolveWorkspaceMetroPort } from "./start-_BdJ32cZ.mjs";
16
15
  import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
17
16
  import { n as windowsLauncherArgs } from "./detached-entry-KmieOKgN.mjs";
18
17
  import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-BvV8ssI3.mjs";