stim 1.19.0 → 1.20.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 (172) hide show
  1. package/README.md +20 -3
  2. package/dist/{activity-BSw0x84R.mjs → activity-BrGh9EAI.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-Bjxu_VmX.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
  4. package/dist/android-0vv-OruW.mjs +6 -0
  5. package/dist/android-Brx6EKvJ.mjs +1258 -0
  6. package/dist/{android-BdQC6zs1.mjs → android-BsYNR81W.mjs} +103 -45
  7. package/dist/{android-DE5g_5gv.mjs → android-CK3fpEyZ.mjs} +2 -2
  8. package/dist/{android-cas-C87geAg-.mjs → android-cas-DCAuXryb.mjs} +9 -5
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/api-run.mjs +159 -8
  11. package/dist/{api-DIf_s86s.mjs → api-zuX3ynYN.mjs} +5 -1
  12. package/dist/api.d.mts +98 -4
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-CFI4ptUL.mjs → app-install-0LgaQRT7.mjs} +9 -8
  15. package/dist/artifact-CnC0mfov.mjs +807 -0
  16. package/dist/artifact-DClXJNWx.mjs +772 -0
  17. package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
  18. package/dist/{browser-web-CDhqQxhv.mjs → browser-web-CzBmhmgs.mjs} +19 -19
  19. package/dist/{budget-Dz-kyXLv.mjs → budget-BONq9vXY.mjs} +3101 -3062
  20. package/dist/build-BixRI6sB.mjs +462 -0
  21. package/dist/{build-facts-B87vo-Im.d.mts → build-facts-DcLv2HSd.d.mts} +1 -32
  22. package/dist/build-plan-CP0tckNU.mjs +553 -0
  23. package/dist/{cache-manifest-DiwKSyv9.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
  24. package/dist/cache-manifest.mjs +1 -1
  25. package/dist/{manifest-CX0d1IkZ.mjs → ccache-CjHQ5F8g.mjs} +13 -19
  26. package/dist/{chrome-BTUOo8p2.mjs → chrome-Dp2lMLBe.mjs} +1 -1
  27. package/dist/{cli-C9Zvgbdc.mjs → cli-B2R8wH1F.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-CuUo8Nvg.mjs → client-BLy1Pw2V.mjs} +89 -307
  30. package/dist/collector-run.d.mts +4 -0
  31. package/dist/collector-run.mjs +7 -7
  32. package/dist/{command-output-Bt8ygHE7.mjs → command-output-BjPN99ZB.mjs} +2 -2
  33. package/dist/{config-DC5jEtd1.mjs → config-D0LhTY3S.mjs} +8 -12
  34. package/dist/{created-devices-D0s26Hx5.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
  35. package/dist/{dependency-state-DKaS1OM9.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
  36. package/dist/{detached-entry-pB_IPfV4.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
  37. package/dist/{dev-client-CDY_zAmD.mjs → dev-client-ClATaJoH.mjs} +2 -2
  38. package/dist/{device-BHw0WlHl.mjs → device-B7lsC0K1.mjs} +8 -8
  39. package/dist/device-DVCwAFlX.mjs +727 -0
  40. package/dist/{device-capacity-BoN1jQkO.mjs → device-capacity-Ca_ke1LE.mjs} +13 -14
  41. package/dist/device-host-worker.mjs +38 -18
  42. package/dist/device-ios-CRUqPxKw.mjs +413 -0
  43. package/dist/{device-lease-Cu7PtQpZ.mjs → device-lease-DHOBXGgS.mjs} +135 -22
  44. package/dist/{device-lease-run-D38SnZtt.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
  45. package/dist/{device-pool-CP4rAsHx.mjs → device-pool-L2-5GxMy.mjs} +3 -3
  46. package/dist/{device-remote-B5GiUifk.mjs → device-remote-Bmg42063.mjs} +17 -68
  47. package/dist/doctor-C2MSuMMg.mjs +515 -0
  48. package/dist/{doctor-PRJH94v6.mjs → doctor-DPAqhVCK.mjs} +333 -744
  49. package/dist/{doctor-watchman-wZhyTdp4.mjs → doctor-watchman-CB4NnVZm.mjs} +13 -12
  50. package/dist/{simslim-D9LkJxIO.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
  51. package/dist/{stim-installations-DbmUjsLv.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
  52. package/dist/{error-diagnostics--v5HGOU0.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
  53. package/dist/errors-DzkMYh8Q.mjs +205 -0
  54. package/dist/{exec-i8GDPwq9.mjs → exec-B81Qodjn.mjs} +40 -10
  55. package/dist/{gc-CyHMcKcn.mjs → gc-PWp34zGb.mjs} +21 -20
  56. package/dist/{device-ios-B2ruohE-.mjs → gradle-C2OEKCCI.mjs} +21 -650
  57. package/dist/{guide-dRaQJJk9.mjs → guide-Dai9lphv.mjs} +504 -117
  58. package/dist/{hosted-android-Bs7fytj7.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
  59. package/dist/{hosted-client-C5G4h_OJ.mjs → hosted-client-Io01s5By.mjs} +9 -3
  60. package/dist/{hosted-ios-Bik035eL.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
  61. package/dist/{hosted-logs-CI9Az9a4.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
  62. package/dist/{hosted-macos-DABm3ScO.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
  63. package/dist/{hosted-native-DbV2aUVw.mjs → hosted-native-BdAQi21M.mjs} +17 -14
  64. package/dist/{idle-shutdown-DYiMBn34.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
  65. package/dist/{ios-DYUr9LGc.mjs → ios-BZ9dg2Fr.mjs} +8 -7
  66. package/dist/{ios-BWbHFZVz.mjs → ios-CXLIUxXJ.mjs} +180 -24
  67. package/dist/ios-CZuv6gRv.mjs +1112 -0
  68. package/dist/{ios-DCrkgXEM.mjs → ios-VGvNdsv2.mjs} +1 -1
  69. package/dist/{ios-device-CrW8aMb5.mjs → ios-device-B1B14xND.mjs} +1 -1
  70. package/dist/{ios-device-CJ_ZOGky.mjs → ios-device-BreZOpM0.mjs} +3 -3
  71. package/dist/ios-project-B9drt_aY.mjs +197 -0
  72. package/dist/{ios-state-By0XuLTQ.mjs → ios-state-CjrL2qv-.mjs} +1 -1
  73. package/dist/js-swap-C8icNYIY.mjs +432 -0
  74. package/dist/launch-DxH0THLP.mjs +745 -0
  75. package/dist/{react-native-ios-CSpIxexZ.mjs → launch-YrbqaIFj.mjs} +59 -612
  76. package/dist/{launch-verify-DCveSE6d.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
  77. package/dist/{logs-Bao1HOMy.mjs → logs-DHaRNfg7.mjs} +11 -11
  78. package/dist/macos-C0iljhsN.mjs +2 -0
  79. package/dist/{macos-ciyBdTY5.mjs → macos-V_3Ui7g4.mjs} +42 -50
  80. package/dist/macos-run.mjs +1 -1
  81. package/dist/maintenance-run.mjs +13 -10
  82. package/dist/{metro-DI2AjPF_.mjs → metro-D_j9sN-B.mjs} +18 -5
  83. package/dist/{metro-gateway-BxpJLIwh.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
  84. package/dist/miss-reason-BPAzZS0r.mjs +238 -0
  85. package/dist/{named-ports-B4iWH4E-.mjs → named-ports-C2lvoPsb.mjs} +3 -3
  86. package/dist/native-android-lHzaew7r.mjs +226 -0
  87. package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
  88. package/dist/{native-runtime-BGxsbfny.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
  89. package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
  90. package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
  91. package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
  92. package/dist/offload-worker.d.mts +41 -7
  93. package/dist/offload-worker.mjs +409 -74
  94. package/dist/{ownership-EB0ySdGK.mjs → ownership-DXzMMSx6.mjs} +2 -2
  95. package/dist/{placement-log-Dxe34rJm.mjs → placement-log-reFbjqEr.mjs} +1 -1
  96. package/dist/plan-BDk2AeY_.mjs +260 -0
  97. package/dist/plan-placement-D_YYlE6N.mjs +73 -0
  98. package/dist/{ports-ByPc0_97.mjs → ports-jzvAJXXL.mjs} +3 -3
  99. package/dist/{prebuild-BKJ3wJI1.mjs → prebuild-Bw44QxVh.mjs} +4 -4
  100. package/dist/{preview-BbSottmO.mjs → preview-BaBJ72Al.mjs} +50 -32
  101. package/dist/project-B8_duAzW.mjs +1067 -0
  102. package/dist/project-plan-BPwbLwQu.mjs +10 -0
  103. package/dist/{pull-request-IHNdMnG8.mjs → pull-request-vOhLNmIb.mjs} +1 -1
  104. package/dist/pull-requests.mjs +1 -1
  105. package/dist/react-native-android-chm1DMlA.mjs +921 -0
  106. package/dist/react-native-build-oAw6gQeW.mjs +239 -0
  107. package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
  108. package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
  109. package/dist/{recordings-Bv8McZN4.mjs → recordings-Bk-VivUV.mjs} +1 -1
  110. package/dist/{reload-rAPdqeRR.mjs → reload-D34GkY78.mjs} +17 -13
  111. package/dist/remote-BU9UyhCJ.mjs +192 -0
  112. package/dist/{remote-cache-N3hAEaAL.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
  113. package/dist/result-BDoRk1k3.mjs +186 -0
  114. package/dist/{run-lAkle1-c.mjs → run-qvff78hv.mjs} +3 -3
  115. package/dist/{server-bare-CkIjnegq.mjs → server-bare-dWjAarki.mjs} +5 -5
  116. package/dist/server-command-7XIKlWtO.mjs +69 -0
  117. package/dist/{server-expo-n3tUi3Em.mjs → server-expo-CsYu2aKL.mjs} +107 -82
  118. package/dist/server-expo-DV43vep4.mjs +2 -0
  119. package/dist/{settings-CxgngUZk.mjs → settings-Bbztm4oV.mjs} +179 -129
  120. package/dist/{settings-2am7TSxp.mjs → settings-CT3E71-i.mjs} +6 -6
  121. package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
  122. package/dist/settings.schema.json +84 -0
  123. package/dist/simslim-ChMfe8rg.mjs +149 -0
  124. package/dist/{slot-launch-HV_KtPIw.mjs → slot-launch-B9hn96wd.mjs} +6 -6
  125. package/dist/{stage-BgaZJVZY.mjs → stage-BNKKdDNc.mjs} +6 -3
  126. package/dist/start-CbQCSnXQ.mjs +2 -0
  127. package/dist/{start-DtxthMfI.mjs → start-CdvcTaXr.mjs} +97 -68
  128. package/dist/{state-Tp4uImDS.mjs → state-Boo0IMJq.mjs} +1 -1
  129. package/dist/{state-D2KtnALG.mjs → state-DI84A-uu.mjs} +29 -10
  130. package/dist/{stats-8EJ5ivFT.mjs → stats-BIIDrjA8.mjs} +5 -5
  131. package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
  132. package/dist/{status-BOyp0CUl.mjs → status-DARMkc9q.mjs} +81 -293
  133. package/dist/status-watch-DvmI3SmN.mjs +296 -0
  134. package/dist/{stim-desktop-C65jk_q2.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
  135. package/dist/{stop-DRipAg-e.mjs → stop-CCZS-C9m.mjs} +2 -2
  136. package/dist/{stop-D0UIpZuh.mjs → stop-WQPQHLuy.mjs} +5 -5
  137. package/dist/{stop-zDlknFoz.mjs → stop-iNemHsJC.mjs} +21 -20
  138. package/dist/supervisor-run.d.mts +7 -2
  139. package/dist/supervisor-run.mjs +32 -20
  140. package/dist/{support-DsNaFg6D.mjs → support-CnE_SIjt.mjs} +17 -7
  141. package/dist/{support-CNqYkV0y.mjs → support-DCco5fut.mjs} +61 -8
  142. package/dist/{swiftpm-macos-aJzPAj1t.mjs → swiftpm-macos-afeNUExW.mjs} +5 -5
  143. package/dist/tailnet-CoJUb2tB.mjs +265 -0
  144. package/dist/toolchain-BIupIro1.mjs +2 -0
  145. package/dist/{toolchain-C3xSoyUl.mjs → toolchain-DqyDXs30.mjs} +206 -53
  146. package/dist/{trigger-CAhmG-4s.mjs → trigger-C0MWBi8O.mjs} +2 -2
  147. package/dist/trigger-SHLOWJ4O.mjs +2 -0
  148. package/dist/{warm-progress-pFLB2e6P.mjs → warm-progress-C3ASD6z5.mjs} +6 -6
  149. package/dist/{watchman-BL1IdOtq.mjs → watchman-CQl51YZu.mjs} +6 -6
  150. package/dist/{web-DbbrPUn0.mjs → web-B3eldHFH.mjs} +9 -13
  151. package/dist/web-BLXpOe6b.mjs +2 -0
  152. package/dist/web-run.mjs +10 -10
  153. package/dist/{workspace-state-CR9X86xJ.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
  154. package/dist/{workspaces-Djb2gfi9.mjs → workspaces-D2xSHBDY.mjs} +1260 -1258
  155. package/dist/{worktree-BL4M1rhB.mjs → worktree-BxDqaTev.mjs} +84 -48
  156. package/dist/worktree-q7_OZNY0.mjs +2 -0
  157. package/package.json +8 -6
  158. package/shim/native-android.gradle +101 -0
  159. package/dist/android-BXc6BmEi.mjs +0 -3732
  160. package/dist/android-BvV1gGdN.mjs +0 -4
  161. package/dist/ios-ITYno9rO.mjs +0 -2241
  162. package/dist/macos-nIOATJmR.mjs +0 -2
  163. package/dist/metro-store-BAHFcJm6.mjs +0 -106
  164. package/dist/miss-reason-CjQCOKqq.mjs +0 -1743
  165. package/dist/plan-placement-BVY59qa8.mjs +0 -290
  166. package/dist/project-B5eQ1USs.mjs +0 -612
  167. package/dist/react-native-ios-BMh2i25I.mjs +0 -2
  168. package/dist/server-expo-DGsdUGX2.mjs +0 -2
  169. package/dist/start-D8NbxNBb.mjs +0 -2
  170. package/dist/trigger-CoalsMTV.mjs +0 -2
  171. package/dist/web-DFpFeZu5.mjs +0 -2
  172. package/dist/worktree-DV-A0LNL.mjs +0 -2
@@ -0,0 +1,226 @@
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { $ as settingValueAt } from "./settings-Bbztm4oV.mjs";
3
+ import { x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
4
+ import { T as findBuildTool, o as androidHome } from "./android-BsYNR81W.mjs";
5
+ import { i as skippedMissReason } from "./miss-reason-BPAzZS0r.mjs";
6
+ import { o as resolveCcache } from "./ccache-CjHQ5F8g.mjs";
7
+ import { a as buildGradle, r as androidSdkRefusal } from "./gradle-C2OEKCCI.mjs";
8
+ import { n as androidToolchain } from "./toolchain-DqyDXs30.mjs";
9
+ import { i as nativeGradleTransfer, t as gradleOffloadInputs } from "./native-gradle-inputs-BQnIdAlL.mjs";
10
+ import { n as androidProcessRuntime } from "./launch-DxH0THLP.mjs";
11
+ import { existsSync, readFileSync, statSync } from "node:fs";
12
+ import { isAbsolute, join } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ //#region src/integrations/native-android.ts
15
+ const CACHE_LIMIT = "Native Gradle inputs can include arbitrary external files and plugins; Stim artifact caching is unavailable. Offload requires a complete android.offloadInputs declaration. Gradle still owns incremental and task-cache reuse.";
16
+ const MODEL_LIMIT = "Native Android requires AGP with androidComponents, one application module and configuration-on-demand disabled. Gradle resolves the exact variant and APK outputs during the build.";
17
+ function refusal(reason) {
18
+ return {
19
+ code: "STIM_BUILD_FAILED",
20
+ reason,
21
+ remedy: "Select one signed standalone APK for the requested variant and target ABI in the Android application module, then retry. Stim does not sign APKs or install split APK sets."
22
+ };
23
+ }
24
+ function selectNativeApk(value, variant, abi) {
25
+ const model = value;
26
+ if (!model || model.schema !== 1 || typeof model.module !== "string" || !model.module.startsWith(":") || model.variant !== variant || typeof model.applicationId !== "string" || !/^[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+$/.test(model.applicationId) || typeof model.sdkDirectory !== "string" || !isAbsolute(model.sdkDirectory) || !Array.isArray(model.elements) || !model.elements.every((element) => element && typeof element.path === "string" && isAbsolute(element.path) && element.path.endsWith(".apk") && Array.isArray(element.filters) && element.filters.every((filter) => filter && typeof filter.type === "string" && typeof filter.value === "string"))) return refusal("Gradle did not export a valid model for the requested native Android variant.");
27
+ const universal = model.elements.filter((element) => element.filters.length === 0);
28
+ const candidates = universal.length ? universal : model.elements.filter((element) => abi !== null && element.filters.length === 1 && element.filters[0].type === "ABI" && element.filters[0].value === abi);
29
+ if (candidates.length !== 1) return refusal(`Native variant "${variant}" has ${candidates.length} installable APK candidates for ${abi ?? "an unspecified ABI"}. Density splits and ambiguous output sets are unsupported.`);
30
+ return {
31
+ apkPath: candidates[0].path,
32
+ androidPackage: model.applicationId
33
+ };
34
+ }
35
+ async function locateNativeApk(modelFile, variant, abi) {
36
+ let value;
37
+ try {
38
+ value = JSON.parse(readFileSync(modelFile, "utf8"));
39
+ } catch {
40
+ return refusal("Gradle succeeded without exporting the native Android APK model.");
41
+ }
42
+ const located = selectNativeApk(value, variant, abi);
43
+ if ("code" in located) return located;
44
+ try {
45
+ if (!statSync(located.apkPath).isFile()) return refusal("The APK selected by Gradle is not a file.");
46
+ } catch {
47
+ return refusal("The APK selected by Gradle does not exist.");
48
+ }
49
+ const signer = findBuildTool(["apksigner"], { home: value.sdkDirectory });
50
+ if (!signer) return refusal("No Android SDK apksigner is available to verify the native APK signature.");
51
+ try {
52
+ await getExecutor().runFileAsync(signer.path, ["verify", located.apkPath], { timeoutMs: 3e4 });
53
+ } catch (error) {
54
+ return refusal(`The native APK signature could not be verified: ${error.message}`);
55
+ }
56
+ return located;
57
+ }
58
+ function nativeAndroidProject(root) {
59
+ return {
60
+ isExpo: false,
61
+ packageRemedy: "Check the applicationId reported by AGP for the selected application variant.",
62
+ appIds: () => ({
63
+ bundleId: null,
64
+ androidPackage: null
65
+ }),
66
+ variantProblem: () => null,
67
+ targets: [
68
+ "emulator",
69
+ "physical",
70
+ "hosted"
71
+ ],
72
+ eas: false,
73
+ runtimeKind: () => "process",
74
+ plan: async () => ({ refusal: {
75
+ code: "STIM_BAD_ARG",
76
+ message: `${MODEL_LIMIT} --plan does not execute Gradle. ${CACHE_LIMIT}`,
77
+ remedy: "Run `stim android` with an exact --variant to resolve and build the native app."
78
+ } }),
79
+ runtime: ({ phase }) => androidProcessRuntime(async () => {
80
+ phase("metro", "skipped (native process)");
81
+ return {
82
+ ok: true,
83
+ prepared: { metroPort: null }
84
+ };
85
+ }),
86
+ artifact: ({ writer, buildPlan, target, out, estimates, settings }) => {
87
+ const variant = buildPlan.variant ?? "debug";
88
+ const inputs = settingValueAt(settings, "android.offloadInputs");
89
+ let transfer = null;
90
+ const modelFile = join(workspaceDir(root), "gradle-build", `native-apk-${encodeURIComponent(variant)}.json`);
91
+ return {
92
+ identity: async () => ({ cacheIneligible: CACHE_LIMIT }),
93
+ cache: () => {
94
+ throw new Error(CACHE_LIMIT);
95
+ },
96
+ prepare: async () => {},
97
+ reconcile: async () => ({
98
+ identity: null,
99
+ rekeyedBy: [],
100
+ cacheRefusal: null
101
+ }),
102
+ validate: async () => null,
103
+ materialize: async () => null,
104
+ explain: () => ({
105
+ reason: skippedMissReason(CACHE_LIMIT),
106
+ diff: null
107
+ }),
108
+ untrackedLine: () => null,
109
+ legacyCache: null,
110
+ offload: {
111
+ supportsUncachedArtifacts: true,
112
+ get unsupported() {
113
+ if (buildPlan.cas) return "Apple Clang CAS builds build here";
114
+ try {
115
+ gradleOffloadInputs(inputs);
116
+ return null;
117
+ } catch (error) {
118
+ return error.message;
119
+ }
120
+ },
121
+ target: () => {
122
+ transfer = nativeGradleTransfer(root, inputs);
123
+ return {
124
+ platform: "android",
125
+ native: "gradle",
126
+ local: androidToolchain(),
127
+ requires: {
128
+ ndk: null,
129
+ buildTools: null,
130
+ compileSdk: null
131
+ }
132
+ };
133
+ },
134
+ get request() {
135
+ if (!transfer) throw new Error("Native Gradle offload needs a declared source inventory.");
136
+ return {
137
+ platform: "android",
138
+ isExpo: false,
139
+ native: {
140
+ provider: "gradle",
141
+ transfer
142
+ },
143
+ android: {
144
+ variant,
145
+ abi: target.abi,
146
+ gradleBuildCache: buildPlan.gradleBuildCache,
147
+ pch: buildPlan.pch,
148
+ compilerCache: buildPlan.compilerCache === "none" ? "none" : "ccache"
149
+ }
150
+ };
151
+ },
152
+ unchanged: async () => transfer !== null && nativeGradleTransfer(root, inputs).digest === transfer.digest
153
+ },
154
+ compile: async () => {
155
+ const script = ["../shim/native-android.gradle", "../../shim/native-android.gradle"].map((path) => fileURLToPath(new URL(path, import.meta.url))).find(existsSync);
156
+ if (!script) throw new Error("Stim installation is missing shim/native-android.gradle.");
157
+ return buildGradle({
158
+ root,
159
+ logWriter: writer,
160
+ variant,
161
+ project: {
162
+ directory: root,
163
+ gradlew: join(root, process.platform === "win32" ? "gradlew.bat" : "gradlew"),
164
+ module: ":",
165
+ outputsDir: root
166
+ },
167
+ task: ":stimExportAndroidApk",
168
+ projectArgs: [
169
+ "--init-script",
170
+ script,
171
+ `-Pstim.native.variant=${variant}`,
172
+ `-Pstim.native.model=${modelFile}`
173
+ ],
174
+ locate: () => locateNativeApk(modelFile, variant, target.abi)
175
+ }, {
176
+ estimateMs: estimates().coldBuildMs,
177
+ ccache: buildPlan.compilerCache === "ccache" ? resolveCcache({
178
+ root,
179
+ onNote: out
180
+ }) : null,
181
+ cas: buildPlan.cas,
182
+ buildCache: buildPlan.gradleBuildCache,
183
+ pch: buildPlan.pch,
184
+ compilerCacheDisabled: buildPlan.compilerCache === "none"
185
+ });
186
+ }
187
+ };
188
+ }
189
+ };
190
+ }
191
+ function nativeAndroidDoctor(root) {
192
+ return { inspect: () => {
193
+ const sdkPath = androidHome();
194
+ const sdk = androidSdkRefusal({
195
+ sdkPath,
196
+ sdkExists: existsSync(sdkPath),
197
+ hasLocalProperties: existsSync(join(root, "local.properties")),
198
+ localPropertiesPath: "local.properties"
199
+ });
200
+ const wrapper = join(root, process.platform === "win32" ? "gradlew.bat" : "gradlew");
201
+ return [
202
+ {
203
+ level: "note",
204
+ title: "Native Android Gradle project",
205
+ detail: `${MODEL_LIMIT} ${CACHE_LIMIT} Metro and EAS are unsupported; local, physical and hosted targets use native process readiness.`,
206
+ fix: null
207
+ },
208
+ ...sdk ? [{
209
+ level: "cost",
210
+ code: "android-sdk-missing",
211
+ title: "No Android SDK was found",
212
+ detail: sdk.reason,
213
+ fix: sdk.remedy
214
+ }] : [],
215
+ ...!existsSync(wrapper) ? [{
216
+ level: "cost",
217
+ code: "android-wrapper-missing",
218
+ title: "The Gradle wrapper for this host is missing",
219
+ detail: wrapper,
220
+ fix: "Restore the project Gradle wrapper."
221
+ }] : []
222
+ ];
223
+ } };
224
+ }
225
+ //#endregion
226
+ export { nativeAndroidDoctor, nativeAndroidProject };
@@ -0,0 +1,356 @@
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync, realpathSync } from "node:fs";
3
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ //#region src/offload/manifest.ts
6
+ function manifestDigest(entries) {
7
+ const hash = createHash("sha256");
8
+ for (const entry of entries.toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)) hash.update(`${entry.path}\0${entry.kind}\0${entry.sha256}\n`);
9
+ return hash.digest("hex");
10
+ }
11
+ //#endregion
12
+ //#region src/integrations/native-inputs.ts
13
+ var NativeInputError = class extends Error {};
14
+ function fingerprintNativeInputs(inputs, { excluded = [], ignoredDirectoryMarkers = [], parameters }) {
15
+ const exclusions = excluded.map((path) => resolve(path));
16
+ const directoryMarkers = new Set(ignoredDirectoryMarkers.map((path) => resolve(path)));
17
+ const entries = [];
18
+ const names = /* @__PURE__ */ new Set();
19
+ const isExcluded = (path) => exclusions.some((output) => path === output || path.startsWith(`${output}${sep}`));
20
+ let admit;
21
+ const record = (path, kind, content = "") => {
22
+ entries.push({
23
+ path,
24
+ kind,
25
+ sha256: createHash("sha256").update(content).digest("hex")
26
+ });
27
+ };
28
+ const walk = (absolute, logical, ancestors, optional = false, relative = null) => {
29
+ let stat;
30
+ try {
31
+ stat = lstatSync(absolute);
32
+ } catch (error) {
33
+ if (optional && error.code === "ENOENT") {
34
+ record(logical, "absent");
35
+ return;
36
+ }
37
+ throw error;
38
+ }
39
+ if (stat.isSymbolicLink()) {
40
+ const target = readlinkSync(absolute);
41
+ const resolved = resolve(dirname(absolute), target);
42
+ if (isExcluded(resolved)) throw new NativeInputError(`Native input ${logical} links into an excluded output.`);
43
+ if (ancestors.has(absolute)) throw new NativeInputError(`Native input ${logical} contains a link cycle.`);
44
+ record(logical, "link", target);
45
+ walk(resolved, `${logical}/@target`, /* @__PURE__ */ new Set([...ancestors, absolute]));
46
+ } else if (stat.isDirectory()) {
47
+ const canonical = realpathSync(absolute);
48
+ if (ancestors.has(canonical)) throw new NativeInputError(`Native input ${logical} contains a directory cycle.`);
49
+ if (!directoryMarkers.has(absolute)) record(logical, "directory");
50
+ const next = /* @__PURE__ */ new Set([...ancestors, canonical]);
51
+ for (const name of readdirSync(absolute).toSorted()) {
52
+ const child = join(absolute, name);
53
+ const childRelative = relative === null ? null : relative ? `${relative}/${name}` : name;
54
+ if (isExcluded(child) || childRelative !== null && admit && !admit(childRelative)) continue;
55
+ walk(child, `${logical}/${name}`, next, false, childRelative);
56
+ }
57
+ } else if (stat.isFile()) record(logical, `file:${stat.mode & 73}`, readFileSync(absolute));
58
+ else throw new NativeInputError(`Native input ${logical} is not a file, directory or symbolic link.`);
59
+ };
60
+ try {
61
+ for (const input of inputs) {
62
+ if (!input.name || names.has(input.name)) throw new NativeInputError("Native input names must be unique.");
63
+ names.add(input.name);
64
+ const path = resolve(input.path);
65
+ if (isExcluded(path)) throw new NativeInputError(`Native input ${input.name} is also an excluded output.`);
66
+ admit = input.admit;
67
+ walk(path, input.name, /* @__PURE__ */ new Set(), input.optional, "");
68
+ }
69
+ } catch (error) {
70
+ if (error instanceof NativeInputError) throw error;
71
+ throw new NativeInputError(`Could not read native build inputs: ${error.message}`, { cause: error });
72
+ }
73
+ const sorted = entries.toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
74
+ return {
75
+ hash: createHash("sha256").update("stim-native-inputs-v1\0").update(JSON.stringify(parameters)).update("\0").update(manifestDigest(sorted)).digest("hex"),
76
+ entries: sorted,
77
+ parameters
78
+ };
79
+ }
80
+ //#endregion
81
+ //#region src/offload/native-source.ts
82
+ function* repositoryInputs(snapshot) {
83
+ const links = snapshot.entries.filter((entry) => entry.kind === "link").map((entry) => `${entry.path}/@target`);
84
+ for (const entry of snapshot.entries) {
85
+ if (entry.path === "repository") continue;
86
+ if (!entry.path.startsWith("repository/")) throw new Error("Native offload requires every input to be inside the repository.");
87
+ if (links.some((link) => entry.path === link || entry.path.startsWith(`${link}/`))) continue;
88
+ yield {
89
+ entry,
90
+ path: entry.path.slice(11)
91
+ };
92
+ }
93
+ }
94
+ const absentInput = (path) => /* @__PURE__ */ new Error(`Native input ${path} is ignored or absent from the source transfer; it was not uploaded.`);
95
+ /** Throws the same membership refusal as nativeTransferManifest, from the git-visible paths alone. */
96
+ function checkNativeTransferMembership(snapshot, visible) {
97
+ for (const { entry, path } of repositoryInputs(snapshot)) {
98
+ if (entry.kind === "directory" || visible.has(path)) continue;
99
+ for (let index = path.indexOf("/"); index !== -1; index = path.indexOf("/", index + 1)) if (visible.has(path.slice(0, index))) throw new Error(`Native input ${path} is inside the git submodule ${path.slice(0, index)}; submodules are not transferred.`);
100
+ throw absentInput(path);
101
+ }
102
+ }
103
+ function nativeTransferManifest(root, snapshot, visible) {
104
+ const files = new Map(visible.map((file) => [file.path, file]));
105
+ root = realpathSync(root);
106
+ const selected = [];
107
+ const empty = createHash("sha256").update("").digest("hex");
108
+ for (const { entry, path } of repositoryInputs(snapshot)) {
109
+ if (entry.kind === "directory") {
110
+ selected.push({
111
+ path,
112
+ kind: "directory",
113
+ size: 0,
114
+ sha256: empty
115
+ });
116
+ continue;
117
+ }
118
+ const file = files.get(path);
119
+ if (!file) throw absentInput(path);
120
+ const kind = entry.kind === "file:0" ? "file" : entry.kind === "file:73" ? "exec" : entry.kind;
121
+ if (kind !== file.kind || entry.sha256 !== file.sha256) throw new Error(`Native input ${path} changed or has an unsupported executable mode.`);
122
+ selected.push(file);
123
+ if (kind === "link") {
124
+ const link = join(root, path);
125
+ const target = readlinkSync(link);
126
+ const destination = relative(root, realpathSync(resolve(dirname(link), target)));
127
+ if (isAbsolute(target) || isAbsolute(destination) || destination === ".." || destination.startsWith(`..${sep}`)) throw new Error(`Native input ${path} has a link that cannot be relocated inside the repository.`);
128
+ }
129
+ }
130
+ return selected.toSorted((a, b) => a.path.localeCompare(b.path));
131
+ }
132
+ function verifyNativeTransfer(root, files, digest, ignoredDirectoryMarkers = []) {
133
+ return manifestDigest(nativeTransferManifest(root, fingerprintNativeInputs([{
134
+ name: "repository",
135
+ path: root
136
+ }], {
137
+ excluded: [join(root, ".git")],
138
+ ignoredDirectoryMarkers,
139
+ parameters: null
140
+ }), files)) === digest;
141
+ }
142
+ /** The exact source a build needs: tracked and untracked, not ignored, as `git ls-files -co --exclude-standard`. */
143
+ function sourceManifest(repoRoot, strict = false) {
144
+ const files = [];
145
+ for (const path of gitVisiblePaths(repoRoot)) {
146
+ const absolute = join(repoRoot, path);
147
+ let stat;
148
+ try {
149
+ stat = lstatSync(absolute);
150
+ } catch (error) {
151
+ if (strict && error.code !== "ENOENT") throw error;
152
+ continue;
153
+ }
154
+ if (stat.isSymbolicLink()) {
155
+ const target = Buffer.from(readlinkSync(absolute));
156
+ files.push({
157
+ path,
158
+ kind: "link",
159
+ size: target.length,
160
+ sha256: createHash("sha256").update(target).digest("hex")
161
+ });
162
+ } else if (stat.isFile()) {
163
+ const content = readFileSync(absolute);
164
+ files.push({
165
+ path,
166
+ kind: stat.mode & 73 ? "exec" : "file",
167
+ size: content.length,
168
+ sha256: createHash("sha256").update(content).digest("hex")
169
+ });
170
+ } else if (strict) throw new Error(`Native source ${path} is not a file or link; transfer submodule contents explicitly.`);
171
+ }
172
+ return files;
173
+ }
174
+ function gitVisiblePaths(repoRoot) {
175
+ const listed = getExecutor().runFile("git", [
176
+ "-C",
177
+ repoRoot,
178
+ "ls-files",
179
+ "-z",
180
+ "-co",
181
+ "--exclude-standard"
182
+ ], {
183
+ untrimmed: true,
184
+ timeoutMs: 12e4
185
+ });
186
+ return new Set(listed.split("\0").filter(Boolean));
187
+ }
188
+ //#endregion
189
+ //#region src/integrations/native-gradle-inputs.ts
190
+ function containedPath(path) {
191
+ return typeof path === "string" && path.length > 0 && !path.includes("\\") && !path.includes(":") && !path.includes("\0") && !path.split("/").some((part) => !part || part === "." || part === ".." || part.toLowerCase() === ".git");
192
+ }
193
+ function gradleOffloadInputs(value) {
194
+ const input = value;
195
+ if (!input || typeof input !== "object" || input.complete !== true || Object.keys(input).some((key) => ![
196
+ "complete",
197
+ "ignored",
198
+ "outputs"
199
+ ].includes(key)) || !Array.isArray(input.ignored) || !input.ignored.every(containedPath) || !Array.isArray(input.outputs) || !input.outputs.every(containedPath)) throw new Error("Native Gradle offload requires android.offloadInputs with complete: true, ignored: [exact repository-relative files], and outputs: [generated repository-relative directories].");
200
+ const ignored = [...new Set(input.ignored)].toSorted();
201
+ const outputs = [...new Set(input.outputs)].toSorted();
202
+ if (ignored.some((path) => path.split("/").at(-1) === "local.properties")) throw new Error("local.properties is machine-local; remove it from android.offloadInputs.ignored.");
203
+ if (outputs.some((path) => path.split("/").some((part) => part === ".gradle" || part === ".kotlin"))) throw new Error("Gradle project state is worker-owned and cannot be declared as a generated output.");
204
+ for (const output of outputs) if (outputs.some((other) => other !== output && output.startsWith(`${other}/`))) throw new Error(`Generated output ${output} is nested inside another output declaration.`);
205
+ return {
206
+ complete: true,
207
+ ignored,
208
+ outputs
209
+ };
210
+ }
211
+ const below = (path, directory) => path === directory || path.startsWith(`${directory}/`);
212
+ function gradleStateDirectories(project) {
213
+ return [".gradle", ".kotlin"].map((name) => project ? `${project}/${name}` : name);
214
+ }
215
+ function requireRealParents(repository, path) {
216
+ const parts = path.split("/");
217
+ for (let index = 1; index < parts.length; index++) {
218
+ const parent = join(repository, ...parts.slice(0, index));
219
+ const stat = lstatSync(parent, { throwIfNoEntry: false });
220
+ if (stat && !stat.isDirectory()) throw new Error(`Native input ${path} has a non-directory parent.`);
221
+ }
222
+ }
223
+ function nativeGradleTransfer(root, value) {
224
+ const declaration = gradleOffloadInputs(value);
225
+ const repository = realpathSync(getExecutor().runFile("git", [
226
+ "-C",
227
+ root,
228
+ "rev-parse",
229
+ "--show-toplevel"
230
+ ]));
231
+ const project = relative(repository, realpathSync(root)).split(sep).join("/");
232
+ if (project && !containedPath(project)) throw new Error("The native Gradle project leaves its repository.");
233
+ if (lstatSync(join(repository, project, "buildSrc"), { throwIfNoEntry: false })?.isDirectory()) throw new Error("Native Gradle offload does not support buildSrc: AGP does not report its build directories, so the worker cannot keep them.");
234
+ const state = gradleStateDirectories(project);
235
+ const files = new Map(sourceManifest(repository, true).map((file) => [file.path, file]));
236
+ for (const path of declaration.ignored) {
237
+ requireRealParents(repository, path);
238
+ const absolute = join(repository, path);
239
+ const stat = lstatSync(absolute);
240
+ if (!stat.isFile() && !stat.isSymbolicLink()) throw new Error(`Ignored native input ${path} must be an exact file or link, not a directory.`);
241
+ const content = stat.isSymbolicLink() ? Buffer.from(readlinkSync(absolute)) : readFileSync(absolute);
242
+ files.set(path, {
243
+ path,
244
+ kind: stat.isSymbolicLink() ? "link" : stat.mode & 73 ? "exec" : "file",
245
+ size: content.length,
246
+ sha256: createHash("sha256").update(content).digest("hex")
247
+ });
248
+ }
249
+ for (const file of files.values()) {
250
+ if (!containedPath(file.path)) throw new Error(`Native input ${file.path} is not a contained relative path.`);
251
+ requireRealParents(repository, file.path);
252
+ if (state.some((path) => below(file.path, path))) throw new Error("Gradle project state cannot be transferred as source.");
253
+ if (declaration.outputs.some((output) => below(file.path, output) || below(output, file.path))) throw new Error(`Native input ${file.path} overlaps a declared generated output.`);
254
+ if (file.path.split("/").at(-1) === "local.properties") {
255
+ if (file.kind === "link") throw new Error(`Native input ${file.path} is a machine-local properties link.`);
256
+ if (readFileSync(join(repository, file.path), "utf8").split(/\r?\n/).some((line) => line.trim() && !/^\s*[#!]/.test(line) && !/^\s*sdk\.dir\s*[:=].*[^\\]$/.test(line))) throw new Error(`Native input ${file.path} contains unsupported machine-local properties.`);
257
+ files.delete(file.path);
258
+ continue;
259
+ }
260
+ }
261
+ for (const file of files.values()) if (file.kind === "link") {
262
+ const absolute = join(repository, file.path);
263
+ const target = readlinkSync(absolute);
264
+ const resolved = realpathSync(resolve(dirname(absolute), target));
265
+ const destination = relative(repository, resolved).split(sep).join("/");
266
+ if (isAbsolute(target) || !containedPath(destination) || !files.has(destination)) throw new Error(`Native input ${file.path} links to a target outside the declared source inventory.`);
267
+ }
268
+ for (const output of declaration.outputs) {
269
+ requireRealParents(repository, output);
270
+ const stat = lstatSync(join(repository, output), { throwIfNoEntry: false });
271
+ if (stat && !stat.isDirectory()) throw new Error(`Generated output ${output} is not a real directory.`);
272
+ if (state.some((path) => below(output, path) || below(path, output))) throw new Error(`Generated output ${output} overlaps Gradle project state.`);
273
+ }
274
+ const empty = createHash("sha256").update("").digest("hex");
275
+ for (const path of files.keys()) {
276
+ const parts = path.split("/");
277
+ for (let index = 1; index < parts.length; index++) {
278
+ const directory = parts.slice(0, index).join("/");
279
+ files.set(directory, {
280
+ path: directory,
281
+ kind: "directory",
282
+ size: 0,
283
+ sha256: empty
284
+ });
285
+ }
286
+ }
287
+ const selected = [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path));
288
+ return {
289
+ repository,
290
+ project,
291
+ declaration,
292
+ files: selected,
293
+ digest: manifestDigest(selected)
294
+ };
295
+ }
296
+ function canonicalParent(path) {
297
+ const missing = [];
298
+ while (!existsSync(path) && dirname(path) !== path) {
299
+ missing.unshift(basename(path));
300
+ path = dirname(path);
301
+ }
302
+ return join(realpathSync(path), ...missing);
303
+ }
304
+ function nativeGradleOutputs(repository, declaration, reported) {
305
+ if (!Array.isArray(reported) || !reported.every((path) => typeof path === "string" && isAbsolute(path))) throw new Error("AGP did not report the configured native Gradle build directories.");
306
+ const real = realpathSync(repository);
307
+ const reportedPaths = /* @__PURE__ */ new Set();
308
+ for (const absolute of reported) {
309
+ const resolved = resolve(absolute);
310
+ const canonical = join(canonicalParent(dirname(resolved)), basename(resolved));
311
+ const path = relative(real, canonical).split(sep).join("/");
312
+ if (!containedPath(path)) throw new Error("A Gradle build directory leaves the transferred repository.");
313
+ requireRealParents(repository, path);
314
+ const stat = lstatSync(join(repository, path), { throwIfNoEntry: false });
315
+ if (stat && !stat.isDirectory()) throw new Error(`Gradle build directory ${path} is not a real directory.`);
316
+ reportedPaths.add(path);
317
+ }
318
+ for (const output of declaration.outputs) if (!reportedPaths.has(output)) throw new Error(`Declared output ${output} was not reported by AGP.`);
319
+ for (const path of reportedPaths) if (lstatSync(join(repository, path), { throwIfNoEntry: false })?.isDirectory() && !declaration.outputs.some((output) => below(path, output))) throw new Error(`Gradle build directory ${path} is not declared; add it to android.offloadInputs.outputs.`);
320
+ return declaration.outputs.filter((path) => lstatSync(join(repository, path), { throwIfNoEntry: false })?.isDirectory());
321
+ }
322
+ function validateGradleManifest(project, declaration, files) {
323
+ gradleOffloadInputs(declaration);
324
+ if (project && !containedPath(project)) throw new Error("The native Gradle project leaves its repository.");
325
+ const excluded = [...declaration.outputs, ...gradleStateDirectories(project)];
326
+ for (const file of files) if (!containedPath(file.path) || excluded.some((path) => below(file.path, path) || file.kind !== "directory" && below(path, file.path))) throw new Error(`Native source ${file.path} overlaps worker outputs or leaves the repository.`);
327
+ for (const path of declaration.ignored) if (!files.some((file) => file.path === path && file.kind !== "directory")) throw new Error(`Declared ignored input ${path} is missing from the transfer.`);
328
+ }
329
+ function verifyGradleTransfer(repository, project, declaration, files, digest) {
330
+ validateGradleManifest(project, declaration, files);
331
+ const excluded = [...declaration.outputs, ...gradleStateDirectories(project)];
332
+ for (const path of excluded) {
333
+ requireRealParents(repository, path);
334
+ const stat = lstatSync(join(repository, path), { throwIfNoEntry: false });
335
+ if (stat && !stat.isDirectory()) throw new Error(`Worker output ${path} is not a real directory.`);
336
+ }
337
+ const markers = excluded.flatMap((path) => path.split("/").slice(0, -1).map((_, index) => join(repository, ...path.split("/").slice(0, index + 1))));
338
+ const snapshot = fingerprintNativeInputs([{
339
+ name: "repository",
340
+ path: repository
341
+ }], {
342
+ excluded: [join(repository, ".git"), ...excluded.map((path) => join(repository, path))],
343
+ ignoredDirectoryMarkers: markers.filter((path) => !files.some((file) => join(repository, file.path) === path)),
344
+ parameters: null
345
+ });
346
+ const known = new Set(files.map((file) => file.path));
347
+ for (const entry of snapshot.entries) {
348
+ if (!entry.path.startsWith("repository/") || entry.path.includes("/@target")) continue;
349
+ const parts = entry.path.slice(11).split("/");
350
+ const index = parts.findIndex((_, depth) => !known.has(parts.slice(0, depth + 1).join("/")));
351
+ if (index >= 0 && (index < parts.length - 1 || entry.kind === "directory")) throw new Error(`Native Gradle directory ${parts.slice(0, index + 1).join("/")} is outside the source transfer and not a declared output reported by AGP; such directories, for example, included builds or externalNativeBuild staging, are not supported for remote builds.`);
352
+ }
353
+ return manifestDigest(nativeTransferManifest(repository, snapshot, files)) === digest;
354
+ }
355
+ //#endregion
356
+ export { validateGradleManifest as a, gitVisiblePaths as c, verifyNativeTransfer as d, NativeInputError as f, nativeGradleTransfer as i, nativeTransferManifest as l, manifestDigest as m, gradleStateDirectories as n, verifyGradleTransfer as o, fingerprintNativeInputs as p, nativeGradleOutputs as r, checkNativeTransferMembership as s, gradleOffloadInputs as t, sourceManifest as u };
@@ -1,15 +1,15 @@
1
- import { l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
2
- import { r as readWorkspaceState$1, u as ensureWorkspaceStorage } from "./workspace-state-CR9X86xJ.mjs";
3
- import { x as metroPortSetting } from "./settings-CxgngUZk.mjs";
4
- import { u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
5
- import { r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING } from "./launch-verify-DCveSE6d.mjs";
6
- import { c as startDevServer } from "./start-DtxthMfI.mjs";
1
+ import { j as metroPortSetting } from "./settings-Bbztm4oV.mjs";
2
+ import { p as ensureWorkspaceStorage, r as readWorkspaceState$1 } from "./workspace-state-CSIFuuDa.mjs";
3
+ import { l as phaseLine } from "./command-output-BjPN99ZB.mjs";
4
+ import { u as resolveProjectMetro } from "./metro-D_j9sN-B.mjs";
5
+ import { c as startDevServer } from "./start-CdvcTaXr.mjs";
6
+ import { r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING } from "./launch-verify-BzRdbuO1.mjs";
7
7
  import { readIdleStop } from "@stim-cli/core/state";
8
8
  import chalk from "chalk";
9
9
  //#region src/commands/native-runtime.ts
10
10
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
11
- async function ensureDevServer({ root, port, settings, remote, note, resolve = resolveProjectMetro, start = startDevServer, readState = readWorkspaceState$1 }) {
12
- const pin = metroPortSetting(root);
11
+ async function ensureDevServer({ root, port, settings, settingsContext, remote, note, resolve = resolveProjectMetro, start = startDevServer, readState = readWorkspaceState$1 }) {
12
+ const pin = metroPortSetting(settings);
13
13
  const canReuse = !pin.error && (pin.port === null || pin.port === port);
14
14
  const held = port === null || !canReuse ? null : (await resolve(port, root)).metro;
15
15
  if (port !== null && held) return {
@@ -24,6 +24,7 @@ async function ensureDevServer({ root, port, settings, remote, note, resolve = r
24
24
  const result = await start({
25
25
  root,
26
26
  settings,
27
+ settingsContext,
27
28
  remote,
28
29
  out: note,
29
30
  note