stim 1.20.2 → 1.21.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 (217) hide show
  1. package/README.md +88 -8
  2. package/dist/acquire-artifact-CD4lbiWE.mjs +153 -0
  3. package/dist/act-DHAw2A2S.mjs +2667 -0
  4. package/dist/activity-BzVfHSrY.mjs +1376 -0
  5. package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-zh1vhbLp.mjs} +21 -65
  6. package/dist/{android-HqP1_vB_.mjs → android-BEJ8Jpl7.mjs} +2 -2
  7. package/dist/{android-DCKZrNvV.mjs → android-BLgbNqox.mjs} +128 -78
  8. package/dist/{android-Dlzxshgp.mjs → android-CV_GCELZ.mjs} +5 -5
  9. package/dist/{android-Mz_Inn3w.mjs → android-DUYkNF4u.mjs} +184 -102
  10. package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-Ct5b1xCK.mjs} +7 -6
  11. package/dist/android-cas-compiler.mjs +2 -2
  12. package/dist/android-project-BCAAmMwz.mjs +12 -0
  13. package/dist/api.d.mts +740 -8
  14. package/dist/api.mjs +585 -1
  15. package/dist/{artifact-HSwkIWEQ.mjs → artifact-B8T3S5gi.mjs} +223 -201
  16. package/dist/{artifact-D3czlUvT.mjs → artifact-DAuZ-FNU.mjs} +158 -148
  17. package/dist/{browser-web-CA-F1GQo.mjs → browser-web-QQzVjz3O.mjs} +26 -24
  18. package/dist/budget-Bs6SxxzO.mjs +9154 -0
  19. package/dist/{build-DYDbfkk5.mjs → build-CoPzQRNw.mjs} +144 -96
  20. package/dist/build-cache-DmyR9Zzc.mjs +602 -0
  21. package/dist/build-plan-CaFskB7_.mjs +188 -0
  22. package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DkkqguoK.mjs} +2 -2
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/{ccache-zdKiYQ3E.mjs → ccache-BJRZ9pG3.mjs} +10 -9
  25. package/dist/{cdp-Dq_ypAlJ.mjs → cdp-CWmIUMbw.mjs} +18 -5
  26. package/dist/{chrome-BnzZMqsR.mjs → chrome-B6tfCta1.mjs} +7 -4
  27. package/dist/{cli-CLP3diBm.mjs → cli-0DYf8QhQ.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/client-B7QVOlCr.d.mts +253 -0
  30. package/dist/client-UXD70ZbM.mjs +1406 -0
  31. package/dist/collector-run.d.mts +4 -40
  32. package/dist/collector-run.mjs +9 -8
  33. package/dist/{command-output-BTy8hZ0F.mjs → command-output-B1UrjZHL.mjs} +1 -1
  34. package/dist/config-CYcBF478.mjs +949 -0
  35. package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-CqeBlrEn.mjs} +3 -3
  36. package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-BbKQW83h.mjs} +20 -5
  37. package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-DFRyG1_o.mjs} +1 -1
  38. package/dist/{dev-client-DAWVIGBu.mjs → dev-client-UOeESKm6.mjs} +2 -2
  39. package/dist/device-DCxH7_By.mjs +1068 -0
  40. package/dist/{device-BECOiufl.mjs → device-ExJq8Ei7.mjs} +35 -35
  41. package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-CMlqEcvw.mjs} +43 -13
  42. package/dist/device-host-worker.mjs +65 -61
  43. package/dist/{device-ios-COSi6oS1.mjs → device-ios-DRUeKaFV.mjs} +48 -45
  44. package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-C8raGFoP.mjs} +14 -26
  45. package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-DMRpVX9a.mjs} +5 -5
  46. package/dist/doctor-BLHCYxzi.mjs +2 -0
  47. package/dist/{doctor-kfMBnUw6.mjs → doctor-DTvaDOda.mjs} +281 -317
  48. package/dist/{doctor-CB8oZKCk.mjs → doctor-Dhqebm0q.mjs} +183 -91
  49. package/dist/doctor-fingerprint.mjs +19 -0
  50. package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-Cv1F10Kj.mjs} +40 -21
  51. package/dist/{eas-build-JyfqyHfC.mjs → eas-build-BomfRnFT.mjs} +53 -20
  52. package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-DJwZpy0c.mjs} +26 -208
  53. package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-op6A54yi.mjs} +229 -11
  54. package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-Bf0rZvG9.mjs} +172 -82
  55. package/dist/exec-H20xSg2T.d.mts +65 -0
  56. package/dist/exec-_UbtCQcG.mjs +750 -0
  57. package/dist/gc-C-WwL0yi.mjs +3 -0
  58. package/dist/{gc-qWOMdnER.mjs → gc-_-dCXdyL.mjs} +584 -796
  59. package/dist/git-C3iTsJaZ.mjs +73 -0
  60. package/dist/{guide-G9cAbVAc.mjs → guide-Yqwt2bd6.mjs} +941 -269
  61. package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-Bw-honsd.mjs} +8 -6
  62. package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DB_gBPfY.mjs} +34 -19
  63. package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CUvOf4Vr.mjs} +1 -1
  64. package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-DL_P5AdN.mjs} +77 -43
  65. package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-QI141yKk.mjs} +21 -17
  66. package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-Ksyjgzq-.mjs} +30 -21
  67. package/dist/idle-BVeRGroT.d.mts +24 -0
  68. package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DaKmZi0z.mjs} +11 -10
  69. package/dist/{ios-BwVCF7oA.mjs → ios-CQ68hG9s.mjs} +8 -8
  70. package/dist/{ios-RkW4pnQf.mjs → ios-CpByZy12.mjs} +140 -80
  71. package/dist/{ios-device-B5veSDDQ.mjs → ios-device-CXGP1bsD.mjs} +1 -1
  72. package/dist/{ios-device-D7pi2Sca.mjs → ios-device-CwFMehUS.mjs} +51 -26
  73. package/dist/{ios-project-K9hY_Jab.mjs → ios-project-WuwwBdvW.mjs} +13 -13
  74. package/dist/{ios-nOLJGVdy.mjs → ios-qNJt4dFm.mjs} +1 -1
  75. package/dist/ios-signing-DTTIChGs.mjs +489 -0
  76. package/dist/{ios-state-CBLe1xYw.mjs → ios-state-DvFX-K_l.mjs} +1 -1
  77. package/dist/{ios-Ce7bc7br.mjs → ios-ubFsBzwq.mjs} +129 -86
  78. package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Cc1dttps.mjs} +53 -26
  79. package/dist/{launch-F4sOqAhB.mjs → launch-CD1yVc7U.mjs} +91 -90
  80. package/dist/{launch-C3qJ6Agb.mjs → launch-Zq2mOSDy.mjs} +82 -541
  81. package/dist/logs-BS00Anxf.mjs +352 -0
  82. package/dist/logs-CMm05HxN.mjs +255 -0
  83. package/dist/{macos-D7uDvO-z.mjs → macos-B65--pPd.mjs} +1 -1
  84. package/dist/{macos-Ch5VJmcS.mjs → macos-C-0qJ6zq.mjs} +225 -212
  85. package/dist/macos-run.mjs +1 -1
  86. package/dist/maintenance-run.mjs +122 -247
  87. package/dist/{metro-DnCEjCxs.mjs → metro-DEXpIhHC.mjs} +67 -12
  88. package/dist/{metro-gateway-CX9Xlkq2.mjs → metro-gateway-BMJNlj3E.mjs} +20 -12
  89. package/dist/{named-ports-4WopRPg-.mjs → named-ports-BWTzt6mu.mjs} +8 -63
  90. package/dist/native-android-JACyjTZs.mjs +844 -0
  91. package/dist/{native-gradle-inputs-BsLRrl7u.mjs → native-gradle-inputs-Bep9JcSF.mjs} +128 -140
  92. package/dist/native-inputs-TRTTTRxt.mjs +91 -0
  93. package/dist/native-run-DY_RLx3C.mjs +277 -0
  94. package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-Dg1Q7tfF.mjs} +9 -8
  95. package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-CB2iQeWq.mjs} +27 -18
  96. package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-CXX39F7o.mjs} +96 -47
  97. package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
  98. package/dist/offload-worker.d.mts +1 -46
  99. package/dist/offload-worker.mjs +197 -66
  100. package/dist/{ownership-DCtw_2IA.mjs → ownership-DEmM5vhh.mjs} +3 -3
  101. package/dist/{page-DRHy329N.mjs → page-CPaHeYqj.mjs} +7 -4
  102. package/dist/paths-BsJMoPP2.mjs +12 -0
  103. package/dist/paths-DQtTgsBf.mjs +42 -0
  104. package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BqGbTa61.mjs} +5 -5
  105. package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-Bwj-IjY1.mjs} +6 -6
  106. package/dist/{ports-DdSUicVo.mjs → ports-D-MmCTdv.mjs} +3 -3
  107. package/dist/prebuild-uD_ipCxF.mjs +449 -0
  108. package/dist/{project-_phNIJfs.mjs → project-BZNjmW_8.mjs} +65 -37
  109. package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-Lfetn8Kr.mjs} +2 -2
  110. package/dist/pull-request-zjCSAryH.d.mts +120 -0
  111. package/dist/pull-requests.d.mts +1 -119
  112. package/dist/pull-requests.mjs +1 -1
  113. package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-DuzH0cn3.mjs} +74 -48
  114. package/dist/{gradle-DSrXb6lG.mjs → react-native-build-rhk4smwQ.mjs} +292 -15
  115. package/dist/react-native-doctor-CQpuIMso.mjs +234 -0
  116. package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-Bhq1rJeV.mjs} +46 -28
  117. package/dist/{recordings-D0d5aQt0.mjs → recordings-DYteQSu4.mjs} +12 -9
  118. package/dist/{reload-C8JhxjSh.mjs → reload-CmTRFJaX.mjs} +93 -47
  119. package/dist/reload-DzjSl5P_.mjs +2 -0
  120. package/dist/{remote-BiR6aYjy.mjs → remote-ByYkXdGD.mjs} +15 -10
  121. package/dist/result-DNiS-tTP.mjs +434 -0
  122. package/dist/{run-BtPgpKks.mjs → run-D23HmJMs.mjs} +4 -5
  123. package/dist/selection-CSl9i5qU.mjs +619 -0
  124. package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CxTrvDg8.mjs} +3 -4
  125. package/dist/{server-command-CTtCkmcQ.mjs → server-command-CtzloH3v.mjs} +14 -7
  126. package/dist/server-expo-C-90EhcG.mjs +2 -0
  127. package/dist/{server-expo-DsguMGUF.mjs → server-expo-DT_F_uVI.mjs} +50 -9
  128. package/dist/{settings-B717odTD.mjs → settings-CsJDEXgK.mjs} +234 -24
  129. package/dist/{settings-vk3mJGSm.d.mts → settings-DkdmlelE.d.mts} +6 -4
  130. package/dist/settings-T1gtc3bf.mjs +114 -0
  131. package/dist/settings-write-HyVZ8eQ8.mjs +359 -0
  132. package/dist/settings.schema.json +163 -16
  133. package/dist/{simslim-CCr3rE-A.mjs → simslim-Cgk17SXV.mjs} +14 -12
  134. package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-DF8VfT64.mjs} +15 -20
  135. package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
  136. package/dist/stage-BIS0ydsV.mjs +183 -0
  137. package/dist/{start-BWqzODpb.mjs → start-7lpH7hmN.mjs} +63 -44
  138. package/dist/{start-TXeMmmO2.mjs → start-RChynRDp.mjs} +1 -1
  139. package/dist/{state-D1Icyjlu.mjs → state-C4ZtUisW.mjs} +40 -13
  140. package/dist/{state-CG_OFoaA.mjs → state-XMziexv2.mjs} +3 -2
  141. package/dist/{stats-BoY5sEPU.mjs → stats-53T7OTb9.mjs} +7 -13
  142. package/dist/stats-report-BFfMpWWF.mjs +16 -0
  143. package/dist/{status-WgFbkRzj.mjs → status-BL7jVyAB.mjs} +535 -447
  144. package/dist/status-CSi6tlRq.mjs +2 -0
  145. package/dist/{status-BTA7kKiQ.mjs → status-DqEUSSxs.mjs} +6 -4
  146. package/dist/{status-watch-C23ILtf9.mjs → status-watch-GDCfqpTE.mjs} +187 -22
  147. package/dist/status-worker.d.mts +1 -0
  148. package/dist/status-worker.mjs +19 -0
  149. package/dist/stim-desktop-C12we7lz.mjs +112 -0
  150. package/dist/{stop-DR6VoDIk.mjs → stop-Bk_1qiV6.mjs} +2 -2
  151. package/dist/{stop-BNmBMi1F.mjs → stop-CPzlM1L-.mjs} +138 -98
  152. package/dist/{stop-DPEhunlw.mjs → stop-D7h6jAXQ.mjs} +11 -10
  153. package/dist/supervisor-run.d.mts +8 -17
  154. package/dist/supervisor-run.mjs +63 -27
  155. package/dist/{support-DMTqj3Hm.mjs → support-67vraa1Q.mjs} +18 -11
  156. package/dist/{support-CwjbFs9H.mjs → support-Dlu37g6H.mjs} +12 -12
  157. package/dist/{swiftpm-macos-DRNVJWlb.mjs → swiftpm-macos-p8WZbxKU.mjs} +35 -24
  158. package/dist/toolchain-DhKwp9iI.mjs +2 -0
  159. package/dist/toolchain-Hp9sCpK4.mjs +873 -0
  160. package/dist/{trigger-CigAYjeL.mjs → trigger-BAahxUPq.mjs} +20 -5
  161. package/dist/trigger-Bf3uDcpv.mjs +2 -0
  162. package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-BHX5r0Ei.mjs} +250 -156
  163. package/dist/{web-BDBMxDpx.mjs → web-CJmIj6AI.mjs} +18 -13
  164. package/dist/web-DknQETPs.mjs +2 -0
  165. package/dist/web-run.mjs +11 -12
  166. package/dist/windows-report.d.mts +1 -0
  167. package/dist/windows-report.mjs +18 -0
  168. package/dist/windows-report.ps1 +43 -0
  169. package/dist/workspace-process-lock-1_1OoVW5.mjs +57 -0
  170. package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-Cjuigeeu.mjs} +62 -58
  171. package/dist/{workspaces-C36s2jb9.mjs → workspaces-BccMFmGQ.mjs} +1188 -1079
  172. package/dist/worktree-CK2MpJW5.mjs +2 -0
  173. package/dist/{worktree-CgvJYJ-Q.mjs → worktree-DQ6Zi2Mv.mjs} +304 -53
  174. package/dist/xcode-Zlx3qjEs.mjs +896 -0
  175. package/package.json +7 -5
  176. package/shim/android-optimizations.gradle +7 -5
  177. package/dist/activity-BSV745Kz.mjs +0 -629
  178. package/dist/api-qvOzWyfO.mjs +0 -154
  179. package/dist/api-run.mjs +0 -294
  180. package/dist/app-install-BIKtMfPq.mjs +0 -896
  181. package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
  182. package/dist/budget-f7516Zk0.mjs +0 -4106
  183. package/dist/build-facts-DcLv2HSd.d.mts +0 -111
  184. package/dist/cancellation-C_22VQTH.mjs +0 -24
  185. package/dist/client-qQAaXSUs.mjs +0 -1771
  186. package/dist/config-BYDxlMY3.mjs +0 -562
  187. package/dist/device-DuiPJQSn.mjs +0 -290
  188. package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
  189. package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
  190. package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
  191. package/dist/exec-DqKo9GKJ.mjs +0 -268
  192. package/dist/git-DDfFzkMm.mjs +0 -45
  193. package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
  194. package/dist/logs-BGrEUaEs.mjs +0 -383
  195. package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
  196. package/dist/native-android-D5qc3-_v.mjs +0 -226
  197. package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
  198. package/dist/plan-C4TjdPsR.mjs +0 -260
  199. package/dist/prebuild-DYbucPXy.mjs +0 -212
  200. package/dist/preview-78a9kR_-.mjs +0 -1011
  201. package/dist/react-native-build-CtCccJtb.mjs +0 -239
  202. package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
  203. package/dist/remote-cache-OyOyVIS3.mjs +0 -526
  204. package/dist/result-CaJg5Iat.mjs +0 -186
  205. package/dist/server-expo-Bigriskl.mjs +0 -2
  206. package/dist/settings-BORNaaCO.mjs +0 -402
  207. package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
  208. package/dist/stage-KNTQopqv.mjs +0 -157
  209. package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
  210. package/dist/tailnet-Dh-qiYzG.mjs +0 -265
  211. package/dist/toolchain-BFkAcstd.mjs +0 -2
  212. package/dist/toolchain-DxSsNssu.mjs +0 -1657
  213. package/dist/trigger-9_USgmxz.mjs +0 -2
  214. package/dist/web-Dq-i3wzJ.mjs +0 -2
  215. package/dist/worktree-DpLdCHga.mjs +0 -2
  216. package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
  217. package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
