stim 1.18.0 → 1.19.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.
- package/README.md +1 -1
- package/dist/{activity-BxnkDZDi.mjs → activity-BSw0x84R.mjs} +3 -3
- package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +5 -5
- package/dist/{android-BvwuMUJ9.mjs → android-BXc6BmEi.mjs} +507 -347
- package/dist/{android-DC3ZLuw0.mjs → android-BdQC6zs1.mjs} +6 -6
- package/dist/{android-BKA16DTf.mjs → android-BvV1gGdN.mjs} +3 -3
- package/dist/{android-CBwCNicO.mjs → android-DE5g_5gv.mjs} +2 -2
- package/dist/{android-cas-BBFyr9CA.mjs → android-cas-C87geAg-.mjs} +3 -3
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{api-D0VtFhqk.mjs → api-DIf_s86s.mjs} +5 -7
- package/dist/api-run.mjs +8 -8
- package/dist/api.d.mts +8 -2
- package/dist/api.mjs +1 -1
- package/dist/{app-install-D-PUENug.mjs → app-install-CFI4ptUL.mjs} +33 -13
- package/dist/{web-DTU0uiWj.mjs → browser-web-CDhqQxhv.mjs} +134 -172
- package/dist/{budget-DIhL2BKx.mjs → budget-Dz-kyXLv.mjs} +15 -202
- package/dist/{build-facts-DcLv2HSd.d.mts → build-facts-B87vo-Im.d.mts} +32 -1
- package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-DiwKSyv9.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-DJnmnS5q.mjs → chrome-BTUOo8p2.mjs} +1 -1
- package/dist/{cli-DNJMwADx.mjs → cli-C9Zvgbdc.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-DzhapoMB.mjs → client-CuUo8Nvg.mjs} +248 -23
- package/dist/collector-run.d.mts +6 -0
- package/dist/collector-run.mjs +6 -6
- package/dist/{command-output-CBtzyIgF.mjs → command-output-Bt8ygHE7.mjs} +1 -1
- package/dist/{config-CgYMahz7.mjs → config-DC5jEtd1.mjs} +6 -2
- package/dist/{created-devices-DKbeWsiK.mjs → created-devices-D0s26Hx5.mjs} +2 -2
- package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
- package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
- package/dist/{dev-client-CLnIH02x.mjs → dev-client-CDY_zAmD.mjs} +2 -2
- package/dist/{device-D7oCHGWi.mjs → device-BHw0WlHl.mjs} +8 -8
- package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-BoN1jQkO.mjs} +23 -12
- package/dist/device-host-worker.mjs +14 -14
- package/dist/{gradle-C6GKnunQ.mjs → device-ios-B2ruohE-.mjs} +659 -105
- package/dist/{device-lease-Co-EwifR.mjs → device-lease-Cu7PtQpZ.mjs} +5 -5
- package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
- package/dist/{device-pool-F5WvRPtD.mjs → device-pool-CP4rAsHx.mjs} +3 -3
- package/dist/{device-remote-tHbd1fKy.mjs → device-remote-B5GiUifk.mjs} +15 -16
- package/dist/{doctor-B9ckYUoU.mjs → doctor-PRJH94v6.mjs} +53 -29
- package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
- package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics--v5HGOU0.mjs} +10 -10
- package/dist/{exec-DWhCZDGm.mjs → exec-i8GDPwq9.mjs} +32 -8
- package/dist/{gc-Dh6mXOKC.mjs → gc-CyHMcKcn.mjs} +19 -19
- package/dist/{guide-tm6igAaa.mjs → guide-dRaQJJk9.mjs} +409 -472
- package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
- package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-C5G4h_OJ.mjs} +1 -1
- package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-Bik035eL.mjs} +1 -1
- package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-CI9Az9a4.mjs} +7 -7
- package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-DABm3ScO.mjs} +4 -4
- package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-DbV2aUVw.mjs} +12 -8
- package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DYiMBn34.mjs} +7 -7
- package/dist/{ios-B3SbOWdw.mjs → ios-BWbHFZVz.mjs} +5 -5
- package/dist/{ios-Bvbf0SGY.mjs → ios-DCrkgXEM.mjs} +1 -1
- package/dist/{ios-DNpdygiv.mjs → ios-DYUr9LGc.mjs} +7 -6
- package/dist/ios-ITYno9rO.mjs +2241 -0
- package/dist/{ios-device-vOaByMhw.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
- package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-CrW8aMb5.mjs} +1 -1
- package/dist/{ios-state-B2pES6Vs.mjs → ios-state-By0XuLTQ.mjs} +1 -1
- package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-DCveSE6d.mjs} +4 -4
- package/dist/{logs-1Ylc1Ri6.mjs → logs-Bao1HOMy.mjs} +10 -10
- package/dist/{macos-DF6C7wUU.mjs → macos-ciyBdTY5.mjs} +108 -130
- package/dist/macos-nIOATJmR.mjs +2 -0
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +7 -7
- package/dist/manifest-CX0d1IkZ.mjs +148 -0
- package/dist/{metro-Dh8T4Ytd.mjs → metro-DI2AjPF_.mjs} +194 -41
- package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BxpJLIwh.mjs} +2 -2
- package/dist/{plan-placement-CtxkCO54.mjs → miss-reason-CjQCOKqq.mjs} +180 -296
- package/dist/{named-ports-BFIz1Shz.mjs → named-ports-B4iWH4E-.mjs} +12 -5
- package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BGxsbfny.mjs} +6 -6
- package/dist/offload-worker.d.mts +1 -29
- package/dist/offload-worker.mjs +9 -8
- package/dist/{ownership-D6Se7gg_.mjs → ownership-EB0ySdGK.mjs} +2 -2
- package/dist/{placement-log-BcPhRwR4.mjs → placement-log-Dxe34rJm.mjs} +7 -3
- package/dist/plan-placement-BVY59qa8.mjs +290 -0
- package/dist/{ports-BLTtfBq-.mjs → ports-ByPc0_97.mjs} +3 -3
- package/dist/{prebuild-juCyreaR.mjs → prebuild-BKJ3wJI1.mjs} +4 -4
- package/dist/{preview-D5V07Nrl.mjs → preview-BbSottmO.mjs} +16 -17
- package/dist/project-B5eQ1USs.mjs +612 -0
- package/dist/{pull-request-u4vp7zmK.mjs → pull-request-IHNdMnG8.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/react-native-ios-BMh2i25I.mjs +2 -0
- package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
- package/dist/{recordings-BAWltsVt.mjs → recordings-Bv8McZN4.mjs} +1 -1
- package/dist/{reload-DvyWzVjJ.mjs → reload-rAPdqeRR.mjs} +13 -14
- package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-N3hAEaAL.mjs} +4 -4
- package/dist/{run-vhtDgpHO.mjs → run-lAkle1-c.mjs} +2 -2
- package/dist/{server-bare-B9E7S1aR.mjs → server-bare-CkIjnegq.mjs} +3 -3
- package/dist/server-expo-DGsdUGX2.mjs +2 -0
- package/dist/{server-expo-DoBHhuzK.mjs → server-expo-n3tUi3Em.mjs} +3 -3
- package/dist/{settings-Byp2AQ_E.mjs → settings-2am7TSxp.mjs} +5 -6
- package/dist/{settings-CQyMElEP.mjs → settings-CxgngUZk.mjs} +767 -15
- package/dist/settings.schema.json +72 -6
- package/dist/{simslim-EHBQ2R4G.mjs → simslim-D9LkJxIO.mjs} +5 -5
- package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
- package/dist/{stage-g_WqWeaE.mjs → stage-BgaZJVZY.mjs} +1 -1
- package/dist/{start-NTc1Ifqs.mjs → start-D8NbxNBb.mjs} +1 -1
- package/dist/{start-D-IeOyoK.mjs → start-DtxthMfI.mjs} +29 -22
- package/dist/{state-BG-aAk4k.mjs → state-D2KtnALG.mjs} +2 -2
- package/dist/{state-xnqpx3AD.mjs → state-Tp4uImDS.mjs} +4 -2
- package/dist/{stats-DY6ekz8F.mjs → stats-8EJ5ivFT.mjs} +6 -6
- package/dist/{status-DCjZeE-K.mjs → status-BOyp0CUl.mjs} +25 -27
- package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
- package/dist/{stim-installations-aR_WsNOA.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
- package/dist/stop-D0UIpZuh.mjs +72 -0
- package/dist/{stop-DIJtD2GL.mjs → stop-DRipAg-e.mjs} +2 -2
- package/dist/{stop-BTjs3xbc.mjs → stop-zDlknFoz.mjs} +78 -31
- package/dist/supervisor-run.mjs +14 -14
- package/dist/{support-BaayeYCf.mjs → support-CNqYkV0y.mjs} +7 -7
- package/dist/{support-Bwvbrq5-.mjs → support-DsNaFg6D.mjs} +5 -5
- package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
- package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-C3xSoyUl.mjs} +27 -270
- package/dist/{trigger-CJMhwXe8.mjs → trigger-CAhmG-4s.mjs} +3 -3
- package/dist/trigger-CoalsMTV.mjs +2 -0
- package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-pFLB2e6P.mjs} +133 -36
- package/dist/{status-Dcr0Qexd.mjs → watchman-BL1IdOtq.mjs} +75 -7
- package/dist/web-DFpFeZu5.mjs +2 -0
- package/dist/web-DbbrPUn0.mjs +127 -0
- package/dist/web-run.mjs +7 -7
- package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CR9X86xJ.mjs} +1 -1
- package/dist/{workspaces-xXItD8Dj.mjs → workspaces-Djb2gfi9.mjs} +102 -18
- package/dist/{worktree-BSYlofkq.mjs → worktree-BL4M1rhB.mjs} +45 -42
- package/dist/{worktree-BJfnU6r5.mjs → worktree-DV-A0LNL.mjs} +1 -1
- package/package.json +5 -5
- package/shim/bundle-response.cjs +2 -1
- package/shim/bundle-response.d.cts +1 -1
- package/shim/expo-metro-config.cjs +1 -1
- package/dist/device-ios-6MewKKnc.mjs +0 -412
- package/dist/guide-status-Bhf9SJXc.mjs +0 -125
- package/dist/ios-CPdkoKaa.mjs +0 -3953
- package/dist/macos-Ck7OBMNY.mjs +0 -2
- package/dist/native-run-B06FkmZx.mjs +0 -158
- package/dist/project-C3ChRLZy.mjs +0 -212
- package/dist/projects-DD7dBTCj.mjs +0 -92
- package/dist/server-expo-Db9HBUoa.mjs +0 -2
- package/dist/stop-BGhKMOuH.mjs +0 -48
- package/dist/trigger-DWAq9hkw.mjs +0 -2
- package/dist/web-B6_bFDn7.mjs +0 -2
- package/dist/worktree-CsKYexJM.mjs +0 -753
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as ownership_claim_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
|
|
2
3
|
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
3
|
-
import { l as phaseLine } from "./command-output-
|
|
4
|
+
import { l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
|
|
5
|
+
import { C as saveConfig, D as withConfigLock, H as projectDeviceSlots, _ as loadConfig, a as clearDevice, d as getConfigDir, w as setDevice, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
|
|
6
|
+
import { p as sharedCompilationCache, y as workspaceId } from "./workspace-state-CR9X86xJ.mjs";
|
|
7
|
+
import { v as resolvePackageJson } from "./project-B5eQ1USs.mjs";
|
|
8
|
+
import { Ot as resolveOptimizations, v as iosSimSlimProfileSetting } from "./settings-CxgngUZk.mjs";
|
|
9
|
+
import { r as register } from "./cache-manifest-DiwKSyv9.mjs";
|
|
10
|
+
import { j as teardownParkedIosSim } from "./workspaces-Djb2gfi9.mjs";
|
|
4
11
|
import { a as spawnDeclared } from "./spawn-claims-Kqiifsk2.mjs";
|
|
5
|
-
import { o as androidHome } from "./android-
|
|
6
|
-
import {
|
|
12
|
+
import { ct as dropParked, ft as parkedMaxSetting, ht as selectParked, o as androidHome, pt as readParked, st as adoptParked } from "./android-BdQC6zs1.mjs";
|
|
13
|
+
import { C as resetIosPrivacy, M as readHostMemoryPressure, S as resetIosKeychain, T as resolveOwnedIosSim, a as createOwnedIosSim, d as listAllIosSims, g as ownedSimName, j as hostMemoryPressureAdvice, k as configuredIosSimulatorViewer, m as listIosRuntimes, n as bootIosSim, p as listIosDeviceTypes, u as iosSimulatorFailureAdvice, v as parseRuntimeVersion, w as resolveIosCreation, x as renameIosSim } from "./ios-BWbHFZVz.mjs";
|
|
14
|
+
import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
|
|
15
|
+
import { a as deviceTypeMismatch, c as runtimeMismatch, n as DeviceAdmissionRefusal, p as withDeviceBootAdmission } from "./device-capacity-BoN1jQkO.mjs";
|
|
16
|
+
import { o as readCcacheActivity, r as CCACHE_UNAVAILABLE } from "./manifest-CX0d1IkZ.mjs";
|
|
17
|
+
import { D as swiftPrefixMappingSupported, E as startBuildHeartbeat, S as pickXcodeProject, _ as buildXcode, b as detectSwiftVersion, g as SWIFT_PREFIX_MAPPING_MIN_SWIFT, h as HEARTBEAT_INTERVAL_MS, x as detectXcodeMajor, y as compilationCacheSettings } from "./toolchain-C3xSoyUl.mjs";
|
|
7
18
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
8
19
|
import { dirname, isAbsolute, join, relative, sep } from "node:path";
|
|
9
20
|
import { fileURLToPath } from "node:url";
|
|
@@ -290,44 +301,12 @@ function assembleTaskFor(variant) {
|
|
|
290
301
|
}
|
|
291
302
|
const LAST_LINES = 20;
|
|
292
303
|
const TRANSCRIPT_LINES = 2e3;
|
|
293
|
-
function
|
|
294
|
-
return join(root, "android");
|
|
295
|
-
}
|
|
296
|
-
function gradlewPath(root) {
|
|
297
|
-
return join(androidDir(root), process.platform === "win32" ? "gradlew.bat" : "gradlew");
|
|
298
|
-
}
|
|
299
|
-
function apkOutputsDir(root) {
|
|
300
|
-
return join(androidDir(root), "app", "build", "outputs", "apk");
|
|
301
|
-
}
|
|
302
|
-
function debugApkDir(root) {
|
|
303
|
-
return join(apkOutputsDir(root), "debug");
|
|
304
|
-
}
|
|
305
|
-
function discoverAndroidProject(root) {
|
|
306
|
-
const dir = androidDir(root);
|
|
307
|
-
if (!existsSync(dir)) return {
|
|
308
|
-
failed: true,
|
|
309
|
-
code: BUILD_ERROR,
|
|
310
|
-
reason: `No android/ directory in ${root}.`,
|
|
311
|
-
remedy: "Generate it (`npx expo prebuild -p android`, which `stim android` runs itself on an Expo project) or check out the native sources."
|
|
312
|
-
};
|
|
313
|
-
const gradlew = gradlewPath(root);
|
|
314
|
-
if (!existsSync(gradlew)) return {
|
|
315
|
-
failed: true,
|
|
316
|
-
code: BUILD_ERROR,
|
|
317
|
-
reason: `${gradlew} does not exist, so there is no gradle wrapper to build with.`,
|
|
318
|
-
remedy: "Restore the wrapper (`gradle wrapper` in android/, or regenerate the project with `npx expo prebuild -p android --clean`)."
|
|
319
|
-
};
|
|
320
|
-
return {
|
|
321
|
-
androidDir: dir,
|
|
322
|
-
gradlew
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
function androidSdkRefusal({ sdkPath, sdkExists, hasLocalProperties }) {
|
|
304
|
+
function androidSdkRefusal({ sdkPath, sdkExists, hasLocalProperties, localPropertiesPath }) {
|
|
326
305
|
if (sdkExists || hasLocalProperties) return null;
|
|
327
306
|
return {
|
|
328
307
|
code: BUILD_ERROR,
|
|
329
308
|
reason: `No Android SDK at ${sdkPath}.`,
|
|
330
|
-
remedy:
|
|
309
|
+
remedy: `Set ANDROID_HOME to the Android SDK (Android Studio installs it at ~/Library/Android/sdk), or write sdk.dir into ${localPropertiesPath}. JAVA_HOME must point at a JDK 17 install as well.`
|
|
331
310
|
};
|
|
332
311
|
}
|
|
333
312
|
function pickDebugApk(files) {
|
|
@@ -363,7 +342,7 @@ function variantNameOf(segments) {
|
|
|
363
342
|
return (Array.isArray(segments) ? segments : []).filter((s) => typeof s === "string" && s.trim()).map((s, i) => i === 0 ? s : `${s[0].toUpperCase()}${s.slice(1)}`).join("");
|
|
364
343
|
}
|
|
365
344
|
function apkInDir(dir) {
|
|
366
|
-
const metadata = readOrNull(join(dir, "output-metadata.json"));
|
|
345
|
+
const metadata = readOrNull$1(join(dir, "output-metadata.json"));
|
|
367
346
|
if (metadata) {
|
|
368
347
|
const named = parseOutputMetadata(metadata);
|
|
369
348
|
if (named) {
|
|
@@ -392,8 +371,7 @@ function listApkSubdirs(base, prefix = [], depth = 0) {
|
|
|
392
371
|
}
|
|
393
372
|
return dirs;
|
|
394
373
|
}
|
|
395
|
-
function findVariantApkDir(
|
|
396
|
-
const base = apkOutputsDir(root);
|
|
374
|
+
function findVariantApkDir(base, variant) {
|
|
397
375
|
const wanted = variant.trim().toLowerCase();
|
|
398
376
|
for (const segments of listApkSubdirs(base)) if (variantNameOf(segments).toLowerCase() === wanted) return join(base, ...segments);
|
|
399
377
|
return null;
|
|
@@ -410,25 +388,25 @@ function findDebugApksUnder(base) {
|
|
|
410
388
|
}
|
|
411
389
|
return found.toSorted();
|
|
412
390
|
}
|
|
413
|
-
function locateApk(
|
|
391
|
+
function locateApk(project, transcript = "", variant = null) {
|
|
414
392
|
const fromTranscript = parseApkFromTranscript(transcript);
|
|
415
393
|
if (fromTranscript) {
|
|
416
|
-
const abs = isAbsolute(fromTranscript) ? fromTranscript : join(
|
|
394
|
+
const abs = isAbsolute(fromTranscript) ? fromTranscript : join(project.directory, fromTranscript);
|
|
417
395
|
if (existsSync(abs)) return { apkPath: abs };
|
|
418
396
|
}
|
|
419
397
|
if (variant) {
|
|
420
|
-
const dir = findVariantApkDir(
|
|
398
|
+
const dir = findVariantApkDir(project.outputsDir, variant);
|
|
421
399
|
return { apkPath: dir ? apkInDir(dir) : null };
|
|
422
400
|
}
|
|
423
|
-
const direct = apkInDir(
|
|
401
|
+
const direct = apkInDir(join(project.outputsDir, "debug"));
|
|
424
402
|
if (direct) return { apkPath: direct };
|
|
425
|
-
const found = findDebugApksUnder(
|
|
403
|
+
const found = findDebugApksUnder(project.outputsDir);
|
|
426
404
|
if (found.length === 1) {
|
|
427
405
|
const apk = found[0];
|
|
428
|
-
const suggested = variantNameOf(relative(
|
|
406
|
+
const suggested = variantNameOf(relative(project.outputsDir, apk).split(sep).slice(0, -1));
|
|
429
407
|
return {
|
|
430
408
|
apkPath: apk,
|
|
431
|
-
note: `no APK in ${relative(
|
|
409
|
+
note: `no APK in ${relative(project.directory, join(project.outputsDir, "debug"))}; using ${relative(project.directory, apk)}${suggested ? ` -- set the android.variant setting to "${suggested}" to build this variant explicitly` : ""}`
|
|
432
410
|
};
|
|
433
411
|
}
|
|
434
412
|
if (found.length > 1) return {
|
|
@@ -585,48 +563,21 @@ function parseProductFlavors(source) {
|
|
|
585
563
|
dimensions
|
|
586
564
|
};
|
|
587
565
|
}
|
|
588
|
-
function
|
|
589
|
-
return parseProductFlavors(readOrNull(join(androidDir(root), "app", "build.gradle")));
|
|
590
|
-
}
|
|
591
|
-
function productFlavorRefusal({ flavors, variant }) {
|
|
592
|
-
if (variant) return null;
|
|
593
|
-
if (!flavors.known || flavors.dimensions.length === 0) return null;
|
|
594
|
-
let combinations = [[]];
|
|
595
|
-
for (const group of flavors.dimensions) combinations = combinations.flatMap((combination) => group.map((flavor) => combination.concat(flavor)));
|
|
596
|
-
if (combinations.length < 2) return null;
|
|
597
|
-
const count = flavors.dimensions.reduce((total, group) => total + group.length, 0);
|
|
598
|
-
const variants = combinations.map((combination) => variantNameOf(combination.concat("debug")));
|
|
599
|
-
return {
|
|
600
|
-
code: "STIM_BAD_ARG",
|
|
601
|
-
reason: `android/app/build.gradle declares ${count} product flavors, so \`./gradlew ${ASSEMBLE_TASK}\` builds an APK for each of them and nothing says which flavor to install.`,
|
|
602
|
-
remedy: `Pass \`--variant ${variants[0]}\` or set the android.variant setting -- e.g. {"android": {"variant": "${variants[0]}"}} in .stim.json. The debug variants are: ${variants.join(", ")}.`
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
function gradleArgs(task, { buildCache = true, abi = null } = {}) {
|
|
566
|
+
function gradleArgs(task, { buildCache = true, projectArgs = [] } = {}) {
|
|
606
567
|
return [
|
|
607
568
|
task,
|
|
608
569
|
...buildCache ? ["--build-cache"] : ["--no-build-cache"],
|
|
609
|
-
...
|
|
570
|
+
...projectArgs
|
|
610
571
|
];
|
|
611
572
|
}
|
|
612
|
-
async function
|
|
613
|
-
const project = discoverAndroidProject(root);
|
|
614
|
-
if (project.failed) return {
|
|
615
|
-
ok: false,
|
|
616
|
-
code: project.code,
|
|
617
|
-
reason: project.reason,
|
|
618
|
-
remedy: project.remedy,
|
|
619
|
-
diagnostics: [],
|
|
620
|
-
truncated: 0,
|
|
621
|
-
lastLines: [],
|
|
622
|
-
durationMs: 0
|
|
623
|
-
};
|
|
573
|
+
async function buildGradle({ root, logWriter, variant = null, project, task, projectArgs = [], preflightFailure = null }, { spawnFn = null, now = Date.now, env = process.env, buildCache = true, ccache = null, cas = null, pch = "auto", compilerCacheDisabled = false, heartbeatMs = HEARTBEAT_INTERVAL_MS, estimateMs = null, onHeartbeat = (line) => console.error(line), onNote = (line) => console.error(line) } = {}) {
|
|
624
574
|
const sdk = androidHome(env);
|
|
625
575
|
const sdkExists = existsSync(sdk);
|
|
626
576
|
const refusal = androidSdkRefusal({
|
|
627
577
|
sdkPath: sdk,
|
|
628
578
|
sdkExists,
|
|
629
|
-
hasLocalProperties: existsSync(join(project.
|
|
579
|
+
hasLocalProperties: existsSync(join(project.directory, "local.properties")),
|
|
580
|
+
localPropertiesPath: relative(root, join(project.directory, "local.properties")).split(sep).join("/")
|
|
630
581
|
});
|
|
631
582
|
if (refusal) return {
|
|
632
583
|
ok: false,
|
|
@@ -636,26 +587,21 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
636
587
|
lastLines: [],
|
|
637
588
|
durationMs: 0
|
|
638
589
|
};
|
|
639
|
-
|
|
640
|
-
abi,
|
|
641
|
-
variant,
|
|
642
|
-
platform
|
|
643
|
-
});
|
|
644
|
-
if (room) return {
|
|
590
|
+
if (preflightFailure) return {
|
|
645
591
|
ok: false,
|
|
646
|
-
|
|
647
|
-
reason: androidPathRoomMessage(room),
|
|
648
|
-
remedy: androidPathRoomRemedy(room),
|
|
592
|
+
...preflightFailure,
|
|
649
593
|
diagnostics: [],
|
|
650
594
|
truncated: 0,
|
|
651
595
|
lastLines: [],
|
|
652
596
|
durationMs: 0
|
|
653
597
|
};
|
|
598
|
+
const wrapper = `./${relative(project.directory, project.gradlew).split(sep).join("/")}`;
|
|
599
|
+
const moduleTask = task.includes(":") ? task : `${project.module === ":" ? "" : project.module}:${task}`;
|
|
600
|
+
const tasksTask = `${project.module === ":" ? "" : project.module}:tasks`;
|
|
654
601
|
const spawn = spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts));
|
|
655
|
-
const task = assembleTaskFor(variant);
|
|
656
602
|
const args = gradleArgs(task, {
|
|
657
603
|
buildCache,
|
|
658
|
-
|
|
604
|
+
projectArgs
|
|
659
605
|
});
|
|
660
606
|
if (cas) {
|
|
661
607
|
args.push("--init-script", cas.initScript);
|
|
@@ -709,7 +655,7 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
709
655
|
let child;
|
|
710
656
|
try {
|
|
711
657
|
child = spawnDeclared(() => spawn(project.gradlew, args, {
|
|
712
|
-
cwd: project.
|
|
658
|
+
cwd: project.directory,
|
|
713
659
|
stdio: [
|
|
714
660
|
"ignore",
|
|
715
661
|
"pipe",
|
|
@@ -726,7 +672,7 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
726
672
|
}
|
|
727
673
|
}));
|
|
728
674
|
} catch (err) {
|
|
729
|
-
return spawnFailure(err, project, now() - startedAt);
|
|
675
|
+
return spawnFailure(err, root, project, now() - startedAt);
|
|
730
676
|
}
|
|
731
677
|
const outReader = createLineReader(push);
|
|
732
678
|
const errReader = createLineReader(push);
|
|
@@ -748,7 +694,7 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
748
694
|
const transcript = window.join("\n");
|
|
749
695
|
const ccacheActivity = ccache ? readCcacheActivity(ccache.statsLog) : CCACHE_UNAVAILABLE;
|
|
750
696
|
if (result.error) return {
|
|
751
|
-
...spawnFailure(result.error, project, durationMs),
|
|
697
|
+
...spawnFailure(result.error, root, project, durationMs),
|
|
752
698
|
lastLines: tail.slice(),
|
|
753
699
|
ccache: ccacheActivity
|
|
754
700
|
};
|
|
@@ -758,7 +704,7 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
758
704
|
return {
|
|
759
705
|
ok: false,
|
|
760
706
|
code: BUILD_ERROR,
|
|
761
|
-
reason:
|
|
707
|
+
reason: `\`${wrapper} ${task}\` failed (${how}).`,
|
|
762
708
|
diagnostics: shown,
|
|
763
709
|
truncated,
|
|
764
710
|
lastLines: tail.slice(),
|
|
@@ -766,23 +712,23 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
|
|
|
766
712
|
ccache: ccacheActivity
|
|
767
713
|
};
|
|
768
714
|
}
|
|
769
|
-
const located = locateApk(
|
|
715
|
+
const located = locateApk(project, transcript, variant);
|
|
770
716
|
if (!located.apkPath && located.candidates?.length) return {
|
|
771
717
|
ok: false,
|
|
772
718
|
code: BUILD_ERROR,
|
|
773
|
-
reason:
|
|
774
|
-
remedy: `Set the android.variant setting to the variant to install -- e.g. {"android": {"variant": "${variantNameOf(relative(
|
|
719
|
+
reason: `\`${wrapper} ${task}\` left ${located.candidates.length} debug APKs under ${project.outputsDir}, and nothing says which flavor to install.`,
|
|
720
|
+
remedy: `Set the android.variant setting to the variant to install -- e.g. {"android": {"variant": "${variantNameOf(relative(project.outputsDir, located.candidates[0]).split(sep).slice(0, -1))}"}} in .stim.json.`,
|
|
775
721
|
diagnostics: [],
|
|
776
722
|
truncated: 0,
|
|
777
|
-
lastLines: located.candidates.map((c) => relative(
|
|
723
|
+
lastLines: located.candidates.map((c) => relative(project.directory, c)),
|
|
778
724
|
durationMs,
|
|
779
725
|
ccache: ccacheActivity
|
|
780
726
|
};
|
|
781
727
|
if (!located.apkPath) return {
|
|
782
728
|
ok: false,
|
|
783
729
|
code: BUILD_ERROR,
|
|
784
|
-
reason: variant ?
|
|
785
|
-
remedy: variant ? `Check that the android.variant setting ("${variant}") names a real variant (
|
|
730
|
+
reason: variant ? `\`${wrapper} ${task}\` succeeded but produced no APK under ${project.outputsDir} for variant "${variant}".` : `\`${wrapper} ${task}\` succeeded but produced no APK in ${join(project.outputsDir, "debug")}.`,
|
|
731
|
+
remedy: variant ? `Check that the android.variant setting ("${variant}") names a real variant (\`${wrapper} ${tasksTask}\` lists the assemble tasks).` : `Check that ${task} builds the ${project.module.replace(/^:/, "") || "root"} module (\`${wrapper} ${moduleTask}\` in ${relative(root, project.directory).split(sep).join("/") || "."}/) and that no flavour redirects the output.`,
|
|
786
732
|
diagnostics: [],
|
|
787
733
|
truncated: 0,
|
|
788
734
|
lastLines: tail.slice(),
|
|
@@ -804,7 +750,7 @@ function resetStatsLog(statsLog) {
|
|
|
804
750
|
rmSync(statsLog, { force: true });
|
|
805
751
|
} catch {}
|
|
806
752
|
}
|
|
807
|
-
function spawnFailure(err, project, durationMs) {
|
|
753
|
+
function spawnFailure(err, root, project, durationMs) {
|
|
808
754
|
const nodeErr = err;
|
|
809
755
|
const message = String(nodeErr?.message || err || "");
|
|
810
756
|
const permissionDenied = nodeErr?.code === "EACCES" || /EACCES|permission denied/i.test(message);
|
|
@@ -812,7 +758,7 @@ function spawnFailure(err, project, durationMs) {
|
|
|
812
758
|
ok: false,
|
|
813
759
|
code: BUILD_ERROR,
|
|
814
760
|
reason: `Could not run ${project.gradlew}: ${message}`,
|
|
815
|
-
remedy: permissionDenied ? `Make the wrapper executable: \`chmod +x ${project.gradlew}\`.` :
|
|
761
|
+
remedy: permissionDenied ? `Make the wrapper executable: \`chmod +x ${project.gradlew}\`.` : `Check that the gradle wrapper is intact (${relative(root, project.gradlew)} and ${relative(root, join(project.directory, "gradle", "wrapper"))}/) and that JAVA_HOME points at a JDK 17 install.`,
|
|
816
762
|
diagnostics: [],
|
|
817
763
|
truncated: 0,
|
|
818
764
|
lastLines: [],
|
|
@@ -830,7 +776,7 @@ function safeList(dir) {
|
|
|
830
776
|
return [];
|
|
831
777
|
}
|
|
832
778
|
}
|
|
833
|
-
function readOrNull(file) {
|
|
779
|
+
function readOrNull$1(file) {
|
|
834
780
|
try {
|
|
835
781
|
return readFileSync(file, "utf-8");
|
|
836
782
|
} catch {
|
|
@@ -838,4 +784,612 @@ function readOrNull(file) {
|
|
|
838
784
|
}
|
|
839
785
|
}
|
|
840
786
|
//#endregion
|
|
841
|
-
|
|
787
|
+
//#region src/integrations/react-native-build.ts
|
|
788
|
+
function androidDir(root) {
|
|
789
|
+
return join(root, "android");
|
|
790
|
+
}
|
|
791
|
+
function gradlewPath(root) {
|
|
792
|
+
return join(androidDir(root), process.platform === "win32" ? "gradlew.bat" : "gradlew");
|
|
793
|
+
}
|
|
794
|
+
function apkOutputsDir(root) {
|
|
795
|
+
return join(androidDir(root), "app", "build", "outputs", "apk");
|
|
796
|
+
}
|
|
797
|
+
function discoverAndroidProject(root) {
|
|
798
|
+
const dir = androidDir(root);
|
|
799
|
+
if (!existsSync(dir)) return {
|
|
800
|
+
failed: true,
|
|
801
|
+
code: BUILD_ERROR,
|
|
802
|
+
reason: `No android/ directory in ${root}.`,
|
|
803
|
+
remedy: "Generate it (`npx expo prebuild -p android`, which `stim android` runs itself on an Expo project) or check out the native sources."
|
|
804
|
+
};
|
|
805
|
+
const gradlew = gradlewPath(root);
|
|
806
|
+
if (!existsSync(gradlew)) return {
|
|
807
|
+
failed: true,
|
|
808
|
+
code: BUILD_ERROR,
|
|
809
|
+
reason: `${gradlew} does not exist, so there is no gradle wrapper to build with.`,
|
|
810
|
+
remedy: "Restore the wrapper (`gradle wrapper` in android/, or regenerate the project with `npx expo prebuild -p android --clean`)."
|
|
811
|
+
};
|
|
812
|
+
return {
|
|
813
|
+
androidDir: dir,
|
|
814
|
+
gradlew
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function readProductFlavors(root) {
|
|
818
|
+
return parseProductFlavors(readOrNull(join(androidDir(root), "app", "build.gradle")));
|
|
819
|
+
}
|
|
820
|
+
function productFlavorRefusal({ flavors, variant }) {
|
|
821
|
+
if (variant) return null;
|
|
822
|
+
if (!flavors.known || flavors.dimensions.length === 0) return null;
|
|
823
|
+
let combinations = [[]];
|
|
824
|
+
for (const group of flavors.dimensions) combinations = combinations.flatMap((combination) => group.map((flavor) => combination.concat(flavor)));
|
|
825
|
+
if (combinations.length < 2) return null;
|
|
826
|
+
const count = flavors.dimensions.reduce((total, group) => total + group.length, 0);
|
|
827
|
+
const variants = combinations.map((combination) => variantNameOf(combination.concat("debug")));
|
|
828
|
+
return {
|
|
829
|
+
code: "STIM_BAD_ARG",
|
|
830
|
+
reason: `android/app/build.gradle declares ${count} product flavors, so \`./gradlew ${ASSEMBLE_TASK}\` builds an APK for each of them and nothing says which flavor to install.`,
|
|
831
|
+
remedy: `Pass \`--variant ${variants[0]}\` or set the android.variant setting -- e.g. {"android": {"variant": "${variants[0]}"}} in .stim.json. The debug variants are: ${variants.join(", ")}.`
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function readOrNull(path) {
|
|
835
|
+
try {
|
|
836
|
+
return readFileSync(path, "utf-8");
|
|
837
|
+
} catch {
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
async function buildAndroid({ root, logWriter, variant = null, abi = null }, options = {}) {
|
|
842
|
+
const project = discoverAndroidProject(root);
|
|
843
|
+
if (project.failed) return {
|
|
844
|
+
ok: false,
|
|
845
|
+
code: project.code,
|
|
846
|
+
reason: project.reason,
|
|
847
|
+
remedy: project.remedy,
|
|
848
|
+
diagnostics: [],
|
|
849
|
+
truncated: 0,
|
|
850
|
+
lastLines: [],
|
|
851
|
+
durationMs: 0
|
|
852
|
+
};
|
|
853
|
+
const room = androidPathRoom(root, {
|
|
854
|
+
abi,
|
|
855
|
+
variant,
|
|
856
|
+
platform: options.platform ?? process.platform
|
|
857
|
+
});
|
|
858
|
+
return buildGradle({
|
|
859
|
+
root,
|
|
860
|
+
logWriter,
|
|
861
|
+
variant,
|
|
862
|
+
project: {
|
|
863
|
+
directory: project.androidDir,
|
|
864
|
+
gradlew: project.gradlew,
|
|
865
|
+
module: ":app",
|
|
866
|
+
outputsDir: apkOutputsDir(root)
|
|
867
|
+
},
|
|
868
|
+
task: assembleTaskFor(variant),
|
|
869
|
+
projectArgs: abi ? [`-PreactNativeArchitectures=${abi}`] : [],
|
|
870
|
+
preflightFailure: room ? {
|
|
871
|
+
code: "STIM_PATH_TOO_LONG",
|
|
872
|
+
reason: androidPathRoomMessage(room),
|
|
873
|
+
remedy: androidPathRoomRemedy(room)
|
|
874
|
+
} : null
|
|
875
|
+
}, options);
|
|
876
|
+
}
|
|
877
|
+
const IOS_DIR = "ios";
|
|
878
|
+
const PREBUILD_REMEDY = "Generate it with `npx expo prebuild -p ios` (stim ios does this automatically for an Expo project with no ios/ directory), or commit the native project.";
|
|
879
|
+
function buildFailure(message, remedy) {
|
|
880
|
+
return { error: {
|
|
881
|
+
code: "STIM_BUILD_FAILED",
|
|
882
|
+
message,
|
|
883
|
+
remedy
|
|
884
|
+
} };
|
|
885
|
+
}
|
|
886
|
+
function discoverXcodeProject(root) {
|
|
887
|
+
const dir = join(root, IOS_DIR);
|
|
888
|
+
let entries;
|
|
889
|
+
try {
|
|
890
|
+
entries = readdirSync(dir);
|
|
891
|
+
} catch {
|
|
892
|
+
return buildFailure(`No ${IOS_DIR}/ directory in ${root}.`, PREBUILD_REMEDY);
|
|
893
|
+
}
|
|
894
|
+
const picked = pickXcodeProject(entries);
|
|
895
|
+
if (!picked) return buildFailure(`${dir} contains no .xcworkspace and no .xcodeproj.`, PREBUILD_REMEDY);
|
|
896
|
+
return {
|
|
897
|
+
...picked,
|
|
898
|
+
dir,
|
|
899
|
+
path: join(dir, picked.file)
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
function ccacheEnabled(podfileProperties) {
|
|
903
|
+
if (!podfileProperties || typeof podfileProperties !== "object") return false;
|
|
904
|
+
return podfileProperties["apple.ccacheEnabled"] === "true";
|
|
905
|
+
}
|
|
906
|
+
function readPodfileProperties(root) {
|
|
907
|
+
try {
|
|
908
|
+
const parsed = JSON.parse(readFileSync(join(root, IOS_DIR, "Podfile.properties.json"), "utf-8"));
|
|
909
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
910
|
+
} catch {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
const SWIFT_CACHE_MIN_REACT_NATIVE = {
|
|
915
|
+
major: 0,
|
|
916
|
+
minor: 87
|
|
917
|
+
};
|
|
918
|
+
function reactNativeSupportsSwiftCache(version) {
|
|
919
|
+
if (!version) return false;
|
|
920
|
+
const min = SWIFT_CACHE_MIN_REACT_NATIVE;
|
|
921
|
+
return version.major > min.major || version.major === min.major && version.minor >= min.minor;
|
|
922
|
+
}
|
|
923
|
+
function parseReactNativeVersion(packageJson) {
|
|
924
|
+
if (!packageJson || typeof packageJson !== "object") return null;
|
|
925
|
+
const raw = packageJson.version;
|
|
926
|
+
const m = typeof raw === "string" ? /^(\d+)\.(\d+)\./.exec(raw) : null;
|
|
927
|
+
if (!m || m[1] === void 0 || m[2] === void 0) return null;
|
|
928
|
+
return {
|
|
929
|
+
major: parseInt(m[1], 10),
|
|
930
|
+
minor: parseInt(m[2], 10)
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function detectReactNativeVersion(root) {
|
|
934
|
+
const file = resolvePackageJson(root, "react-native");
|
|
935
|
+
if (!file) return null;
|
|
936
|
+
try {
|
|
937
|
+
return parseReactNativeVersion(JSON.parse(readFileSync(file, "utf-8")));
|
|
938
|
+
} catch {
|
|
939
|
+
return null;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
function reactNativeCompilationCacheSettings({ reactNativeVersion = null, ...options }) {
|
|
943
|
+
return compilationCacheSettings({
|
|
944
|
+
...options,
|
|
945
|
+
swiftCacheCompatible: reactNativeSupportsSwiftCache(reactNativeVersion)
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
function resolveCompilationCacheSettings({ root, derivedDataPath, exec = null, casPath = sharedCompilationCache(), optimizations = resolveOptimizations({}, {}).ios, onNote = (line) => console.error(line) }) {
|
|
949
|
+
const xcodeMajor = detectXcodeMajor(exec);
|
|
950
|
+
const ccache = ccacheEnabled(readPodfileProperties(root));
|
|
951
|
+
const probe = xcodeMajor !== null && xcodeMajor >= 26 && !ccache && optimizations.compilationCache && optimizations.swiftCompilationCache !== false;
|
|
952
|
+
const swiftVersion = probe ? detectSwiftVersion(exec) : null;
|
|
953
|
+
const reactNativeVersion = probe ? detectReactNativeVersion(root) : null;
|
|
954
|
+
const settings = reactNativeCompilationCacheSettings({
|
|
955
|
+
workspaceRoot: root,
|
|
956
|
+
derivedDataPath,
|
|
957
|
+
casPath,
|
|
958
|
+
xcodeMajor,
|
|
959
|
+
swiftVersion,
|
|
960
|
+
reactNativeVersion,
|
|
961
|
+
ccache,
|
|
962
|
+
optimizations
|
|
963
|
+
});
|
|
964
|
+
if (settings.length > 0 && optimizations.compilationCache) {
|
|
965
|
+
register({
|
|
966
|
+
dir: casPath,
|
|
967
|
+
name: "Xcode compilation cache",
|
|
968
|
+
prune: "atomic",
|
|
969
|
+
note: "shared Xcode compilation cache"
|
|
970
|
+
});
|
|
971
|
+
const swift = settings.includes("SWIFT_ENABLE_COMPILE_CACHE=YES") ? settings.includes("SWIFT_ENABLE_PREFIX_MAPPING=YES") ? "Swift on" : "Swift on, unmapped" : swiftVersion && !swiftPrefixMappingSupported(swiftVersion) ? `Swift off, ${swiftVersion.major}.${swiftVersion.minor} < ${SWIFT_PREFIX_MAPPING_MIN_SWIFT.major}.${SWIFT_PREFIX_MAPPING_MIN_SWIFT.minor}` : swiftVersion && reactNativeVersion && !reactNativeSupportsSwiftCache(reactNativeVersion) ? `Swift off, react-native ${reactNativeVersion.major}.${reactNativeVersion.minor} < ${SWIFT_CACHE_MIN_REACT_NATIVE.major}.${SWIFT_CACHE_MIN_REACT_NATIVE.minor}` : "Swift off";
|
|
972
|
+
onNote(chalk.dim(phaseLine("cache", `compilation cache on (CAS at ${casPath}, ${swift})`)));
|
|
973
|
+
}
|
|
974
|
+
return settings;
|
|
975
|
+
}
|
|
976
|
+
async function buildIos(inputs) {
|
|
977
|
+
const { root, logWriter, udid, destination, now = () => Date.now() } = inputs;
|
|
978
|
+
if (!root || typeof root !== "string") throw new TypeError("buildIos requires {root}");
|
|
979
|
+
if (!logWriter || typeof logWriter.write !== "function") throw new TypeError("buildIos requires {logWriter} with a write() method");
|
|
980
|
+
if (!udid && !destination) throw new TypeError("buildIos requires {udid} (or an explicit {destination})");
|
|
981
|
+
const startedAt = now();
|
|
982
|
+
return buildXcode({
|
|
983
|
+
...inputs,
|
|
984
|
+
startedAt,
|
|
985
|
+
project: inputs.project ?? discoverXcodeProject(root),
|
|
986
|
+
compilationCache: inputs.compilationCache === void 0 ? ({ derivedDataPath, exec }) => resolveCompilationCacheSettings({
|
|
987
|
+
root,
|
|
988
|
+
derivedDataPath,
|
|
989
|
+
exec,
|
|
990
|
+
optimizations: inputs.optimizations,
|
|
991
|
+
onNote: inputs.onNote
|
|
992
|
+
}) : inputs.compilationCache
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
//#endregion
|
|
996
|
+
//#region src/engine/device-ios.ts
|
|
997
|
+
function startIosBoot(udid, configure, label, out, simulatorApp, root, deviceSlotWait) {
|
|
998
|
+
const done = withDeviceBootAdmission({
|
|
999
|
+
platform: "ios",
|
|
1000
|
+
key: udid
|
|
1001
|
+
}, async () => {
|
|
1002
|
+
out(chalk.dim(phaseLine("device", `booting ${label} (${udid})`)));
|
|
1003
|
+
await bootIosSim(udid, {
|
|
1004
|
+
label,
|
|
1005
|
+
out,
|
|
1006
|
+
simulatorApp
|
|
1007
|
+
});
|
|
1008
|
+
await configure();
|
|
1009
|
+
}, {
|
|
1010
|
+
...deviceSlotWait,
|
|
1011
|
+
root,
|
|
1012
|
+
out
|
|
1013
|
+
});
|
|
1014
|
+
done.catch(() => {});
|
|
1015
|
+
return {
|
|
1016
|
+
udid,
|
|
1017
|
+
done
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
var IosDeviceMismatchError = class extends Error {
|
|
1021
|
+
remedy = "Run `stim worktree remove` (or `stim gc --delete`) to reap the current sim, then `stim ios` again to create the requested one, or pass `--slot <name>` to create it beside the current one.";
|
|
1022
|
+
};
|
|
1023
|
+
async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, label, settings, flags, note, out, reconcileIosSimulator, simSnapshot }) {
|
|
1024
|
+
const memoryAdvice = hostMemoryPressureAdvice(readHostMemoryPressure());
|
|
1025
|
+
if (memoryAdvice) out(chalk.yellow(phaseLine("memory", memoryAdvice)));
|
|
1026
|
+
const simslimProfile = iosSimSlimProfileSetting(settings, settingsRoot);
|
|
1027
|
+
if (record?.deviceUdid) {
|
|
1028
|
+
if (record.owned) {
|
|
1029
|
+
const listed = simSnapshot ? simSnapshot.read() : listAllIosSims({ includeUnavailable: true });
|
|
1030
|
+
const resolved = resolveOwnedIosSim(record.deviceUdid, listed);
|
|
1031
|
+
if (resolved.notOwned) note(chalk.yellow(`Note: recorded sim is now named "${resolved.notOwned}", not Stim-owned -- creating a fresh owned sim instead of booting it.`));
|
|
1032
|
+
else if (resolved.missing) {} else {
|
|
1033
|
+
const sim = resolved.sim;
|
|
1034
|
+
const wantedType = flags.deviceType || settings?.ios?.deviceType;
|
|
1035
|
+
const deviceTypes = listIosDeviceTypes();
|
|
1036
|
+
const mismatch = deviceTypeMismatch(sim.deviceTypeIdentifier, wantedType, deviceTypes);
|
|
1037
|
+
if (mismatch) throw new IosDeviceMismatchError(`${mismatch}. Stim will not silently boot a different model.`);
|
|
1038
|
+
const versionMismatch = flags.runtimeFlag ? runtimeMismatch(sim.runtime, flags.runtimeFlag, listIosRuntimes()) : null;
|
|
1039
|
+
if (versionMismatch) throw new IosDeviceMismatchError(`${versionMismatch}. Stim will not silently boot a different iOS version.`);
|
|
1040
|
+
const model = {
|
|
1041
|
+
model: deviceTypes.find((d) => d.identifier === sim.deviceTypeIdentifier)?.name ?? null,
|
|
1042
|
+
runtime: parseRuntimeVersion(sim.runtime)
|
|
1043
|
+
};
|
|
1044
|
+
const name = ownedIosName(sim, label, model, projectPath, listed) === sim.name ? sim.name : await withIosDeviceNameLock(() => renameToOwnedName(sim, label, model, projectPath));
|
|
1045
|
+
const updated = {
|
|
1046
|
+
deviceUdid: sim.udid,
|
|
1047
|
+
owned: true,
|
|
1048
|
+
deviceName: name,
|
|
1049
|
+
...record.simslimManaged ? { simslimManaged: true } : {},
|
|
1050
|
+
...record.adopted ? { adopted: true } : {},
|
|
1051
|
+
...record.adoptionPending ? { adoptionPending: true } : {},
|
|
1052
|
+
...record.parkedCacheKey ? { parkedCacheKey: record.parkedCacheKey } : {},
|
|
1053
|
+
...record.schemeApprovals ? { schemeApprovals: record.schemeApprovals } : {}
|
|
1054
|
+
};
|
|
1055
|
+
const configure = async () => {
|
|
1056
|
+
if (record.adoptionPending) resetAdoptedSim(sim.udid, out);
|
|
1057
|
+
return configureOwnedIosSim({
|
|
1058
|
+
record: updated,
|
|
1059
|
+
projectPath,
|
|
1060
|
+
slot,
|
|
1061
|
+
profile: simslimProfile,
|
|
1062
|
+
out,
|
|
1063
|
+
reconcileIosSimulator
|
|
1064
|
+
});
|
|
1065
|
+
};
|
|
1066
|
+
const facts = {
|
|
1067
|
+
deviceType: model.model,
|
|
1068
|
+
runtime: model.runtime
|
|
1069
|
+
};
|
|
1070
|
+
if (sim.state !== "Booted") return {
|
|
1071
|
+
...updated,
|
|
1072
|
+
booting: startIosBoot(sim.udid, configure, name, out, flags.simulatorApp, projectPath, flags.deviceSlotWait),
|
|
1073
|
+
...facts
|
|
1074
|
+
};
|
|
1075
|
+
return {
|
|
1076
|
+
...await configure(),
|
|
1077
|
+
...facts,
|
|
1078
|
+
booted: sim.udid
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
const sim = listAllIosSims().find((s) => s.udid === record.deviceUdid);
|
|
1083
|
+
if (sim) {
|
|
1084
|
+
if (sim.state !== "Booted") {
|
|
1085
|
+
note(chalk.yellow(`Note: assigned sim ${sim.name} (${sim.udid}) is shut down and is not owned by Stim, so it will not be booted automatically.`));
|
|
1086
|
+
note(chalk.dim("Boot it yourself, or run `stim gc --delete` to clear the assignment so Stim can create an owned sim."));
|
|
1087
|
+
}
|
|
1088
|
+
return record;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
withConfigLock(() => {
|
|
1092
|
+
const current = deviceSlotPlatforms(loadConfig()?.projects?.[projectPath], slot)?.ios;
|
|
1093
|
+
if (!current) return;
|
|
1094
|
+
if (current.deviceUdid !== record.deviceUdid || current.owned !== record.owned) throw new Error("The simulator assignment changed during recovery. Run `stim ios` again.");
|
|
1095
|
+
clearDevice(projectPath, "ios", slot);
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
const choice = resolveIosCreation({
|
|
1099
|
+
deviceType: flags.deviceType || settings.ios?.deviceType,
|
|
1100
|
+
runtime: flags.runtime || settings.ios?.runtime
|
|
1101
|
+
});
|
|
1102
|
+
const adopted = parkedMaxSetting("ios").max > 0 ? await withIosDeviceNameLock(() => takeParkedIosSim({
|
|
1103
|
+
projectPath,
|
|
1104
|
+
slot,
|
|
1105
|
+
label,
|
|
1106
|
+
choice,
|
|
1107
|
+
out
|
|
1108
|
+
})) : null;
|
|
1109
|
+
if (adopted) {
|
|
1110
|
+
const booting = startIosBoot(adopted.deviceUdid, async () => {
|
|
1111
|
+
resetAdoptedSim(adopted.deviceUdid, out);
|
|
1112
|
+
await configureOwnedIosSim({
|
|
1113
|
+
record: adopted,
|
|
1114
|
+
projectPath,
|
|
1115
|
+
slot,
|
|
1116
|
+
profile: simslimProfile,
|
|
1117
|
+
out,
|
|
1118
|
+
reconcileIosSimulator
|
|
1119
|
+
});
|
|
1120
|
+
}, adopted.deviceName, out, flags.simulatorApp, projectPath, flags.deviceSlotWait);
|
|
1121
|
+
return {
|
|
1122
|
+
...adopted,
|
|
1123
|
+
booting,
|
|
1124
|
+
deviceType: choice.deviceType,
|
|
1125
|
+
runtime: choice.runtime
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
const created = await withIosDeviceNameLock(() => {
|
|
1129
|
+
const suffix = ownedIosNameSuffix(label, {
|
|
1130
|
+
model: choice.deviceType,
|
|
1131
|
+
runtime: choice.runtime
|
|
1132
|
+
}, projectPath);
|
|
1133
|
+
const result = createOwnedIosSim(label, { suffix }, choice);
|
|
1134
|
+
setDevice(projectPath, "ios", {
|
|
1135
|
+
deviceUdid: result.udid,
|
|
1136
|
+
owned: true,
|
|
1137
|
+
deviceName: result.name
|
|
1138
|
+
}, slot);
|
|
1139
|
+
return result;
|
|
1140
|
+
});
|
|
1141
|
+
const newRecord = {
|
|
1142
|
+
deviceUdid: created.udid,
|
|
1143
|
+
owned: true,
|
|
1144
|
+
deviceName: created.name
|
|
1145
|
+
};
|
|
1146
|
+
const booting = startIosBoot(created.udid, () => configureOwnedIosSim({
|
|
1147
|
+
record: newRecord,
|
|
1148
|
+
projectPath,
|
|
1149
|
+
slot,
|
|
1150
|
+
profile: simslimProfile,
|
|
1151
|
+
out,
|
|
1152
|
+
reconcileIosSimulator
|
|
1153
|
+
}), created.name, out, flags.simulatorApp, projectPath, flags.deviceSlotWait);
|
|
1154
|
+
return {
|
|
1155
|
+
...newRecord,
|
|
1156
|
+
created: true,
|
|
1157
|
+
booting,
|
|
1158
|
+
deviceType: created.deviceType,
|
|
1159
|
+
runtime: created.runtime
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
function withIosDeviceNameLock(fn) {
|
|
1163
|
+
return withWorkspaceProcessLock(getConfigDir(), "ios-device-names", async () => fn(), { external: true });
|
|
1164
|
+
}
|
|
1165
|
+
function ownedIosNameSuffix(label, model, projectPath, udid, listed = listAllIosSims({ includeUnavailable: true })) {
|
|
1166
|
+
const names = new Set(listed.filter((sim) => sim.udid !== udid).map((sim) => sim.name));
|
|
1167
|
+
for (const project of Object.values(loadConfig()?.projects ?? {})) for (const { platforms } of projectDeviceSlots(project)) {
|
|
1168
|
+
const record = platforms.ios;
|
|
1169
|
+
if (record?.deviceUdid !== udid && record?.deviceName) names.add(record.deviceName);
|
|
1170
|
+
}
|
|
1171
|
+
for (const parked of readParked("ios")) if (parked.udid !== udid) names.add(parked.name);
|
|
1172
|
+
let suffix = "";
|
|
1173
|
+
for (let attempt = 0; names.has(ownedSimName(label, model, suffix)); attempt++) suffix = ` ${workspaceId(projectPath)}${attempt ? `-${attempt}` : ""}`;
|
|
1174
|
+
return suffix;
|
|
1175
|
+
}
|
|
1176
|
+
function ownedIosName(sim, label, model, projectPath, listed) {
|
|
1177
|
+
return ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, sim.udid, listed));
|
|
1178
|
+
}
|
|
1179
|
+
function renameToOwnedName(sim, label, model, projectPath) {
|
|
1180
|
+
const wanted = ownedIosName(sim, label, model, projectPath);
|
|
1181
|
+
if (sim.name === wanted) return wanted;
|
|
1182
|
+
try {
|
|
1183
|
+
renameIosSim(sim.udid, wanted);
|
|
1184
|
+
return wanted;
|
|
1185
|
+
} catch {
|
|
1186
|
+
return sim.name;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
function resetAdoptedSim(udid, out) {
|
|
1190
|
+
out(chalk.dim(phaseLine("device", `resetting privacy grants and the keychain on ${udid}`)));
|
|
1191
|
+
resetIosPrivacy(udid);
|
|
1192
|
+
resetIosKeychain(udid);
|
|
1193
|
+
}
|
|
1194
|
+
function takeParkedIosSim({ projectPath, slot, label, choice, out }) {
|
|
1195
|
+
const candidates = selectParked(readParked("ios"), {
|
|
1196
|
+
deviceTypeIdentifier: choice.deviceTypeId,
|
|
1197
|
+
runtimeIdentifier: choice.runtimeId
|
|
1198
|
+
});
|
|
1199
|
+
if (candidates.length === 0) return null;
|
|
1200
|
+
const listed = new Map(listAllIosSims({ includeUnavailable: true }).map((sim) => [sim.udid, sim]));
|
|
1201
|
+
for (const parked of candidates) {
|
|
1202
|
+
const sim = listed.get(parked.udid);
|
|
1203
|
+
if (!sim || !sim.available) {
|
|
1204
|
+
const result = sim ? teardownParkedIosSim(parked.udid, { label: parked.name }) : null;
|
|
1205
|
+
if (sim ? result?.status === "torn-down" : dropParked("ios", parked.udid)) out(chalk.dim(phaseLine("device", `deleted parked ${parked.name} (${parked.udid}): ${sim ? "unavailable" : "gone"}`)));
|
|
1206
|
+
else if (result?.status === "failed") out(chalk.yellow(phaseLine("device", `could not delete unavailable parked ${parked.name} (${parked.udid}): ${result.reason}`)));
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
if (!sim.name.startsWith("stim-")) {
|
|
1210
|
+
out(chalk.yellow(phaseLine("device", `kept parked record for ${parked.udid}: simulator is now named ${JSON.stringify(sim.name)} and is not Stim-owned`)));
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
const model = {
|
|
1214
|
+
model: choice.deviceType,
|
|
1215
|
+
runtime: choice.runtime
|
|
1216
|
+
};
|
|
1217
|
+
const name = ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, parked.udid));
|
|
1218
|
+
const device = {
|
|
1219
|
+
deviceUdid: parked.udid,
|
|
1220
|
+
owned: true,
|
|
1221
|
+
deviceName: name,
|
|
1222
|
+
adopted: true,
|
|
1223
|
+
adoptionPending: true,
|
|
1224
|
+
...parked.simslimManaged ? { simslimManaged: true } : {},
|
|
1225
|
+
...parked.cacheKey ? { parkedCacheKey: parked.cacheKey } : {}
|
|
1226
|
+
};
|
|
1227
|
+
const adopted = adoptParked({
|
|
1228
|
+
platform: "ios",
|
|
1229
|
+
projectPath,
|
|
1230
|
+
slot,
|
|
1231
|
+
udid: parked.udid,
|
|
1232
|
+
device
|
|
1233
|
+
});
|
|
1234
|
+
if (!adopted) continue;
|
|
1235
|
+
try {
|
|
1236
|
+
renameIosSim(parked.udid, name);
|
|
1237
|
+
} catch {}
|
|
1238
|
+
return adopted.schemeApprovals && adopted.schemeApprovals.length > 0 ? {
|
|
1239
|
+
...device,
|
|
1240
|
+
schemeApprovals: adopted.schemeApprovals
|
|
1241
|
+
} : device;
|
|
1242
|
+
}
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
function clearIosAdoptionPending(projectPath, slot = "default") {
|
|
1246
|
+
withConfigLock(() => {
|
|
1247
|
+
const cfg = loadConfig();
|
|
1248
|
+
const ios = deviceSlotPlatforms(cfg?.projects?.[projectPath], slot)?.ios;
|
|
1249
|
+
if (!cfg || !ios?.adoptionPending) return;
|
|
1250
|
+
delete ios.adopted;
|
|
1251
|
+
delete ios.adoptionPending;
|
|
1252
|
+
delete ios.parkedCacheKey;
|
|
1253
|
+
saveConfig(cfg);
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
async function configureOwnedIosSim({ record, projectPath, slot, profile, out, reconcileIosSimulator }) {
|
|
1257
|
+
if (profile) out(chalk.dim(phaseLine("device", `applying the SimSlim profile to ${record.deviceUdid}`)));
|
|
1258
|
+
else if (record.simslimManaged) out(chalk.dim(phaseLine("device", `restoring stock simulator services on ${record.deviceUdid}`)));
|
|
1259
|
+
const previouslyManaged = Boolean(record.simslimManaged);
|
|
1260
|
+
if (profile && !record.simslimManaged) {
|
|
1261
|
+
const pending = {
|
|
1262
|
+
...record,
|
|
1263
|
+
simslimManaged: true
|
|
1264
|
+
};
|
|
1265
|
+
setDevice(projectPath, "ios", pending, slot);
|
|
1266
|
+
record = pending;
|
|
1267
|
+
}
|
|
1268
|
+
const result = await reconcileIosSimulator({
|
|
1269
|
+
udid: record.deviceUdid,
|
|
1270
|
+
profile,
|
|
1271
|
+
previouslyManaged,
|
|
1272
|
+
out
|
|
1273
|
+
});
|
|
1274
|
+
const updated = { ...record };
|
|
1275
|
+
if (result.managed) updated.simslimManaged = true;
|
|
1276
|
+
else delete updated.simslimManaged;
|
|
1277
|
+
setDevice(projectPath, "ios", updated, slot);
|
|
1278
|
+
return updated;
|
|
1279
|
+
}
|
|
1280
|
+
async function ensureIosBooted({ device, projectPath, deviceSlotWait, simulatorApp, timeoutMs, pollMs, out }) {
|
|
1281
|
+
const udid = device?.deviceUdid;
|
|
1282
|
+
if (!udid) return {
|
|
1283
|
+
failed: true,
|
|
1284
|
+
reason: "No iOS simulator is recorded for this project."
|
|
1285
|
+
};
|
|
1286
|
+
const ready = () => {
|
|
1287
|
+
try {
|
|
1288
|
+
getExecutor().runFile("xcrun", [
|
|
1289
|
+
"simctl",
|
|
1290
|
+
"spawn",
|
|
1291
|
+
udid,
|
|
1292
|
+
"launchctl",
|
|
1293
|
+
"list"
|
|
1294
|
+
], { timeoutMs: 3e4 });
|
|
1295
|
+
return {
|
|
1296
|
+
ok: true,
|
|
1297
|
+
udid
|
|
1298
|
+
};
|
|
1299
|
+
} catch (error) {
|
|
1300
|
+
return {
|
|
1301
|
+
failed: true,
|
|
1302
|
+
reason: `Simulator ${udid} failed its process-spawn readiness check: ${error?.message || error}. ${iosSimulatorFailureAdvice()}`
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
const booting = device?.booting;
|
|
1307
|
+
if (booting?.udid === udid) {
|
|
1308
|
+
try {
|
|
1309
|
+
await booting.done;
|
|
1310
|
+
} catch (e) {
|
|
1311
|
+
return bootFailure(udid, e);
|
|
1312
|
+
}
|
|
1313
|
+
return ready();
|
|
1314
|
+
}
|
|
1315
|
+
const readiness = device?.booted === udid ? ready() : null;
|
|
1316
|
+
if (readiness?.ok) {
|
|
1317
|
+
if (simulatorApp !== void 0) configuredIosSimulatorViewer(simulatorApp).open(udid);
|
|
1318
|
+
return readiness;
|
|
1319
|
+
}
|
|
1320
|
+
let resolved;
|
|
1321
|
+
try {
|
|
1322
|
+
resolved = resolveOwnedIosSim(udid);
|
|
1323
|
+
} catch (e) {
|
|
1324
|
+
return {
|
|
1325
|
+
failed: true,
|
|
1326
|
+
reason: `Could not list simulators: ${e?.message || e}`
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
if (resolved.missing) return {
|
|
1330
|
+
failed: true,
|
|
1331
|
+
reason: `Simulator ${udid} no longer exists. Run \`stim ios\` again to create a fresh owned sim.`
|
|
1332
|
+
};
|
|
1333
|
+
if (resolved.notOwned) return {
|
|
1334
|
+
failed: true,
|
|
1335
|
+
reason: `Simulator ${udid} is now named "${resolved.notOwned}" and is not Stim-owned; refusing to boot it.`
|
|
1336
|
+
};
|
|
1337
|
+
const sim = resolved.sim;
|
|
1338
|
+
if (sim.state === "Booted") {
|
|
1339
|
+
const result = readiness ?? ready();
|
|
1340
|
+
if (result.ok && simulatorApp !== void 0) configuredIosSimulatorViewer(simulatorApp).open(udid);
|
|
1341
|
+
return result;
|
|
1342
|
+
}
|
|
1343
|
+
const bootDeadline = Date.now() + timeoutMs;
|
|
1344
|
+
try {
|
|
1345
|
+
await withDeviceBootAdmission({
|
|
1346
|
+
platform: "ios",
|
|
1347
|
+
key: udid
|
|
1348
|
+
}, () => {
|
|
1349
|
+
out(chalk.dim(phaseLine("device", `booting ${sim.name} (${udid})`)));
|
|
1350
|
+
return bootIosSim(udid, {
|
|
1351
|
+
timeoutMs,
|
|
1352
|
+
label: sim.name,
|
|
1353
|
+
out,
|
|
1354
|
+
simulatorApp
|
|
1355
|
+
});
|
|
1356
|
+
}, {
|
|
1357
|
+
...deviceSlotWait,
|
|
1358
|
+
root: projectPath,
|
|
1359
|
+
out
|
|
1360
|
+
});
|
|
1361
|
+
} catch (e) {
|
|
1362
|
+
return bootFailure(udid, e);
|
|
1363
|
+
}
|
|
1364
|
+
const deadline = Math.max(bootDeadline, Date.now() + 2 * pollMs);
|
|
1365
|
+
while (Date.now() < deadline) {
|
|
1366
|
+
await sleep(pollMs);
|
|
1367
|
+
let state = null;
|
|
1368
|
+
try {
|
|
1369
|
+
state = listAllIosSims({ timeoutMs: 3e4 }).find((s) => s.udid === udid)?.state ?? null;
|
|
1370
|
+
} catch {}
|
|
1371
|
+
if (state === "Booted") return ready();
|
|
1372
|
+
}
|
|
1373
|
+
return {
|
|
1374
|
+
failed: true,
|
|
1375
|
+
reason: `Simulator ${udid} did not reach the Booted state within ${Math.round(timeoutMs / 1e3)}s.`
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function bootFailure(udid, error) {
|
|
1379
|
+
const refusal = error instanceof DeviceAdmissionRefusal ? error : (0, ownership_claim_exports.claimFailure)(error, "stim ios");
|
|
1380
|
+
if (refusal) return {
|
|
1381
|
+
failed: true,
|
|
1382
|
+
code: refusal.code,
|
|
1383
|
+
reason: refusal.message,
|
|
1384
|
+
remedy: refusal.remedy
|
|
1385
|
+
};
|
|
1386
|
+
return {
|
|
1387
|
+
failed: true,
|
|
1388
|
+
reason: `Could not boot simulator ${udid}: ${error?.message || error}`
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
function sleep(ms) {
|
|
1392
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
1393
|
+
}
|
|
1394
|
+
//#endregion
|
|
1395
|
+
export { androidPathRoomMessage as _, apkOutputsDir as a, ccacheEnabled as c, productFlavorRefusal as d, readProductFlavors as f, androidPathRoom as g, formatDiagnostic as h, ensureOwnedIosDevice as i, discoverXcodeProject as l, assembleTaskFor as m, clearIosAdoptionPending as n, buildAndroid as o, androidSdkRefusal as p, ensureIosBooted as r, buildIos as s, IosDeviceMismatchError as t, gradlewPath as u, androidPathRoomRemedy as v };
|