@@ -1,1657 +0,0 @@
1
- import { t as getExecutor } from "./exec-DqKo9GKJ.mjs";
2
- import { b as workspaceDerivedData } from "./workspace-state-DJt_MMvf.mjs";
3
- import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { a as formatElapsed, l as phaseLine } from "./command-output-BTy8hZ0F.mjs";
5
- import { o as androidHome } from "./android-Mz_Inn3w.mjs";
6
- import { a as spawnDeclared } from "./spawn-claims-DVS5RkMS.mjs";
7
- import { p as resolveOptimizations } from "./errors-DzkMYh8Q.mjs";
8
- import { t as cleanLine } from "./server-expo-DsguMGUF.mjs";
9
- import { createRequire } from "node:module";
10
- import { existsSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
11
- import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
12
- import { stimBuildDigest } from "@stim-cli/core/state";
13
- import { fileURLToPath } from "node:url";
14
- import { createHash } from "node:crypto";
15
- import { homedir, tmpdir } from "node:os";
16
- //#region src/engine/bundler.ts
17
- const COCOAPODS_SPEC = /^ {4}cocoapods \(/m;
18
- function bundlerPin(root) {
19
- const gemfile = join(root, "Gemfile");
20
- const lockfile = join(root, "Gemfile.lock");
21
- if (!existsSync(gemfile)) return null;
22
- let lock;
23
- try {
24
- lock = readFileSync(lockfile, "utf-8");
25
- } catch {
26
- return null;
27
- }
28
- if (!COCOAPODS_SPEC.test(lock)) return null;
29
- return {
30
- gemfile,
31
- lockfile
32
- };
33
- }
34
- function podInstallCommand(root, ...args) {
35
- const pod = [
36
- "pod",
37
- "install",
38
- ...args
39
- ].join(" ");
40
- return bundlerPin(root) ? `bundle exec ${pod}` : pod;
41
- }
42
- const BUILD_FAILED = "** BUILD FAILED **";
43
- const POSITIONED = /^(\S[^\t]*?):(\d+):(?:(\d+):)?\s*(?:fatal\s+)?error:\s+(.+)$/;
44
- const UNPOSITIONED = /^(\S[^\t]*?)?\berror:\s+(.+)$/;
45
- const LD_ERROR = /^ld:\s+(?!warning:)(.+)$/;
46
- const UNDEFINED_HEADER = /^(?:ld:\s+)?Undefined symbols?(?:\s+for architecture\s+\S+)?:\s*$/;
47
- const UNDEFINED_SYMBOL = /^\s+"?([^",]+)"?,\s+referenced from:\s*$/;
48
- function undefinedSymbolMessage(symbol) {
49
- return `Undefined symbol: ${symbol}`;
50
- }
51
- const PODS_OUT_OF_SYNC = /The sandbox is not in sync with the Podfile\.lock/;
52
- const SIGNING = [
53
- /No profiles for '.*' were found/,
54
- /requires a development team/i,
55
- /[Cc]ode ?[Ss]igning [Ee]rror/,
56
- /No signing certificate/i,
57
- /code signing is required/i,
58
- /errSecInternalComponent/,
59
- /Provisioning profile .* doesn't (?:include|match)/i
60
- ];
61
- const NO_SUCH_SCHEME = /does not contain a scheme named/;
62
- const CAS_CORRUPT = /not a IncludeTreeRoot node kind/;
63
- const DEVICE_SIGNING_REMEDY = "Set a team and a Development profile for the target's configuration in Xcode > Signing & Capabilities, then build once from Xcode to install the profile. Stim never passes -allowProvisioningUpdates, because registering a device or minting a profile changes your Apple Developer account.";
64
- const SIMULATOR_SIGNING_REMEDY = "Stim builds for the simulator here, which needs no signing. Check CODE_SIGNING_REQUIRED / DEVELOPMENT_TEAM in the target's configuration, or build for a phone with `stim ios --device`.";
65
- function remedyFor(message, root, sdk) {
66
- if (CAS_CORRUPT.test(message)) return "The compilation cache holds a damaged object. Run `stim gc --delete --cache \"compilation cache\"` to empty that cache, then build again. The next build is a cold one.";
67
- if (PODS_OUT_OF_SYNC.test(message)) return `Run \`${root ? podInstallCommand(root) : "pod install"}\` in ios/ (stim ios does this when Podfile.lock and Pods/Manifest.lock disagree), then build again.`;
68
- if (NO_SUCH_SCHEME.test(message)) return "Run `xcodebuild -list` in ios/ to see the schemes this project defines, and share the app scheme so it is visible to the build.";
69
- for (const pattern of SIGNING) if (pattern.test(message)) return sdk.startsWith("iphoneos") ? DEVICE_SIGNING_REMEDY : SIMULATOR_SIGNING_REMEDY;
70
- return null;
71
- }
72
- function fileFromPrefix(prefix) {
73
- const trimmed = String(prefix).trim().replace(/:$/, "");
74
- if (!trimmed) return null;
75
- const head = (trimmed.split(": ")[0] ?? "").trim();
76
- if (!head.includes("/")) return null;
77
- return head;
78
- }
79
- function makeDiagnostic({ file = null, line = null, column = null, message }, root, sdk) {
80
- const text = String(message).trim();
81
- const out = { message: text };
82
- if (file) out.file = file;
83
- if (line !== null && line !== void 0) out.line = line;
84
- if (column !== null && column !== void 0) out.column = column;
85
- out.message = text;
86
- const remedy = remedyFor(text, root, sdk);
87
- if (remedy) out.remedy = remedy;
88
- return out;
89
- }
90
- function dedupeKey(d) {
91
- return `${d.file || ""}|${d.line || ""}|${d.column || ""}|${d.message}`;
92
- }
93
- function createXcodeDiagnosticCollector(root = null, sdk = "iphonesimulator") {
94
- const out = [];
95
- const seen = /* @__PURE__ */ new Set();
96
- let finished = false;
97
- let inUndefinedSymbols = false;
98
- const add = (d) => {
99
- const key = dedupeKey(d);
100
- if (seen.has(key)) return;
101
- seen.add(key);
102
- out.push(d);
103
- };
104
- const push = (line) => {
105
- if (finished) return;
106
- const raw = line.replace(/\r$/, "");
107
- if (inUndefinedSymbols) {
108
- const sym = UNDEFINED_SYMBOL.exec(raw);
109
- if (sym) {
110
- const symbol = sym[1];
111
- if (symbol !== void 0) add(makeDiagnostic({ message: undefinedSymbolMessage(symbol) }, root, sdk));
112
- return;
113
- }
114
- if (/^\s+\S/.test(line) && !/^\S/.test(line)) return;
115
- inUndefinedSymbols = false;
116
- }
117
- if (raw.includes(BUILD_FAILED)) {
118
- finished = true;
119
- return;
120
- }
121
- if (UNDEFINED_HEADER.test(raw)) {
122
- inUndefinedSymbols = true;
123
- return;
124
- }
125
- const ld = LD_ERROR.exec(raw);
126
- if (ld) {
127
- add(makeDiagnostic({ message: `ld: ${ld[1]}` }, root, sdk));
128
- return;
129
- }
130
- const positioned = POSITIONED.exec(raw);
131
- if (positioned) {
132
- const posMsg = positioned[4];
133
- if (posMsg === void 0) return;
134
- add(makeDiagnostic({
135
- file: positioned[1],
136
- line: Number(positioned[2]),
137
- column: positioned[3] === void 0 ? null : Number(positioned[3]),
138
- message: posMsg
139
- }, root, sdk));
140
- return;
141
- }
142
- const plain = UNPOSITIONED.exec(raw);
143
- if (plain) {
144
- const plainMsg = plain[2];
145
- if (plainMsg === void 0) return;
146
- add(makeDiagnostic({
147
- file: fileFromPrefix(plain[1] || ""),
148
- message: plainMsg
149
- }, root, sdk));
150
- }
151
- };
152
- return {
153
- push,
154
- diagnostics: out
155
- };
156
- }
157
- function capDiagnostics(diagnostics, max = 10) {
158
- const list = Array.isArray(diagnostics) ? diagnostics : [];
159
- if (list.length <= max) return {
160
- diagnostics: list.slice(),
161
- truncated: 0
162
- };
163
- return {
164
- diagnostics: list.slice(0, max),
165
- truncated: list.length - max
166
- };
167
- }
168
- function describeDiagnostic(diagnostic) {
169
- if (!diagnostic || typeof diagnostic !== "object") return "";
170
- const { file, line, column, message } = diagnostic;
171
- if (!file) return String(message ?? "");
172
- return `${file}${line ? column ? `:${line}:${column}` : `:${line}` : ""}: ${message}`;
173
- }
174
- //#endregion
175
- //#region src/engine/xcode.ts
176
- function pickXcodeProject(entries) {
177
- const names = (Array.isArray(entries) ? entries : []).filter((e) => typeof e === "string");
178
- const workspaces = names.filter((e) => e.endsWith(".xcworkspace")).toSorted();
179
- const projects = names.filter((e) => e.endsWith(".xcodeproj")).toSorted();
180
- if (workspaces.length > 0) {
181
- const projectNames = new Set(projects.map((p) => basename(p, ".xcodeproj")));
182
- const file = workspaces.find((w) => projectNames.has(basename(w, ".xcworkspace"))) || workspaces[0];
183
- if (file === void 0) return null;
184
- return {
185
- kind: "workspace",
186
- flag: "-workspace",
187
- file,
188
- name: basename(file, ".xcworkspace")
189
- };
190
- }
191
- if (projects.length > 0) {
192
- const file = projects[0];
193
- if (file === void 0) return null;
194
- return {
195
- kind: "project",
196
- flag: "-project",
197
- file,
198
- name: basename(file, ".xcodeproj")
199
- };
200
- }
201
- return null;
202
- }
203
- function parseSchemeList(text) {
204
- const empty = {
205
- name: null,
206
- schemes: []
207
- };
208
- if (typeof text !== "string") return empty;
209
- const start = text.indexOf("{");
210
- const end = text.lastIndexOf("}");
211
- if (start < 0 || end <= start) return empty;
212
- let data;
213
- try {
214
- data = JSON.parse(text.slice(start, end + 1));
215
- } catch {
216
- return empty;
217
- }
218
- if (!data || typeof data !== "object") return empty;
219
- const record = data;
220
- const container = record.workspace || record.project;
221
- if (!container || typeof container !== "object") return empty;
222
- const info = container;
223
- const schemes = Array.isArray(info.schemes) ? info.schemes.filter((s) => typeof s === "string" && s.trim() !== "") : [];
224
- return {
225
- name: typeof info.name === "string" ? info.name : null,
226
- schemes
227
- };
228
- }
229
- const TEST_SCHEME = /(?:UI)?Tests$/;
230
- function pickScheme(schemes, containerName) {
231
- const list = (Array.isArray(schemes) ? schemes : []).filter((s) => typeof s === "string" && s.trim() !== "");
232
- if (list.length === 0) return null;
233
- const name = typeof containerName === "string" ? containerName.trim() : "";
234
- if (name) {
235
- const exact = list.find((s) => s === name);
236
- if (exact) return exact;
237
- const insensitive = list.find((s) => s.toLowerCase() === name.toLowerCase());
238
- if (insensitive) return insensitive;
239
- }
240
- const app = list.filter((s) => !TEST_SCHEME.test(s));
241
- return app.length === 1 ? app[0] : null;
242
- }
243
- const LIST_TIMEOUT_MS = 18e4;
244
- function listSchemes(project, { exec = null } = {}) {
245
- const executor = exec || getExecutor();
246
- try {
247
- return parseSchemeList(executor.runFile("xcodebuild", [
248
- project.flag,
249
- project.path,
250
- "-list",
251
- "-json"
252
- ], { timeoutMs: LIST_TIMEOUT_MS }));
253
- } catch {
254
- return null;
255
- }
256
- }
257
- function resolveScheme(project, { exec = null, scheme: requested = null } = {}) {
258
- const listing = listSchemes(project, { exec });
259
- if (listing === null) return { error: {
260
- code: "STIM_NO_SCHEME",
261
- message: `Could not list schemes for ${project.path}.`,
262
- remedy: `Run \`xcodebuild ${project.flag} ${project.path} -list\` to see what it reports.`
263
- } };
264
- if (requested !== null) {
265
- if (listing.schemes.includes(requested)) return {
266
- scheme: requested,
267
- schemes: listing.schemes
268
- };
269
- return { error: {
270
- code: "STIM_NO_SCHEME",
271
- message: `No shared Xcode scheme named ${JSON.stringify(requested)} in ${project.path}. Available schemes: ${listing.schemes.join(", ") || "none"}.`,
272
- remedy: "Pass an exact available name with --scheme or set it in ios.scheme, or share the intended app scheme in Xcode."
273
- } };
274
- }
275
- let scheme = pickScheme(listing.schemes, listing.name || project.name);
276
- if (!scheme && project.dir) try {
277
- const app = JSON.parse(readFileSync(join(project.appRoot ?? join(project.dir, ".."), "app.json"), "utf8"));
278
- scheme = pickScheme(listing.schemes, app?.name);
279
- } catch {}
280
- if (!scheme) {
281
- const found = listing.schemes.length ? listing.schemes.join(", ") : "none";
282
- return { error: {
283
- code: "STIM_NO_SCHEME",
284
- message: `Could not select an app scheme in ${project.path} (schemes: ${found}).`,
285
- remedy: listing.schemes.length > 0 ? "Pass --scheme <name>, or set ios.scheme, to select the intended shared app scheme. Stim does not guess between unmatched schemes." : "Share the app scheme in Xcode (Product > Scheme > Manage Schemes, tick Shared) so xcodebuild can see it."
286
- } };
287
- }
288
- return {
289
- scheme,
290
- schemes: listing.schemes
291
- };
292
- }
293
- const PREFIX_MAP_TARGET = "/^src";
294
- function prefixMapping(workspaceRoot) {
295
- return `${String(workspaceRoot).replace(/\/+$/, "")}=${PREFIX_MAP_TARGET}`;
296
- }
297
- function compilationPrefixMappings(workspaceRoot, derivedDataPath) {
298
- const source = resolve(workspaceRoot);
299
- const derived = resolve(derivedDataPath);
300
- const mappings = [prefixMapping(source)];
301
- const rel = relative(source, derived);
302
- if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) mappings.push(`${derived}=/^derived-data`);
303
- return mappings.map((mapping) => /[\s"\\]/.test(mapping) ? `"${mapping.replace(/["\\]/g, "\\$&")}"` : mapping).join(" ");
304
- }
305
- const SWIFT_PREFIX_MAPPING_MIN_SWIFT = {
306
- major: 6,
307
- minor: 4
308
- };
309
- function swiftPrefixMappingSupported(version) {
310
- if (!version) return false;
311
- const min = SWIFT_PREFIX_MAPPING_MIN_SWIFT;
312
- return version.major > min.major || version.major === min.major && version.minor >= min.minor;
313
- }
314
- function compilationCacheSettings({ workspaceRoot, derivedDataPath, casPath, xcodeMajor, swiftVersion = null, swiftCacheCompatible = false, ccache = false, optimizations = resolveOptimizations({}, {}).ios }) {
315
- if (xcodeMajor === null || xcodeMajor === void 0) return [];
316
- if (xcodeMajor < 26) return [];
317
- if (ccache) return [];
318
- const swiftMappable = swiftPrefixMappingSupported(swiftVersion);
319
- const auto = swiftMappable && swiftCacheCompatible;
320
- const swift = optimizations.compilationCache && (optimizations.swiftCompilationCache ?? auto);
321
- const mappings = optimizations.prefixMapping ? compilationPrefixMappings(workspaceRoot, derivedDataPath) : "";
322
- return [
323
- `COMPILATION_CACHE_ENABLE_CACHING=${optimizations.compilationCache ? "YES" : "NO"}`,
324
- `COMPILATION_CACHE_CAS_PATH=${casPath}`,
325
- `SWIFT_ENABLE_COMPILE_CACHE=${swift ? "YES" : "NO"}`,
326
- `CLANG_ENABLE_PREFIX_MAPPING=${optimizations.prefixMapping ? "YES" : "NO"}`,
327
- `CLANG_OTHER_PREFIX_MAPPINGS=${mappings}`,
328
- ...swift && swiftMappable && optimizations.prefixMapping ? ["SWIFT_ENABLE_PREFIX_MAPPING=YES", `SWIFT_OTHER_PREFIX_MAPPINGS=${mappings}`] : ["SWIFT_ENABLE_PREFIX_MAPPING=NO"]
329
- ];
330
- }
331
- function parseSwiftVersion(output) {
332
- const m = /\bSwift version (\d+)\.(\d+)/.exec(String(output || ""));
333
- if (!m || m[1] === void 0 || m[2] === void 0) return null;
334
- const major = parseInt(m[1], 10);
335
- const minor = parseInt(m[2], 10);
336
- return Number.isFinite(major) && Number.isFinite(minor) ? {
337
- major,
338
- minor
339
- } : null;
340
- }
341
- function detectSwiftVersion(exec = null) {
342
- return parseSwiftVersion((exec || getExecutor()).runQuiet("xcrun swift --version", { timeoutMs: 1e4 }));
343
- }
344
- function parseXcodeMajor(output) {
345
- const m = /^Xcode\s+(\d+)/m.exec(String(output || ""));
346
- if (!m) return null;
347
- const digits = m[1];
348
- if (digits === void 0) return null;
349
- const major = parseInt(digits, 10);
350
- return Number.isFinite(major) ? major : null;
351
- }
352
- function detectXcodeMajor(exec = null) {
353
- return parseXcodeMajor((exec || getExecutor()).runQuiet("xcodebuild -version", { timeoutMs: 1e4 }));
354
- }
355
- function xcodebuildArgs({ project, scheme, udid = null, destination = null, configuration = "Debug", sdk = "iphonesimulator", derivedDataPath, extraArgs = [], buildSettings = [] }) {
356
- return [
357
- project.flag,
358
- project.path,
359
- "-scheme",
360
- scheme,
361
- "-configuration",
362
- configuration,
363
- "-sdk",
364
- sdk,
365
- "-destination",
366
- destination || `id=${udid}`,
367
- "-derivedDataPath",
368
- derivedDataPath,
369
- ...extraArgs,
370
- "build",
371
- ...buildSettings
372
- ];
373
- }
374
- function productsDir(derivedDataPath, { configuration = "Debug", sdk = "iphonesimulator" } = {}) {
375
- return join(derivedDataPath, "Build", "Products", `${configuration}-${sdk}`);
376
- }
377
- function pickAppBundle(entries, preferredName = null) {
378
- const apps = (Array.isArray(entries) ? entries : []).filter((e) => typeof e === "string" && e.endsWith(".app")).toSorted();
379
- if (apps.length === 0) return null;
380
- if (preferredName) {
381
- const wanted = `${preferredName}.app`;
382
- const exact = apps.find((a) => a === wanted);
383
- if (exact) return exact;
384
- }
385
- return apps[0];
386
- }
387
- function findAppBundle(dir, preferredName = null) {
388
- let entries;
389
- try {
390
- entries = readdirSync(dir);
391
- } catch {
392
- return null;
393
- }
394
- const app = pickAppBundle(entries, preferredName);
395
- return app ? join(dir, app) : null;
396
- }
397
- function parseBundleId(plistJson) {
398
- if (typeof plistJson !== "string") return null;
399
- let data;
400
- try {
401
- data = JSON.parse(plistJson);
402
- } catch {
403
- return null;
404
- }
405
- if (!data || typeof data !== "object") return null;
406
- const id = data.CFBundleIdentifier;
407
- return typeof id === "string" && id.trim() !== "" ? id.trim() : null;
408
- }
409
- function readBundleId(appPath, { exec = null } = {}) {
410
- const executor = exec || getExecutor();
411
- try {
412
- const id = parseBundleId(executor.runFile("plutil", [
413
- "-convert",
414
- "json",
415
- "-o",
416
- "-",
417
- join(appPath, "Info.plist")
418
- ], { timeoutMs: 1e4 }));
419
- if (id) return id;
420
- } catch {}
421
- try {
422
- const value = executor.runFile("defaults", [
423
- "read",
424
- join(appPath, "Info"),
425
- "CFBundleIdentifier"
426
- ], { timeoutMs: 1e4 });
427
- const trimmed = String(value).trim();
428
- return trimmed === "" ? null : trimmed;
429
- } catch {
430
- return null;
431
- }
432
- }
433
- function parseBundleExecutable(plistJson) {
434
- if (typeof plistJson !== "string") return null;
435
- let data;
436
- try {
437
- data = JSON.parse(plistJson);
438
- } catch {
439
- return null;
440
- }
441
- if (!data || typeof data !== "object") return null;
442
- const name = data.CFBundleExecutable;
443
- return typeof name === "string" && name.trim() !== "" ? name.trim() : null;
444
- }
445
- function readBundleExecutable(appPath, { exec = null } = {}) {
446
- const executor = exec || getExecutor();
447
- try {
448
- const name = parseBundleExecutable(executor.runFile("plutil", [
449
- "-convert",
450
- "json",
451
- "-o",
452
- "-",
453
- join(appPath, "Info.plist")
454
- ], { timeoutMs: 1e4 }));
455
- if (name) return name;
456
- } catch {}
457
- try {
458
- const value = executor.runFile("defaults", [
459
- "read",
460
- join(appPath, "Info"),
461
- "CFBundleExecutable"
462
- ], { timeoutMs: 1e4 });
463
- const trimmed = String(value).trim();
464
- return trimmed === "" ? null : trimmed;
465
- } catch {
466
- return null;
467
- }
468
- }
469
- const TAIL_LINES = 5;
470
- function tailLines(lines, count = TAIL_LINES) {
471
- return (Array.isArray(lines) ? lines : []).filter((l) => typeof l === "string" && l.trim() !== "").slice(-count);
472
- }
473
- const HEARTBEAT_INTERVAL_MS = 3e4;
474
- const HEARTBEAT_ACTIVITY = {
475
- build: "compiling",
476
- deps: "installing",
477
- pods: "installing"
478
- };
479
- function heartbeatLine(elapsedMs, label = "build", estimateMs = null) {
480
- const activity = HEARTBEAT_ACTIVITY[label] ?? "running";
481
- const elapsed = formatElapsed(elapsedMs);
482
- const inside = estimateMs && estimateMs > 0 ? elapsedMs > estimateMs ? `${elapsed}, usually ~${formatElapsed(estimateMs)}` : `${elapsed} of ~${formatElapsed(estimateMs)}` : elapsed;
483
- return phaseLine(label, `still ${activity} (${inside})`);
484
- }
485
- const defaultSchedule = (run, delayMs) => {
486
- const timer = setTimeout(run, delayMs);
487
- timer.unref?.();
488
- return () => clearTimeout(timer);
489
- };
490
- function startBuildHeartbeat({ intervalMs, elapsed, emit, label = "build", estimateMs = null, schedule = defaultSchedule }) {
491
- if (!(intervalMs > 0)) return () => {};
492
- let stopped = false;
493
- let lastBeat = 0;
494
- let cancel = null;
495
- function tick() {
496
- if (stopped) return;
497
- const ms = elapsed();
498
- const beat = Math.floor(ms / intervalMs) * intervalMs;
499
- if (beat > lastBeat) {
500
- lastBeat = beat;
501
- emit(heartbeatLine(beat, label, estimateMs));
502
- }
503
- cancel = schedule(tick, intervalMs - ms % intervalMs);
504
- }
505
- cancel = schedule(tick, intervalMs);
506
- return () => {
507
- stopped = true;
508
- cancel?.();
509
- };
510
- }
511
- function failedResult({ code, diagnostics, durationMs, exitCode = null, transcriptLines = 0, tail = [], compilationCache = COMPILATION_CACHE_UNAVAILABLE }) {
512
- const capped = capDiagnostics(diagnostics);
513
- return {
514
- ok: false,
515
- code,
516
- diagnostics: capped.diagnostics,
517
- truncated: capped.truncated,
518
- durationMs,
519
- exitCode,
520
- transcriptLines,
521
- tail,
522
- compilationCache
523
- };
524
- }
525
- const COMPILATION_CACHE_UNAVAILABLE = {
526
- status: "unavailable",
527
- hits: null,
528
- cacheableTasks: null,
529
- hitRatePercent: null
530
- };
531
- const COMPILATION_CACHE_NOT_RUN = {
532
- status: "not-run",
533
- hits: null,
534
- cacheableTasks: null,
535
- hitRatePercent: null
536
- };
537
- function parseCompilationCacheActivity(line) {
538
- if (typeof line !== "string") return null;
539
- const match = line.match(/(?:note:\s*)?(\d+) hits \/ (\d+) cacheable tasks \((\d+(?:\.\d+)?)%\)/);
540
- if (!match) return null;
541
- return {
542
- status: "reported",
543
- hits: Number(match[1]),
544
- cacheableTasks: Number(match[2]),
545
- hitRatePercent: Number(match[3])
546
- };
547
- }
548
- const SWIFT_CACHING_NEEDS_EXPLICIT_MODULES = /warning: swift compiler caching requires explicit module build/;
549
- function compilationCacheActivityLine(activity) {
550
- if (activity.status === "reported") {
551
- const swift = activity.swiftTargetsWithoutExplicitModules ? `; Swift excluded: ${activity.swiftTargetsWithoutExplicitModules} targets build without explicit modules (SWIFT_ENABLE_EXPLICIT_MODULES=NO)` : "";
552
- return `${activity.hits}/${activity.cacheableTasks} hits (${activity.hitRatePercent}%)${swift}`;
553
- }
554
- if (activity.status === "not-run") return "not run; artifact cache supplied the app";
555
- return "unavailable; Xcode did not report reliable statistics";
556
- }
557
- async function buildXcode({ root, udid = null, logWriter, project, scheme = null, configuration = "Debug", applicationTarget, sdk = "iphonesimulator", destination = null, arch = null, derivedDataPath = null, extraArgs = [], compilationCache, startedAt: clockStart, now = () => Date.now(), exec = null, heartbeatMs = HEARTBEAT_INTERVAL_MS, estimateMs = null, onHeartbeat = (line) => console.error(line) }) {
558
- if (!root || typeof root !== "string") throw new TypeError("buildXcode requires {root}");
559
- if (!logWriter || typeof logWriter.write !== "function") throw new TypeError("buildXcode requires {logWriter} with a write() method");
560
- if (!udid && !destination) throw new TypeError("buildXcode requires {udid} (or an explicit {destination})");
561
- const executor = exec || getExecutor();
562
- const dd = derivedDataPath || (scheme ? join(workspaceDerivedData(root), `scheme-${createHash("sha256").update(scheme).digest("hex")}`) : workspaceDerivedData(root));
563
- const startedAt = clockStart ?? now();
564
- const elapsed = () => now() - startedAt;
565
- const reportError = (message, remedy) => {
566
- logWriter.write({
567
- src: "build",
568
- level: "error",
569
- msg: message,
570
- event: "build_diagnostic",
571
- ...remedy ? { remedy } : {}
572
- });
573
- };
574
- if (project.error) {
575
- reportError(project.error.message, project.error.remedy);
576
- return failedResult({
577
- code: project.error.code,
578
- diagnostics: [{
579
- message: project.error.message,
580
- remedy: project.error.remedy ?? void 0
581
- }],
582
- durationMs: elapsed()
583
- });
584
- }
585
- const resolvedTarget = project;
586
- const selected = resolveScheme(resolvedTarget, {
587
- exec: executor,
588
- scheme
589
- });
590
- if (selected.error) {
591
- reportError(selected.error.message, selected.error.remedy);
592
- return failedResult({
593
- code: selected.error.code,
594
- diagnostics: [{
595
- message: selected.error.message,
596
- remedy: selected.error.remedy
597
- }],
598
- durationMs: elapsed()
599
- });
600
- }
601
- const buildScheme = selected.scheme;
602
- const cacheSettings = typeof compilationCache === "function" ? compilationCache({
603
- derivedDataPath: dd,
604
- exec: executor
605
- }) : compilationCache || [];
606
- const buildSettings = arch ? [
607
- ...cacheSettings,
608
- `ARCHS=${arch}`,
609
- "ONLY_ACTIVE_ARCH=YES"
610
- ] : cacheSettings;
611
- const args = xcodebuildArgs({
612
- project: resolvedTarget,
613
- scheme: buildScheme,
614
- udid,
615
- destination,
616
- configuration,
617
- sdk,
618
- derivedDataPath: dd,
619
- extraArgs,
620
- buildSettings
621
- });
622
- logWriter.write({
623
- src: "build",
624
- level: "info",
625
- msg: `xcodebuild ${args.join(" ")}`,
626
- event: "build_start"
627
- });
628
- const diagnosticCollector = createXcodeDiagnosticCollector(root, sdk);
629
- const tail = [];
630
- let transcriptLines = 0;
631
- let compilationCacheActivity = COMPILATION_CACHE_UNAVAILABLE;
632
- let swiftTargetsWithoutExplicitModules = 0;
633
- const onLine = (line) => {
634
- const msg = cleanLine(line);
635
- transcriptLines += 1;
636
- diagnosticCollector.push(msg);
637
- if (msg.trim() === "") return;
638
- tail.push(msg);
639
- if (tail.length > TAIL_LINES) tail.shift();
640
- logWriter.write({
641
- src: "build",
642
- level: "debug",
643
- msg
644
- });
645
- if (SWIFT_CACHING_NEEDS_EXPLICIT_MODULES.test(msg)) swiftTargetsWithoutExplicitModules += 1;
646
- const parsed = parseCompilationCacheActivity(msg);
647
- if (parsed) {
648
- const activity = swiftTargetsWithoutExplicitModules ? {
649
- ...parsed,
650
- swiftTargetsWithoutExplicitModules
651
- } : parsed;
652
- compilationCacheActivity = activity;
653
- logWriter.write({
654
- src: "build",
655
- level: "info",
656
- msg: compilationCacheActivityLine(activity),
657
- event: "compilation_cache",
658
- hits: activity.hits,
659
- cacheableTasks: activity.cacheableTasks,
660
- hitRatePercent: activity.hitRatePercent,
661
- ...swiftTargetsWithoutExplicitModules ? { swiftTargetsWithoutExplicitModules } : {}
662
- });
663
- }
664
- };
665
- let child;
666
- try {
667
- child = spawnDeclared(() => executor.spawn("xcodebuild", args, {
668
- cwd: resolvedTarget.dir || root,
669
- stdio: [
670
- "ignore",
671
- "pipe",
672
- "pipe"
673
- ],
674
- detached: false,
675
- env: {
676
- ...process.env,
677
- NSUnbufferedIO: "YES",
678
- FORCE_COLOR: "0"
679
- }
680
- }));
681
- } catch (err) {
682
- const message = `Could not run xcodebuild: ${err.message}`;
683
- const remedy = "Install Xcode and select it with `sudo xcode-select -s /Applications/Xcode.app`.";
684
- reportError(message, remedy);
685
- return failedResult({
686
- code: "STIM_BUILD_FAILED",
687
- diagnostics: [{
688
- message,
689
- remedy
690
- }],
691
- durationMs: elapsed()
692
- });
693
- }
694
- const outReader = createLineReader(onLine);
695
- const errReader = createLineReader(onLine);
696
- child.stdout?.setEncoding?.("utf-8");
697
- child.stderr?.setEncoding?.("utf-8");
698
- child.stdout?.on("data", (chunk) => outReader.push(chunk));
699
- child.stderr?.on("data", (chunk) => errReader.push(chunk));
700
- const stopHeartbeat = startBuildHeartbeat({
701
- intervalMs: heartbeatMs,
702
- elapsed,
703
- emit: onHeartbeat,
704
- estimateMs
705
- });
706
- const outcome = await new Promise((settlePromise) => {
707
- let settled = false;
708
- const finish = (value) => {
709
- if (settled) return;
710
- settled = true;
711
- outReader.flush();
712
- errReader.flush();
713
- settlePromise(value);
714
- };
715
- child.on("close", (code, signal) => finish({
716
- code,
717
- signal
718
- }));
719
- child.on("error", (error) => finish({
720
- code: null,
721
- signal: null,
722
- error
723
- }));
724
- });
725
- stopHeartbeat();
726
- const durationMs = elapsed();
727
- if (outcome.error) {
728
- const message = `Could not run xcodebuild: ${outcome.error.message}`;
729
- const remedy = "Install Xcode and select it with `sudo xcode-select -s /Applications/Xcode.app`.";
730
- reportError(message, remedy);
731
- return failedResult({
732
- code: "STIM_BUILD_FAILED",
733
- diagnostics: [{
734
- message,
735
- remedy
736
- }],
737
- durationMs,
738
- transcriptLines,
739
- tail,
740
- compilationCache: compilationCacheActivity
741
- });
742
- }
743
- if (outcome.code !== 0) {
744
- const diagnostics = diagnosticCollector.diagnostics;
745
- const capped = capDiagnostics(diagnostics);
746
- for (const d of capped.diagnostics) reportError(describeDiagnostic(d), d.remedy);
747
- if (capped.diagnostics.length === 0) reportError(`xcodebuild exited ${outcome.code ?? `on ${outcome.signal}`} with no recognizable diagnostic; see the transcript above.`, null);
748
- return failedResult({
749
- code: "STIM_BUILD_FAILED",
750
- diagnostics,
751
- durationMs,
752
- exitCode: outcome.code,
753
- transcriptLines,
754
- tail,
755
- compilationCache: compilationCacheActivity
756
- });
757
- }
758
- const products = productsDir(dd, {
759
- configuration,
760
- sdk
761
- });
762
- let appPath = null;
763
- if (scheme) try {
764
- const targets = JSON.parse(executor.runFile("xcodebuild", [
765
- resolvedTarget.flag,
766
- resolvedTarget.path,
767
- "-scheme",
768
- buildScheme,
769
- "-configuration",
770
- configuration,
771
- "-sdk",
772
- sdk,
773
- "-destination",
774
- destination || `id=${udid}`,
775
- "-derivedDataPath",
776
- dd,
777
- ...extraArgs,
778
- ...buildSettings,
779
- "-showBuildSettings",
780
- "-json"
781
- ], { timeoutMs: 3e4 }));
782
- const paths = /* @__PURE__ */ new Set();
783
- for (const item of Array.isArray(targets) ? targets : []) {
784
- const settings = item?.buildSettings;
785
- if (settings?.PRODUCT_TYPE !== "com.apple.product-type.application" || settings.PLATFORM_NAME !== sdk) continue;
786
- if (applicationTarget && (settings.TARGET_NAME !== applicationTarget.name || typeof settings.PROJECT_FILE_PATH !== "string" || realpathSync(settings.PROJECT_FILE_PATH) !== realpathSync(applicationTarget.projectPath))) continue;
787
- const dir = settings.TARGET_BUILD_DIR;
788
- const name = settings.FULL_PRODUCT_NAME;
789
- if (typeof dir !== "string" || !isAbsolute(dir) || typeof name !== "string" || basename(name) !== name || !name.endsWith(".app")) continue;
790
- const path = join(dir, name);
791
- if (statSync(path).isDirectory()) paths.add(path);
792
- }
793
- if (paths.size === 1) appPath = [...paths][0];
794
- } catch {}
795
- else appPath = findAppBundle(products, buildScheme);
796
- if (!appPath) {
797
- const message = scheme ? `xcodebuild succeeded, but the built app for scheme ${JSON.stringify(buildScheme)} could not be identified unambiguously from its build settings.` : `xcodebuild reported success but no .app is in ${products}.`;
798
- const remedy = "Check that the scheme builds one application target for this platform, not a library, test bundle, or several apps.";
799
- reportError(message, remedy);
800
- return failedResult({
801
- code: "STIM_BUILD_FAILED",
802
- diagnostics: [{
803
- message,
804
- remedy
805
- }],
806
- durationMs,
807
- exitCode: 0,
808
- transcriptLines,
809
- tail,
810
- compilationCache: compilationCacheActivity
811
- });
812
- }
813
- const bundleId = readBundleId(appPath, { exec: executor });
814
- if (!bundleId) {
815
- const message = `No readable CFBundleIdentifier in ${join(appPath, "Info.plist")}.`;
816
- const remedy = "Check PRODUCT_BUNDLE_IDENTIFIER in the target's Debug configuration.";
817
- reportError(message, remedy);
818
- return failedResult({
819
- code: "STIM_BUILD_FAILED",
820
- diagnostics: [{
821
- message,
822
- remedy
823
- }],
824
- durationMs,
825
- exitCode: 0,
826
- transcriptLines,
827
- tail,
828
- compilationCache: compilationCacheActivity
829
- });
830
- }
831
- logWriter.write({
832
- src: "build",
833
- level: "info",
834
- msg: `BUILD SUCCEEDED ${appPath} (${bundleId}) in ${durationMs}ms`,
835
- event: "build_done"
836
- });
837
- return {
838
- ok: true,
839
- appPath,
840
- bundleId,
841
- durationMs,
842
- scheme: buildScheme,
843
- project: resolvedTarget,
844
- derivedDataPath: dd,
845
- productsDir: products,
846
- transcriptLines,
847
- compilationCache: compilationCacheActivity
848
- };
849
- }
850
- //#endregion
851
- //#region src/engine/deps.ts
852
- const DEPS_ERROR = "STIM_DEPS_FAILED";
853
- const TRANSCRIPT_LINES = 2e3;
854
- const MAX_POD_DIAGNOSTIC_LINES = 15;
855
- const POD_MARKER = /^\[!\]/;
856
- const POD_CONTINUATION = /^\s+\S/;
857
- const RUBY_HEAD = /^\S.*\.rb:\d+:in\s+(?:`[^']*'|'[^']*'):\s*\S/;
858
- const RUBY_FRAME = /^\s*from\s+\S/;
859
- const RUBY_CONTEXT_BEFORE = 4;
860
- const BUNDLER_FROZEN = /frozen mode|lockfile can't be updated|in deployment mode after changing/i;
861
- const BUNDLER_NO_COCOAPODS = /cocoapods is not currently included in the bundle|command not found: pod\b/i;
862
- function extractPodDiagnostics(transcript) {
863
- if (typeof transcript !== "string" || transcript === "") return null;
864
- const lines = transcript.split("\n").map((line) => line.replace(/\r$/, ""));
865
- return extractPodBangBlocks(lines) || extractRubyHead(lines);
866
- }
867
- function extractPodBangBlocks(lines) {
868
- const blocks = [];
869
- for (let i = 0; i < lines.length; i += 1) {
870
- const line = lines[i];
871
- if (line === void 0 || !POD_MARKER.test(line)) continue;
872
- const block = [line];
873
- let j = i + 1;
874
- for (; j < lines.length; j += 1) {
875
- const next = lines[j];
876
- if (next === void 0 || !POD_CONTINUATION.test(next)) break;
877
- block.push(next);
878
- }
879
- blocks.push(block);
880
- i = j - 1;
881
- }
882
- if (blocks.length === 0) return null;
883
- const out = [];
884
- let dropped = 0;
885
- for (const block of blocks) {
886
- const room = MAX_POD_DIAGNOSTIC_LINES - out.length;
887
- if (room <= 0) {
888
- dropped += block.length;
889
- continue;
890
- }
891
- out.push(...block.slice(0, room));
892
- dropped += Math.max(0, block.length - room);
893
- }
894
- if (dropped > 0) out.push(`(+${dropped} more [!] lines in the build log)`);
895
- return {
896
- source: "cocoapods",
897
- lines: out
898
- };
899
- }
900
- function extractRubyHead(lines) {
901
- for (let i = 0; i < lines.length; i += 1) {
902
- const line = lines[i];
903
- if (line === void 0 || !RUBY_HEAD.test(line) || RUBY_FRAME.test(line)) continue;
904
- let start = i;
905
- while (start > 0 && i - start < RUBY_CONTEXT_BEFORE) {
906
- const prev = lines[start - 1];
907
- if (prev === void 0 || prev.trim() === "" || RUBY_FRAME.test(prev) || POD_MARKER.test(prev)) break;
908
- start -= 1;
909
- }
910
- let end = i + 1;
911
- while (end < lines.length) {
912
- const next = lines[end];
913
- if (next === void 0 || next.trim() === "" || RUBY_FRAME.test(next)) break;
914
- end += 1;
915
- }
916
- return {
917
- source: "ruby",
918
- lines: lines.slice(start, end).filter((entry) => entry.trim() !== "").slice(0, MAX_POD_DIAGNOSTIC_LINES)
919
- };
920
- }
921
- return null;
922
- }
923
- function podsAreStale(lockText, manifestText, dir = "ios/") {
924
- const lock = normalize(lockText);
925
- const manifest = normalize(manifestText);
926
- if (lock === null && manifest === null) return {
927
- noPods: true,
928
- stale: false
929
- };
930
- if (lock === null) return {
931
- stale: true,
932
- reason: `${dir}Podfile.lock is missing but ${dir}Pods exists`
933
- };
934
- if (manifest === null) return {
935
- stale: true,
936
- reason: `${dir}Pods/Manifest.lock is missing (pods have never been installed here)`
937
- };
938
- if (lock !== manifest) return {
939
- stale: true,
940
- reason: `${dir}Podfile.lock and ${dir}Pods/Manifest.lock differ`
941
- };
942
- return { stale: false };
943
- }
944
- function normalize(text) {
945
- if (typeof text !== "string") return null;
946
- return text.replace(/\r\n/g, "\n").trimEnd();
947
- }
948
- function readPodState(root, directory = join(root, "ios")) {
949
- const rel = relative(root, directory);
950
- return {
951
- hasPodfile: existsSync(join(directory, "Podfile")),
952
- lockText: readOrNull(join(directory, "Podfile.lock")),
953
- manifestText: readOrNull(join(directory, "Pods", "Manifest.lock")),
954
- dir: rel ? `${rel}/` : ""
955
- };
956
- }
957
- function readOrNull(file) {
958
- try {
959
- return readFileSync(file, "utf-8");
960
- } catch {
961
- return null;
962
- }
963
- }
964
- function podEnv(root, options = {}) {
965
- return podEnvForRuby(readRubyVersion(root), options);
966
- }
967
- const LOGIN_ENV_BEGIN = "@@ruby-env-begin@@";
968
- const LOGIN_ENV_END = "@@ruby-env-end@@";
969
- const LOGIN_ENV_SCRIPT = `printf '\\n${LOGIN_ENV_BEGIN}\\nPATH=%s\\nGEM_HOME=%s\\nGEM_PATH=%s\\n${LOGIN_ENV_END}\\n' "\$PATH" "\$GEM_HOME" "\$GEM_PATH" > "\$1"`;
970
- function parseLoginRubyEnv(output) {
971
- const lines = output.split("\n").map((line) => line.replace(/\r$/, ""));
972
- const begin = lines.lastIndexOf(LOGIN_ENV_BEGIN);
973
- const end = lines.indexOf(LOGIN_ENV_END, begin + 1);
974
- if (begin < 0 || end < 0) return null;
975
- const out = {};
976
- for (const line of lines.slice(begin + 1, end)) {
977
- const eq = line.indexOf("=");
978
- if (eq < 0) continue;
979
- const key = line.slice(0, eq);
980
- const value = line.slice(eq + 1);
981
- if (value && (key === "PATH" || key === "GEM_HOME" || key === "GEM_PATH")) out[key] = value;
982
- }
983
- return out;
984
- }
985
- const loginRubyEnvByShell = /* @__PURE__ */ new Map();
986
- const LOGIN_ENV_OPTIONS = {
987
- timeoutMs: 1e4,
988
- killSignal: "SIGKILL",
989
- detachedSilent: true
990
- };
991
- function readLoginRubyEnv(shell = process.env.SHELL, platform = process.platform) {
992
- if (platform !== "darwin" || !shell || !isAbsolute(shell)) return null;
993
- if (loginRubyEnvByShell.has(shell)) return loginRubyEnvByShell.get(shell) ?? null;
994
- let dir = null;
995
- let parsed = null;
996
- try {
997
- dir = mkdtempSync(join(tmpdir(), "stim-ruby-env-"));
998
- const file = join(dir, "env");
999
- getExecutor().runFile(shell, [
1000
- "-lic",
1001
- LOGIN_ENV_SCRIPT,
1002
- "stim",
1003
- file
1004
- ], LOGIN_ENV_OPTIONS);
1005
- parsed = parseLoginRubyEnv(readFileSync(file, "utf-8"));
1006
- } catch {
1007
- parsed = null;
1008
- } finally {
1009
- if (dir) rmSync(dir, {
1010
- recursive: true,
1011
- force: true
1012
- });
1013
- }
1014
- loginRubyEnvByShell.set(shell, parsed);
1015
- return parsed;
1016
- }
1017
- async function readLoginRubyEnvAsync(shell = process.env.SHELL, platform = process.platform) {
1018
- if (platform !== "darwin" || !shell || !isAbsolute(shell)) return null;
1019
- if (loginRubyEnvByShell.has(shell)) return loginRubyEnvByShell.get(shell) ?? null;
1020
- let dir = null;
1021
- let parsed = null;
1022
- try {
1023
- dir = mkdtempSync(join(tmpdir(), "stim-ruby-env-"));
1024
- const file = join(dir, "env");
1025
- await getExecutor().runFileAsync(shell, [
1026
- "-lic",
1027
- LOGIN_ENV_SCRIPT,
1028
- "stim",
1029
- file
1030
- ], LOGIN_ENV_OPTIONS);
1031
- parsed = parseLoginRubyEnv(readFileSync(file, "utf-8"));
1032
- } catch {
1033
- parsed = null;
1034
- } finally {
1035
- if (dir) rmSync(dir, {
1036
- recursive: true,
1037
- force: true
1038
- });
1039
- }
1040
- loginRubyEnvByShell.set(shell, parsed);
1041
- return parsed;
1042
- }
1043
- function rubyPathEntries(login, callerPath, exists) {
1044
- const have = new Set((callerPath ?? "").split(delimiter));
1045
- const gemDirs = [login.GEM_HOME, ...(login.GEM_PATH ?? "").split(delimiter)].filter((dir) => !!dir);
1046
- return (login.PATH ?? "").split(delimiter).filter((entry) => {
1047
- if (!entry || have.has(entry)) return false;
1048
- if (gemDirs.some((gem) => entry === gem || entry.startsWith(gem + sep))) return true;
1049
- return exists(join(entry, "ruby")) || exists(join(entry, "pod"));
1050
- });
1051
- }
1052
- function prependPath(entries, existing) {
1053
- const seen = /* @__PURE__ */ new Set();
1054
- return [...entries, ...(existing ?? "").split(delimiter)].filter((entry) => entry && !seen.has(entry) && seen.add(entry)).join(delimiter);
1055
- }
1056
- function podEnvForRuby(version, { env = process.env, home = homedir(), exists = existsSync, loginEnv = readLoginRubyEnv } = {}) {
1057
- const out = {
1058
- ...env,
1059
- FORCE_COLOR: "0",
1060
- CLICOLOR: "0",
1061
- LANG: env.LANG ?? "en_US.UTF-8",
1062
- LC_ALL: env.LC_ALL ?? env.LANG ?? "en_US.UTF-8"
1063
- };
1064
- const candidates = version ? [
1065
- { bin: join(home, ".rbenv", "versions", version, "bin") },
1066
- {
1067
- bin: join(home, ".rvm", "rubies", `ruby-${version}`, "bin"),
1068
- gems: join(home, ".rvm", "gems", `ruby-${version}`)
1069
- },
1070
- { bin: join(home, ".asdf", "installs", "ruby", version, "bin") },
1071
- { bin: join(home, ".local", "share", "mise", "installs", "ruby", version, "bin") }
1072
- ] : [];
1073
- for (const c of candidates) {
1074
- if (!exists(c.bin)) continue;
1075
- out.PATH = `${c.bin}${delimiter}${out.PATH ?? ""}`;
1076
- if (c.gems && exists(c.gems)) {
1077
- out.GEM_HOME = c.gems;
1078
- out.GEM_PATH = c.gems;
1079
- }
1080
- return out;
1081
- }
1082
- if (env.GEM_HOME) return out;
1083
- const login = loginEnv();
1084
- if (!login) return out;
1085
- const rubyPath = rubyPathEntries(login, out.PATH, exists);
1086
- if (rubyPath.length) out.PATH = prependPath(rubyPath, out.PATH);
1087
- if (login.GEM_HOME) out.GEM_HOME = login.GEM_HOME;
1088
- if (login.GEM_PATH) out.GEM_PATH = login.GEM_PATH;
1089
- return out;
1090
- }
1091
- async function podEnvForRubyAsync(version) {
1092
- let loginNeeded = false;
1093
- const withoutLogin = podEnvForRuby(version, { loginEnv: () => {
1094
- loginNeeded = true;
1095
- return null;
1096
- } });
1097
- if (!loginNeeded) return withoutLogin;
1098
- const login = await readLoginRubyEnvAsync();
1099
- return podEnvForRuby(version, { loginEnv: () => login });
1100
- }
1101
- function readRubyVersion(root, { read = readFileSync } = {}) {
1102
- try {
1103
- const first = String(read(join(root, ".ruby-version"), "utf-8")).split("\n").map((l) => l.trim()).find((l) => l && !l.startsWith("#"));
1104
- if (!first) return null;
1105
- return first.replace(/^ruby-/, "");
1106
- } catch {
1107
- return null;
1108
- }
1109
- }
1110
- function bundlerEnv(root, gemfile) {
1111
- return {
1112
- ...podEnv(root),
1113
- BUNDLE_GEMFILE: gemfile,
1114
- BUNDLE_FROZEN: "true"
1115
- };
1116
- }
1117
- const BUNDLE_PATH_SETTING = /^BUNDLE_PATH:[ \t]*["']?([^"'\r\n]+?)["']?[ \t]*$/m;
1118
- function bundlePathInsideProject(root, env) {
1119
- const fromEnv = env.BUNDLE_PATH;
1120
- const configured = fromEnv || BUNDLE_PATH_SETTING.exec(readOrNull(join(root, ".bundle", "config")) ?? "")?.[1];
1121
- if (!configured || configured.startsWith("~")) return null;
1122
- const resolved = resolve(root, configured);
1123
- if (resolved !== root && !resolved.startsWith(root + sep)) return null;
1124
- return {
1125
- path: relative(root, resolved) || ".",
1126
- where: fromEnv ? "where the BUNDLE_PATH environment variable points" : "where its own .bundle/config points BUNDLE_PATH"
1127
- };
1128
- }
1129
- async function runCaptured(ctx) {
1130
- const startedAt = ctx.now();
1131
- const transcript = [];
1132
- const push = (line) => {
1133
- const msg = stripAnsi(String(line)).trimEnd();
1134
- if (!msg.trim()) return;
1135
- transcript.push(msg);
1136
- if (transcript.length > TRANSCRIPT_LINES) transcript.splice(TRANSCRIPT_LINES / 2, 1);
1137
- ctx.logWriter?.write?.({
1138
- src: "build",
1139
- level: "debug",
1140
- msg,
1141
- raw: true,
1142
- event: ctx.event
1143
- });
1144
- };
1145
- let child;
1146
- try {
1147
- child = spawnDeclared(() => ctx.spawn(ctx.cmd, ctx.args, {
1148
- cwd: ctx.cwd,
1149
- stdio: [
1150
- "ignore",
1151
- "pipe",
1152
- "pipe"
1153
- ],
1154
- env: ctx.env
1155
- }));
1156
- } catch (error) {
1157
- return {
1158
- transcript,
1159
- code: null,
1160
- signal: null,
1161
- error,
1162
- durationMs: ctx.now() - startedAt
1163
- };
1164
- }
1165
- const reader = {
1166
- out: createLineReader(push),
1167
- err: createLineReader(push)
1168
- };
1169
- child.stdout?.setEncoding?.("utf-8");
1170
- child.stderr?.setEncoding?.("utf-8");
1171
- child.stdout?.on("data", (chunk) => reader.out.push(chunk));
1172
- child.stderr?.on("data", (chunk) => reader.err.push(chunk));
1173
- const stopHeartbeat = ctx.label ? startBuildHeartbeat({
1174
- intervalMs: ctx.heartbeatMs,
1175
- elapsed: () => ctx.now() - startedAt,
1176
- emit: ctx.onHeartbeat,
1177
- label: ctx.label,
1178
- estimateMs: ctx.estimateMs ?? null
1179
- }) : () => {};
1180
- let result;
1181
- try {
1182
- result = await waitForChild(child);
1183
- } finally {
1184
- stopHeartbeat();
1185
- }
1186
- reader.out.flush();
1187
- reader.err.flush();
1188
- return {
1189
- transcript,
1190
- code: result.code ?? null,
1191
- signal: result.signal ?? null,
1192
- error: result.error ?? null,
1193
- durationMs: ctx.now() - startedAt
1194
- };
1195
- }
1196
- async function ensureBundledGems(root, pin, ctx) {
1197
- const env = bundlerEnv(root, pin.gemfile);
1198
- const cwd = dirname(pin.gemfile);
1199
- const check = await runCaptured({
1200
- ...ctx,
1201
- cmd: "bundle",
1202
- args: ["check", "--dry-run"],
1203
- cwd,
1204
- env,
1205
- event: "bundle_check",
1206
- label: "gems"
1207
- });
1208
- if (check.error) return bundlerSpawnFailure("bundle check", check, pin);
1209
- if (check.code === 0) return { bundler: true };
1210
- const install = await runCaptured({
1211
- ...ctx,
1212
- cmd: "bundle",
1213
- args: ["install"],
1214
- cwd,
1215
- env,
1216
- event: "bundle_install",
1217
- label: "gems"
1218
- });
1219
- if (install.error) return bundlerSpawnFailure("bundle install", install, pin);
1220
- const inProject = bundlePathInsideProject(cwd, env);
1221
- const note = inProject ? `\`bundle install\` put this project's gems in ${inProject.path}${sep}, ${inProject.where}; Gemfile.lock itself is never written.` : void 0;
1222
- if (install.code === 0) return {
1223
- bundler: true,
1224
- note
1225
- };
1226
- const how = install.signal ? `signal ${install.signal}` : `exit code ${install.code}`;
1227
- const transcript = install.transcript.join("\n");
1228
- const extracted = extractPodDiagnostics(transcript);
1229
- return {
1230
- bundler: false,
1231
- failure: {
1232
- failed: true,
1233
- code: DEPS_ERROR,
1234
- reason: `\`bundle install\` failed (${how}).`,
1235
- remedy: frozenRemedy(root, pin, transcript) || gemInstallRemedy(root, pin),
1236
- diagnosticSource: extracted ? extracted.source : "tail",
1237
- diagnosticLines: extracted ? extracted.lines : [],
1238
- lastLines: install.transcript.slice(-20),
1239
- durationMs: install.durationMs
1240
- }
1241
- };
1242
- }
1243
- function bundlerSpawnFailure(command, run, pin) {
1244
- if (isMissingBinary(run.error)) return {
1245
- bundler: false,
1246
- note: missingBundlerNote(pin)
1247
- };
1248
- return {
1249
- bundler: false,
1250
- failure: {
1251
- failed: true,
1252
- code: DEPS_ERROR,
1253
- reason: `Could not run \`${command}\`: ${run.error?.message || run.error}`,
1254
- remedy: `Bundler is how this project pins its CocoaPods (${pin.lockfile}). Check that \`bundle\` runs in ${dirname(pin.gemfile)}, then run again.`,
1255
- lastLines: run.transcript.slice(-20),
1256
- durationMs: run.durationMs
1257
- }
1258
- };
1259
- }
1260
- function missingBundlerNote(pin) {
1261
- return `${pin.lockfile} pins this project's CocoaPods, but \`bundle\` is not on PATH, so pods run as plain \`pod install\` with whatever CocoaPods PATH resolves to (\`gem install bundler\` to use the pin).`;
1262
- }
1263
- function frozenRemedy(root, pin, transcript) {
1264
- if (!BUNDLER_FROZEN.test(transcript)) return void 0;
1265
- return `Stim runs bundler with BUNDLE_FROZEN so it can never write into your checkout, and ${pin.gemfile} no longer matches ${pin.lockfile}. Run \`cd ${root} && bundle install\` yourself, keep the updated Gemfile.lock, then run again.`;
1266
- }
1267
- function gemInstallRemedy(root, pin) {
1268
- const version = readRubyVersion(root);
1269
- return `${version ? `This repo pins ruby ${version} (.ruby-version), so put that ruby on PATH (rbenv/rvm/asdf/mise) first. ` : ""}Bundler could not install the gems ${pin.lockfile} pins, so \`bundle exec pod install\` cannot run. Run \`cd ${root} && bundle install\` and fix what it reports, then run again.`;
1270
- }
1271
- async function runPodInstall(root, logWriter, { spawnFn = null, now = Date.now, heartbeatMs = HEARTBEAT_INTERVAL_MS, estimateMs = null, onHeartbeat = (line) => console.error(line), directory = join(root, "ios") } = {}) {
1272
- const iosDir = directory;
1273
- if (!existsSync(iosDir)) return {
1274
- failed: true,
1275
- code: DEPS_ERROR,
1276
- reason: `No ${relative(root, iosDir) || "."}/ directory in ${root}, so there is nothing to pod install.`,
1277
- remedy: "Run `stim ios` on a project with native iOS sources, or let prebuild generate them.",
1278
- lastLines: []
1279
- };
1280
- const ctx = {
1281
- logWriter,
1282
- spawn: spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts)),
1283
- now,
1284
- heartbeatMs,
1285
- onHeartbeat
1286
- };
1287
- const notes = [];
1288
- const pin = bundlerPin(root);
1289
- let bundler = false;
1290
- if (pin) {
1291
- const gems = await ensureBundledGems(root, pin, ctx);
1292
- if (gems.failure) return {
1293
- ...gems.failure,
1294
- notes
1295
- };
1296
- if (gems.note) notes.push(gems.note);
1297
- bundler = gems.bundler;
1298
- }
1299
- const args = bundler ? [
1300
- "bundle",
1301
- "exec",
1302
- "pod",
1303
- "install"
1304
- ] : ["pod", "install"];
1305
- const command = args.join(" ");
1306
- const run = await runCaptured({
1307
- ...ctx,
1308
- cmd: args[0],
1309
- args: args.slice(1),
1310
- cwd: iosDir,
1311
- env: bundler && pin ? bundlerEnv(root, pin.gemfile) : podEnv(root),
1312
- event: "pod_install",
1313
- label: "pods",
1314
- estimateMs
1315
- });
1316
- if (run.error) return {
1317
- ...(bundler ? missingBundle(run.error, pin) : missingPod(run.error)) || {
1318
- failed: true,
1319
- code: "STIM_DEPS_FAILED",
1320
- reason: `Could not run \`${command}\`: ${run.error?.message || run.error}`,
1321
- lastLines: run.transcript.slice(-20),
1322
- durationMs: run.durationMs
1323
- },
1324
- command,
1325
- notes
1326
- };
1327
- if (run.code !== 0) {
1328
- const how = run.signal ? `signal ${run.signal}` : `exit code ${run.code}`;
1329
- const transcript = run.transcript.join("\n");
1330
- const extracted = extractPodDiagnostics(transcript);
1331
- return {
1332
- failed: true,
1333
- code: DEPS_ERROR,
1334
- reason: `\`${command}\` failed (${how}).`,
1335
- remedy: podFailureRemedy(root, pin, transcript),
1336
- command,
1337
- notes,
1338
- diagnosticSource: extracted ? extracted.source : "tail",
1339
- diagnosticLines: extracted ? extracted.lines : [],
1340
- lastLines: run.transcript.slice(-20),
1341
- durationMs: run.durationMs
1342
- };
1343
- }
1344
- return {
1345
- ok: true,
1346
- command,
1347
- notes,
1348
- durationMs: run.durationMs
1349
- };
1350
- }
1351
- function podFailureRemedy(root, pin, transcript) {
1352
- if (pin) {
1353
- const frozen = frozenRemedy(root, pin, transcript);
1354
- if (frozen) return frozen;
1355
- if (BUNDLER_NO_COCOAPODS.test(transcript)) return `${pin.lockfile} resolves cocoapods, but bundler found no \`pod\` executable in the bundle it loaded: the installed gems belong to a different Gemfile than ${pin.gemfile}, or that Gemfile's bundle was never installed. Run \`cd ${root} && bundle install && bundle exec pod --version\` and make that work, then run again.`;
1356
- }
1357
- const pinned = /Could not find proper version of cocoapods/.test(transcript) ? readRubyVersion(root) : null;
1358
- if (!pinned) return void 0;
1359
- return `This repo pins ruby ${pinned} (.ruby-version) and its Gemfile's cocoapods was installed under it; the shell's ruby is likely a different version, so bundler looks in the wrong gem home. Put ruby ${pinned} on PATH (rbenv/rvm/asdf/mise) -- \`bundle install\` will NOT fix this.`;
1360
- }
1361
- function isMissingBinary(err) {
1362
- const nodeErr = err;
1363
- const message = String(nodeErr?.message || err || "");
1364
- return nodeErr?.code === "ENOENT" || /ENOENT|not found/i.test(message);
1365
- }
1366
- function missingBundle(err, pin) {
1367
- if (!isMissingBinary(err)) return null;
1368
- return {
1369
- failed: true,
1370
- code: DEPS_ERROR,
1371
- reason: "Bundler is not installed: no `bundle` executable on PATH.",
1372
- remedy: `${pin?.lockfile ?? "Gemfile.lock"} pins this project's CocoaPods, so pods run through bundler. Install bundler (\`gem install bundler\`) and run again.`,
1373
- lastLines: []
1374
- };
1375
- }
1376
- function missingPod(err) {
1377
- if (!isMissingBinary(err)) return null;
1378
- return {
1379
- failed: true,
1380
- code: DEPS_ERROR,
1381
- reason: "CocoaPods is not installed: no `pod` executable on PATH.",
1382
- remedy: "Install CocoaPods (`brew install cocoapods`, or `gem install cocoapods`) and run again.",
1383
- lastLines: []
1384
- };
1385
- }
1386
- //#endregion
1387
- //#region src/offload/toolchain.ts
1388
- const distDir = dirname(fileURLToPath(import.meta.url));
1389
- function quiet(file, args) {
1390
- return getExecutor().runFileQuiet(file, args, { timeoutMs: 2e4 });
1391
- }
1392
- function iosToolchain(root, native) {
1393
- return iosToolchainForRuby(native ? null : readRubyVersion(root), native);
1394
- }
1395
- async function quietAsync(file, args) {
1396
- try {
1397
- return await getExecutor().runFileAsync(file, args, { timeoutMs: 2e4 });
1398
- } catch {
1399
- return null;
1400
- }
1401
- }
1402
- async function iosToolchainAsync(root) {
1403
- const rubyVersion = readRubyVersion(root);
1404
- const [xcode, simulatorSdk, cocoapods] = await Promise.all([
1405
- quietAsync("xcodebuild", ["-version"]),
1406
- quietAsync("xcrun", [
1407
- "--sdk",
1408
- "iphonesimulator",
1409
- "--show-sdk-version"
1410
- ]),
1411
- cocoapodsVersionAsync(rubyVersion)
1412
- ]);
1413
- return assembleIosToolchain(xcode, simulatorSdk, cocoapods);
1414
- }
1415
- function iosToolchainForRuby(rubyVersion, native) {
1416
- return assembleIosToolchain(quiet("xcodebuild", ["-version"]), quiet("xcrun", [
1417
- "--sdk",
1418
- "iphonesimulator",
1419
- "--show-sdk-version"
1420
- ]), native ? null : cocoapodsVersion(rubyVersion));
1421
- }
1422
- function assembleIosToolchain(xcode, simulatorSdk, cocoapods) {
1423
- return {
1424
- stimBuild: stimBuildDigest(distDir),
1425
- arch: process.arch,
1426
- xcode: xcode ? xcode.trim().replace(/\n/g, " / ") : null,
1427
- simulatorSdk: simulatorSdk?.trim() ?? null,
1428
- cocoapods
1429
- };
1430
- }
1431
- function podProbeEnv(env) {
1432
- return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
1433
- }
1434
- function podVersionLine(output) {
1435
- return output?.trim().split("\n").pop()?.trim() ?? null;
1436
- }
1437
- function cocoapodsVersion(rubyVersion) {
1438
- return podVersionLine(getExecutor().runFileQuiet("pod", ["--version"], {
1439
- timeoutMs: 2e4,
1440
- env: podProbeEnv(podEnvForRuby(rubyVersion))
1441
- }));
1442
- }
1443
- async function cocoapodsVersionAsync(rubyVersion) {
1444
- try {
1445
- return podVersionLine(await getExecutor().runFileAsync("pod", ["--version"], {
1446
- timeoutMs: 2e4,
1447
- env: podProbeEnv(await podEnvForRubyAsync(rubyVersion))
1448
- }));
1449
- } catch {
1450
- return null;
1451
- }
1452
- }
1453
- function macosToolchain() {
1454
- const xcode = quiet("xcodebuild", ["-version"]);
1455
- return {
1456
- stimBuild: stimBuildDigest(distDir),
1457
- arch: process.arch,
1458
- xcode: xcode ? xcode.trim().replace(/\n/g, " / ") : null,
1459
- macosSdk: quiet("xcrun", [
1460
- "--sdk",
1461
- "macosx",
1462
- "--show-sdk-version"
1463
- ])?.trim() ?? null
1464
- };
1465
- }
1466
- /** The major version in a JDK's `release` file, as `JAVA_VERSION="17.0.19"` gives it. */
1467
- function jdkMajor(release) {
1468
- return /^JAVA_VERSION="(\d+)/m.exec(release)?.[1] ?? null;
1469
- }
1470
- function releaseMajor(home) {
1471
- try {
1472
- return jdkMajor(readFileSync(join(home, "release"), "utf8"));
1473
- } catch {
1474
- return null;
1475
- }
1476
- }
1477
- /**
1478
- * The JDK Gradle's wrapper picks: `JAVA_HOME`, else the `java` on PATH, which is the macOS `/usr/bin/java`
1479
- * stub (resolved through `java_home`) unless a real JDK comes first.
1480
- */
1481
- function localJdk(env = process.env) {
1482
- if (env.JAVA_HOME) return releaseMajor(env.JAVA_HOME);
1483
- const java = getExecutor().findExecutable("java");
1484
- if (java) try {
1485
- const fromPath = releaseMajor(dirname(dirname(realpathSync(java))));
1486
- if (fromPath) return fromPath;
1487
- } catch {}
1488
- const home = quiet("/usr/libexec/java_home", [])?.trim();
1489
- return home ? releaseMajor(home) : null;
1490
- }
1491
- function androidToolchain() {
1492
- return {
1493
- stimBuild: stimBuildDigest(distDir),
1494
- arch: process.arch,
1495
- jdk: localJdk()
1496
- };
1497
- }
1498
- /** `ndkVersion`, `buildTools` and `compileSdk` from React Native's `gradle/libs.versions.toml`. */
1499
- function parseAndroidRequirements(catalog) {
1500
- const value = (key) => new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, "m").exec(catalog)?.[1] ?? null;
1501
- return {
1502
- ndk: value("ndkVersion"),
1503
- buildTools: value("buildTools"),
1504
- compileSdk: value("compileSdk")
1505
- };
1506
- }
1507
- function androidRequirements(projectRoot) {
1508
- try {
1509
- const pkg = createRequire(join(projectRoot, "package.json")).resolve("react-native/package.json");
1510
- return parseAndroidRequirements(readFileSync(join(dirname(pkg), "gradle", "libs.versions.toml"), "utf8"));
1511
- } catch {
1512
- return {
1513
- ndk: null,
1514
- buildTools: null,
1515
- compileSdk: null
1516
- };
1517
- }
1518
- }
1519
- /** Runtime identifiers that have at least one available iPhone simulator, from `simctl list devices -j`. */
1520
- function iphoneRuntimes(listed) {
1521
- const devices = listed?.devices;
1522
- if (!devices || typeof devices !== "object") return [];
1523
- return Object.entries(devices).filter(([, list]) => (Array.isArray(list) ? list : []).some((device) => device.isAvailable !== false && typeof device.name === "string" && device.name.startsWith("iPhone"))).map(([runtime]) => runtime).toSorted();
1524
- }
1525
- function listDir(path) {
1526
- try {
1527
- return readdirSync(path).filter((entry) => !entry.startsWith(".")).toSorted();
1528
- } catch {
1529
- return null;
1530
- }
1531
- }
1532
- function sdkPackages() {
1533
- const sdk = androidHome();
1534
- const platforms = listDir(join(sdk, "platforms"));
1535
- if (!platforms) return null;
1536
- return {
1537
- ndk: listDir(join(sdk, "ndk")) ?? [],
1538
- buildTools: listDir(join(sdk, "build-tools")) ?? [],
1539
- platforms
1540
- };
1541
- }
1542
- function workerToolchain(rubyVersion = null, native) {
1543
- if (native === "gradle") return {
1544
- ...androidToolchain(),
1545
- xcode: null,
1546
- simulatorSdk: null,
1547
- cocoapods: null,
1548
- macosSdk: null,
1549
- bundler: null,
1550
- runtimes: [],
1551
- androidSdk: sdkPackages()
1552
- };
1553
- let listed = null;
1554
- try {
1555
- listed = JSON.parse(quiet("xcrun", [
1556
- "simctl",
1557
- "list",
1558
- "devices",
1559
- "available",
1560
- "-j"
1561
- ]) ?? "null");
1562
- } catch {}
1563
- return {
1564
- ...iosToolchainForRuby(rubyVersion, native),
1565
- macosSdk: native ? null : quiet("xcrun", [
1566
- "--sdk",
1567
- "macosx",
1568
- "--show-sdk-version"
1569
- ])?.trim() ?? null,
1570
- bundler: native ? null : quiet("bundle", ["--version"])?.trim() || null,
1571
- runtimes: iphoneRuntimes(listed),
1572
- jdk: native ? null : localJdk(),
1573
- androidSdk: native ? null : sdkPackages()
1574
- };
1575
- }
1576
- /** The API level of an SDK `platforms/` directory: `android-37.0` and `android-37` are both 37. */
1577
- const platformLevel = (dir) => dir.replace(/^android-/, "").split(".")[0];
1578
- function androidMismatches(local, requires, worker) {
1579
- const out = [];
1580
- if (!local.jdk || worker.jdk !== local.jdk) out.push({
1581
- code: "jdk",
1582
- reason: `JDK ${worker.jdk ?? "none"} there, ${local.jdk ?? "none"} here`
1583
- });
1584
- const sdk = worker.androidSdk;
1585
- if (!sdk) return [...out, {
1586
- code: "android-sdk",
1587
- reason: "no Android SDK there"
1588
- }];
1589
- if (requires.ndk && !sdk.ndk.includes(requires.ndk)) out.push({
1590
- code: "ndk",
1591
- reason: `no NDK ${requires.ndk} there`
1592
- });
1593
- if (requires.buildTools && !sdk.buildTools.includes(requires.buildTools)) out.push({
1594
- code: "build-tools",
1595
- reason: `no build-tools ${requires.buildTools} there`
1596
- });
1597
- if (requires.compileSdk && !sdk.platforms.some((dir) => platformLevel(dir) === requires.compileSdk)) out.push({
1598
- code: "compile-sdk",
1599
- reason: `no platform android-${requires.compileSdk} there`
1600
- });
1601
- return out;
1602
- }
1603
- function versionMismatch(tool, there, here) {
1604
- const side = (version) => version ? version.startsWith(tool) ? version : `${tool} ${version}` : `no ${tool}`;
1605
- return `${side(there)} there, ${side(here)} here`;
1606
- }
1607
- /** Why a remote Mac cannot build like this Mac; empty when it can. */
1608
- function toolchainMismatches(target, worker) {
1609
- const { local } = target;
1610
- const out = [];
1611
- if (!local.stimBuild || worker.stimBuild !== local.stimBuild) out.push({
1612
- code: "stim-build",
1613
- reason: `Stim build ${worker.stimBuild ?? "unknown"} there, ${local.stimBuild ?? "unknown"} here`
1614
- });
1615
- if (worker.arch !== local.arch) out.push({
1616
- code: "arch",
1617
- reason: `CPU ${worker.arch} there, ${local.arch} here`
1618
- });
1619
- if (target.platform === "android") return [...out, ...androidMismatches(target.local, target.requires, worker)];
1620
- if (target.platform === "macos") {
1621
- const macos = target.local;
1622
- if (!macos.xcode || worker.xcode !== macos.xcode) out.push({
1623
- code: "xcode",
1624
- reason: versionMismatch("Xcode", worker.xcode, macos.xcode)
1625
- });
1626
- if (!macos.macosSdk || worker.macosSdk !== macos.macosSdk) out.push({
1627
- code: "macos-sdk",
1628
- reason: versionMismatch("macOS SDK", worker.macosSdk, macos.macosSdk)
1629
- });
1630
- return out;
1631
- }
1632
- const ios = target.local;
1633
- if (!ios.xcode || worker.xcode !== ios.xcode) out.push({
1634
- code: "xcode",
1635
- reason: versionMismatch("Xcode", worker.xcode, ios.xcode)
1636
- });
1637
- if (!ios.simulatorSdk || worker.simulatorSdk !== ios.simulatorSdk) out.push({
1638
- code: "simulator-sdk",
1639
- reason: versionMismatch("simulator SDK", worker.simulatorSdk, ios.simulatorSdk)
1640
- });
1641
- if (!target.native && target.cocoapodsPinned) {
1642
- if (!worker.bundler) out.push({
1643
- code: "bundler",
1644
- reason: "no Bundler there to run the CocoaPods this project's Gemfile.lock pins"
1645
- });
1646
- } else if (!target.native && worker.cocoapods !== ios.cocoapods) out.push({
1647
- code: "cocoapods",
1648
- reason: versionMismatch("CocoaPods", worker.cocoapods, ios.cocoapods)
1649
- });
1650
- if (target.runtime && !worker.runtimes.includes(target.runtime)) out.push({
1651
- code: "runtime",
1652
- reason: `no iPhone simulator on ${target.runtime} there`
1653
- });
1654
- return out;
1655
- }
1656
- //#endregion
1657
- export { readBundleId as A, compilationCacheSettings as C, parseXcodeMajor as D, parseSwiftVersion as E, describeDiagnostic as F, bundlerPin as I, podInstallCommand as L, startBuildHeartbeat as M, swiftPrefixMappingSupported as N, pickXcodeProject as O, tailLines as P, compilationCacheActivityLine as S, detectXcodeMajor as T, COMPILATION_CACHE_NOT_RUN as _, iphoneRuntimes as a, SWIFT_PREFIX_MAPPING_MIN_SWIFT as b, parseAndroidRequirements as c, DEPS_ERROR as d, podsAreStale as f, runPodInstall as g, runCaptured as h, iosToolchainAsync as i, resolveScheme as j, readBundleExecutable as k, toolchainMismatches as l, readRubyVersion as m, androidToolchain as n, jdkMajor as o, readPodState as p, iosToolchain as r, macosToolchain as s, androidRequirements as t, workerToolchain as u, COMPILATION_CACHE_UNAVAILABLE as v, detectSwiftVersion as w, buildXcode as x, HEARTBEAT_INTERVAL_MS as y };