stim 1.15.0 → 1.17.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/dist/{activity-B2-kb7k0.mjs → activity-IRvJY_ru.mjs} +49 -16
- package/dist/agent-device-usage-output-BK41vnzN.mjs +411 -0
- package/dist/{android-Cu_L4RpL.mjs → android--GorydsK.mjs} +692 -321
- package/dist/{android-Db2eEMaf.mjs → android-B_YNZy61.mjs} +25 -60
- package/dist/{android-CYmq0jNi.mjs → android-DE4v59Mb.mjs} +12 -3
- package/dist/{android-cas-PnKfAdB2.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
- package/dist/{app-install-CAAplXAt.mjs → app-install-VPkI5WEg.mjs} +52 -8
- package/dist/attempt-Bk2ouQVL.mjs +39 -0
- package/dist/{budget-CMiqghig.mjs → budget-DM984mnd.mjs} +372 -366
- package/dist/{build-plan-aeGMFX7e.mjs → build-plan-CmQCoyT-.mjs} +346 -88
- package/dist/{build-slots-Df1ApSuH.mjs → build-slots-41v_d2x9.mjs} +36 -21
- package/dist/{cli-0cX5s4NM.mjs → cli-Daxug5-K.mjs} +23 -17
- package/dist/cli.mjs +1 -1
- package/dist/collector-run.mjs +5 -192
- package/dist/{command-output-CliHHn7a.mjs → command-output-CDAIFD-8.mjs} +3 -3
- package/dist/{created-devices-BwVb3liH.mjs → created-devices-CpvzBL25.mjs} +1 -1
- package/dist/{dependency-state-BmsjKZ2H.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
- package/dist/{deps-BFlKbOIp.mjs → deps-DNWaQs4V.mjs} +2 -2
- package/dist/{dev-client-CjzLoNs0.mjs → dev-client-B-XC4uRH.mjs} +3 -40
- package/dist/{device-BZ1IyS5A.mjs → device-C8IOoJPv.mjs} +7 -6
- package/dist/device-capacity-D0GWHnTM.mjs +580 -0
- package/dist/device-host-worker.mjs +587 -110
- package/dist/{device-ios-DMQBUPus.mjs → device-ios-Bc7vbGwl.mjs} +75 -44
- package/dist/{device-lease-W5Pi1q38.mjs → device-lease-DpoS36_u.mjs} +2 -2
- package/dist/{device-pool-B2r38YjS.mjs → device-lease-run-B8YltIH_.mjs} +5 -125
- package/dist/device-pool-3o7s5lo4.mjs +125 -0
- package/dist/{device-remote-9ulPsdhY.mjs → device-remote-hFSkpfQu.mjs} +13 -13
- package/dist/{doctor-BcE5xsBn.mjs → doctor-Cnk9d7Hm.mjs} +86 -59
- package/dist/{error-diagnostics-Cb0P1WLS.mjs → error-diagnostics-C-NMnhrk.mjs} +11 -15
- package/dist/{gc-BuL1Genr.mjs → gc-DxCL2A46.mjs} +478 -33
- package/dist/{gradle-CmdOBq1d.mjs → gradle-D7-L2Th3.mjs} +4 -4
- package/dist/{guide-cCSGRFd3.mjs → guide-DjrTQGik.mjs} +2198 -566
- package/dist/{guide-status-CIoWK6mG.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
- package/dist/hosted-android-DwLS4Mse.mjs +32 -0
- package/dist/hosted-client-wk1W_CNW.mjs +196 -0
- package/dist/hosted-ios-aMo7Cljf.mjs +15 -0
- package/dist/hosted-logs-DqYmWtXc.mjs +187 -0
- package/dist/hosted-macos-dlHXEeF5.mjs +135 -0
- package/dist/hosted-native-C9xJ9rpA.mjs +255 -0
- package/dist/{build-progress-C2Jv1AtA.mjs → idle-B2m-Ovod.mjs} +300 -9
- package/dist/{idle-shutdown-B5LPaNyY.mjs → idle-shutdown-_3oOV1V_.mjs} +25 -17
- package/dist/{in-use-CndPMilN.mjs → in-use-CvGOUn-x.mjs} +30 -10
- package/dist/ios-Cr1h5gnO.mjs +189 -0
- package/dist/{ios-Chob8ny7.mjs → ios-DE6duQoz.mjs} +819 -460
- package/dist/{ios-3CtCRhwr.mjs → ios-DSfnPfse.mjs} +4 -4
- package/dist/{ios-device-DERmMmk-.mjs → ios-device-pAN4t54-.mjs} +1 -1
- package/dist/ios-state-8L3lgum6.mjs +89 -0
- package/dist/{launch-verify-CLlofxRt.mjs → launch-verify-lTnWZikR.mjs} +3 -3
- package/dist/logs-DUoKlDoS.mjs +384 -0
- package/dist/{client-C2IS36Qf.mjs → machines-C2XiNwh9.mjs} +330 -37
- package/dist/{macos-BwtbUtTN.mjs → macos-32po3kUq.mjs} +23 -18
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.d.mts +4 -0
- package/dist/maintenance-run.mjs +254 -0
- package/dist/{metro-Di8EN2Tb.mjs → metro-g8NqiJp-.mjs} +1 -1
- package/dist/metro-gateway-DmslUM30.mjs +103 -0
- package/dist/{named-ports-Dj_XBNaL.mjs → named-ports-C8m8EQs2.mjs} +2 -2
- package/dist/{native-run-DFDoIRbY.mjs → native-run-D1Q56rAD.mjs} +17 -6
- package/dist/{native-runtime-i6OkVg-w.mjs → native-runtime-DhJI3IVQ.mjs} +6 -6
- package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
- package/dist/offload-worker.d.mts +1 -0
- package/dist/offload-worker.mjs +13 -8
- package/dist/{teardown-BYuQafiA.mjs → ownership-BMLqyBgJ.mjs} +639 -53
- package/dist/{ownership-BkYxUtuj.mjs → ownership-DyRQru0q.mjs} +2 -2
- package/dist/{ports-DddwttKM.mjs → ports-4nYqxPWC.mjs} +2 -2
- package/dist/{prebuild-BvxDlD6C.mjs → prebuild-D7RUMkwN.mjs} +4 -4
- package/dist/preview-CxPRIEht.mjs +318 -0
- package/dist/{project-CV3tDFHl.mjs → project-D47Rh0ly.mjs} +72 -3
- package/dist/{recordings-GEXp4iBT.mjs → recordings-BNgsD1Tr.mjs} +1 -1
- package/dist/{reload-ChPiwvot.mjs → reload-qZei6iWn.mjs} +77 -13
- package/dist/{remote-cache-CO2elm_b.mjs → remote-cache-Ci4DQYYj.mjs} +4 -4
- package/dist/{run-B-xqRrsg.mjs → run-CkE9y0nc.mjs} +2 -2
- package/dist/{server-bare-X7PUgizL.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
- package/dist/{server-expo-DhtX6bom.mjs → server-expo-CHTyXD0G.mjs} +4 -4
- package/dist/server-expo-CeakhI8P.mjs +2 -0
- package/dist/settings-BBpMcDbD.mjs +25 -0
- package/dist/settings-Cfd-0r2d.mjs +1440 -0
- package/dist/{settings-DbL6uhH8.mjs → settings-SR9OmW9h.mjs} +10 -4
- package/dist/settings.schema.json +472 -50
- package/dist/{simslim-Ciluxlq4.mjs → simslim-BWNrc3M3.mjs} +3 -3
- package/dist/{slot-launch-BY0BrOLh.mjs → slot-launch-DmjBmpQV.mjs} +10 -7
- package/dist/{spawn-entry-DncpJvWL.mjs → spawn-entry-jw19m8Nl.mjs} +1 -0
- package/dist/{start-CPO4wRg7.mjs → start-BopZcr4n.mjs} +1 -1
- package/dist/{start-CUD9nasA.mjs → start-uee1wWjY.mjs} +21 -17
- package/dist/{state-CaeaHbDA.mjs → state-BKa8wNN5.mjs} +1 -1
- package/dist/{state-BxCgeTQu.mjs → state-DyaNTgfR.mjs} +2 -2
- package/dist/{state-DFm77wRn.mjs → state-PeQiJuIu.mjs} +5 -5
- package/dist/{stats-DBLLFmKd.mjs → stats-Bq4fJOdB.mjs} +19 -5
- package/dist/{status-l84Gbvp2.mjs → status-CzS4bPO9.mjs} +5 -3
- package/dist/status-DlKvVJBE.mjs +49 -0
- package/dist/{status-DYXxNOT0.mjs → status-dXX2JX1C.mjs} +244 -50
- package/dist/{stop-CceYh1yG.mjs → stop-BCwvvs7F.mjs} +2 -2
- package/dist/{stop-Bad61z_2.mjs → stop-BjizrQwv.mjs} +83 -21
- package/dist/{stop-Bvf1MflS.mjs → stop-Cr1d8DSE.mjs} +4 -4
- package/dist/stop-cause-rhmGfwvt.mjs +97 -0
- package/dist/supervisor-run.d.mts +7 -4
- package/dist/supervisor-run.mjs +156 -27
- package/dist/{support-WLOzVKUv.mjs → support-BJPgYCu-.mjs} +61 -11
- package/dist/{support-CDQbDkL5.mjs → support-F9-sr0Oi.mjs} +6 -5
- package/dist/{toolchain-DmeYjXD9.mjs → toolchain-CNIBTIOv.mjs} +11 -11
- package/dist/trigger-Bemu8ytw.mjs +65 -0
- package/dist/trigger-CXts6qt1.mjs +2 -0
- package/dist/{warm-progress-DVHLN4uC.mjs → warm-progress-DF4JRvYI.mjs} +274 -5
- package/dist/watchman-APYjXSQa.mjs +48 -0
- package/dist/{web-k6w8-HnE.mjs → web-exQtGkoc.mjs} +14 -16
- package/dist/web-run.mjs +5 -5
- package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
- package/dist/{workspace-state-CL2V2Ons.mjs → workspace-state-DqcCbpE7.mjs} +34 -34
- package/dist/workspaces-Bcib97-6.mjs +306 -0
- package/dist/{worktree-BT_uULFx.mjs → worktree-Dc98cE6_.mjs} +1 -1
- package/dist/{worktree-qXKzADSC.mjs → worktree-ZpZR3S1k.mjs} +601 -33
- package/package.json +5 -5
- package/dist/device-capacity-DMuKC7nx.mjs +0 -136
- package/dist/hosted-macos-DwowNU7W.mjs +0 -447
- package/dist/logs-h9h6MUvE.mjs +0 -568
- package/dist/machine-usage-D_YYMzfR.mjs +0 -283
- package/dist/machines-CYtOCqcj.mjs +0 -259
- package/dist/merge-state-BnxLNQiM.mjs +0 -272
- package/dist/server-expo-KJeD109I.mjs +0 -2
- package/dist/settings-CduVcoxj.mjs +0 -680
- package/dist/stop-cause-CZ_Mr-v9.mjs +0 -665
- package/dist/watchman-Bx0wceoF.mjs +0 -238
- package/dist/worktree-C0c5Udwa.mjs +0 -753
|
@@ -1,50 +1,434 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
2
|
import { C as saveConfig, D as withConfigLock$1, E as upsertProject, L as deviceSlotFileKey, R as deviceSlotKey, V as parseDeviceSlotOption, W as validateDeviceSlot, _ as loadConfig$1, j as formatBytes, p as getProject, u as getConcurrencyLimits, w as setDevice, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
|
|
3
3
|
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
4
|
-
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
5
|
-
import { C as workspaceLogsDir, b as workspaceDir, c as writeWorkspaceState, f as emulatorLogFile, i as recordWorkspaceUse, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
|
|
6
|
-
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-C0c5Udwa.mjs";
|
|
7
|
-
import { a as findProjectRoot$1, l as projectShortcut, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-CV3tDFHl.mjs";
|
|
8
|
-
import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-CaeaHbDA.mjs";
|
|
9
4
|
import { r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
10
|
-
import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-
|
|
11
|
-
import {
|
|
5
|
+
import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-CDAIFD-8.mjs";
|
|
6
|
+
import { B as settingsLayers, C as metroWarmupUrlSetting, F as settingFile, G as detectProviders, H as unknownSettingKeys, J as artifactCachePolicy, L as settingOriginScope, N as resolveCacheProviderConfig, P as resolveSettings, R as settingShapeErrors, T as parseIosRemote, Tt as removeTemporaryEntry, V as tunnelModeSetting, X as optimizationBuildProfile, Y as compilerCacheFallbackMessage, Z as resolveOptimizations, gt as repoRoot, i as SETTING_SHAPE_REMEDY, it as gitCommonDir, j as remoteAndroidSetting, k as publicUrlSetting, l as androidDataPartitionSizeGbSettingError, o as androidAvdConfigSettingError, u as cacheProviderSettingError, wt as makeTemporaryDirectory, x as metroPortSetting } from "./settings-Cfd-0r2d.mjs";
|
|
7
|
+
import { d as projectShortcut, n as appProjectProblem, r as detectIsExpo, s as findProjectRoot$1, t as NO_PROJECT_REFUSAL } from "./project-D47Rh0ly.mjs";
|
|
8
|
+
import { l as resolveProjectMetro, o as pidExists, u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
|
|
9
|
+
import { c as writeWorkspaceState, g as workspaceAgentDeviceDir, i as recordWorkspaceUse, l as emulatorLogFile, r as readWorkspaceState$1, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-DqcCbpE7.mjs";
|
|
10
|
+
import { t as budgetGate } from "./budget-DM984mnd.mjs";
|
|
11
|
+
import { A as providerDownloadPath, B as captureAssetManifest, D as fingerprintProject, E as fingerprintDiffRecord, F as storedAssetManifest, H as readAssetManifest, L as untrackedMissLine, M as refingerprintAfterMutation, N as resolveBuild, O as inputsChangedDuringBuild, P as storeBuild, R as untrackedNativeFiles, S as configInputsChanged, T as filesystemBuildCapability, V as compareAssetManifests, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as providerUploadOutcome, k as prepareProviderDownloadDir, m as acquireBuildLock, v as waitForSharedBuild, x as changedDuringBuildLine, z as assetDiffReason } from "./device-lease-DpoS36_u.mjs";
|
|
12
|
+
import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-41v_d2x9.mjs";
|
|
13
|
+
import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-BKa8wNN5.mjs";
|
|
14
|
+
import { $ as trimAndroidCaches, A as listAvds, B as ownedAvdSystemImage, D as hostSystemImageArch, F as ownedAvdDeviceProfile, G as probeEmulatorSerial, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, K as profileNeedsFoldFeature, O as listAdbDevices, Q as systemImageSupportsFold, T as findBuildTool, U as physicalDeviceModel, W as pickDefaultSystemImage, Y as resolvePhysicalDevice, a as androidDeviceAbi, ft as parkedMaxSetting, i as androidDataFreeBytes, j as listInstalledSystemImages, k as listAvdDeviceProfiles, q as resetAdoptedAvd, r as androidBuildToolName, rt as configuredAndroidEmulatorApp, t as DEFAULT_AVD_DEVICE_PROFILE, tt as waitForBoot, u as androidToolCwd } from "./android-B_YNZy61.mjs";
|
|
12
15
|
import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import { l as
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { t as
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { i as
|
|
28
|
-
import { c as
|
|
29
|
-
import { a as
|
|
30
|
-
import { a as
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import { a as
|
|
34
|
-
import { c as
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import { i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-
|
|
39
|
-
import {
|
|
40
|
-
import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-
|
|
41
|
-
import { n as resolveAndroidCas, r as resolveAndroidCompilerCache } from "./android-cas-
|
|
16
|
+
import { m as teardownOwnedAvd } from "./ownership-BMLqyBgJ.mjs";
|
|
17
|
+
import { C as recordRunStats, _ as tapBuildLog, g as startBuildProgress, h as recordFinishedBuild, l as NO_BUILD_PROGRESS, v as createRunRecorder, w as statsProjectKey$1, x as recordCapacityRefusal, y as readRunEstimates } from "./idle-B2m-Ovod.mjs";
|
|
18
|
+
import { r as createNdjsonWriter } from "./ndjson-PclOIwVY.mjs";
|
|
19
|
+
import { E as ccacheActivityLine, T as CCACHE_UNAVAILABLE, b as tailLines, k as resolveCcache, n as androidToolchain, t as androidRequirements, u as HEARTBEAT_INTERVAL_MS, w as CCACHE_NOT_RUN, y as startBuildHeartbeat } from "./toolchain-CNIBTIOv.mjs";
|
|
20
|
+
import { t as cleanLine } from "./server-expo-CHTyXD0G.mjs";
|
|
21
|
+
import { _ as resolveBuildPlacement, a as chooseBuildMachine, d as remotePhaseText, h as parseBuildMachineOption, i as buildPlacementCandidates, l as offloadPlacement, m as namedBuildMachine, o as closeOffload, p as OffloadRefusal, s as offloadBuild, u as placementLoad } from "./machines-C2XiNwh9.mjs";
|
|
22
|
+
import { r as hostedMetroSettings } from "./metro-gateway-DmslUM30.mjs";
|
|
23
|
+
import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-DyRQru0q.mjs";
|
|
24
|
+
import { n as DeviceAdmissionRefusal, r as checkDeviceCapacity, t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-D0GWHnTM.mjs";
|
|
25
|
+
import { S as restartedAppNote, b as launchAndroidReleaseApp, c as androidDevClientUrl, g as installConflictKind, h as installAndroidApp, r as DEFAULT_METRO_PORT, s as androidAppProcess, t as ADB_INSTALL_TIMEOUT_MS, y as launchAndroidApp } from "./app-install-VPkI5WEg.mjs";
|
|
26
|
+
import { C as resolveSystemImage, S as resolveDeviceProfile, T as systemImageRefusal, _ as isReleaseVariant, a as PLATFORM, b as pooledAndroidDevice, c as androidSystemImageSetting, d as apkPackage, f as deviceProfileRefusal, g as foldableImageRefusal, h as findAapt, i as NO_FINGERPRINT, l as androidVariantSetting, m as dumpApkManifest, n as LAUNCH_FAILED, o as androidBuildOptions, p as displayPath, r as NO_DEVICE, s as androidDevClientScheme, t as INSTALL_FAILED, u as apkDevClientFacts, v as noDeviceDiagnostic, w as resolveVariant, x as remoteAvdFlagRefusal, y as parseXmltree } from "./support-F9-sr0Oi.mjs";
|
|
27
|
+
import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
|
|
28
|
+
import { i as staleNativeDirRefusal, n as recordPrebuild, r as runPrebuild, t as planPrebuild } from "./prebuild-D7RUMkwN.mjs";
|
|
29
|
+
import { c as formatDiagnostic, i as buildAndroid, o as productFlavorRefusal, s as readProductFlavors } from "./gradle-D7-L2Th3.mjs";
|
|
30
|
+
import { a as VERIFY_TIMEOUT_MS, d as verifyAndroidReleaseLaunch, f as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unattributedLaunchLines, n as LAUNCH_FATAL, r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING, u as unverifiedLaunchLines } from "./launch-verify-lTnWZikR.mjs";
|
|
31
|
+
import { a as acquireRunLease, c as lostRefusal, d as runLease, f as waitFlagConflict, l as parseDeviceWait, o as leaseExpiryText, s as lostLine, t as DEBUG_VERIFY_STEP_MS, u as releaseLeaseOnSignal } from "./device-lease-run-B8YltIH_.mjs";
|
|
32
|
+
import { a as writeHostedAndroid, i as writeDevicePlacement, t as readHostedAndroid } from "./ios-state-8L3lgum6.mjs";
|
|
33
|
+
import { _ as AvdRecoveryError, a as refusePlan, b as devicePlacementLine, c as skippedMissReason, d as refreshUpdatesManifestFile, g as AvdBootError, h as ensureOwnedDevice, i as printPlan, l as UPDATES_MANIFEST_NAME, m as ensureBooted, n as planFlagRefusal, o as explainBuildMiss, p as didSetUpDevice, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as detectEntryFile, v as warmMetro, y as automaticDevicePlacement } from "./build-plan-CmQCoyT-.mjs";
|
|
34
|
+
import { n as prepareHostedAndroid, t as placeHostedAndroid } from "./hosted-android-DwLS4Mse.mjs";
|
|
35
|
+
import { n as nativeRunCommand, r as siblingPlatformSlots, t as launchSlotScope } from "./slot-launch-DmjBmpQV.mjs";
|
|
36
|
+
import { a as easAuthNote, c as loadProjectProvider, f as resolveEasCliBin, i as checkEasAuth, m as uploadRemote, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as resolveRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS } from "./remote-cache-Ci4DQYYj.mjs";
|
|
37
|
+
import { a as ensureMetroReachable, c as remoteAndroidDeps, n as binOnPath, o as ensureRemoteBootOwned, u as resolveRemoteContext, w as ownedSessionName } from "./device-remote-hFSkpfQu.mjs";
|
|
38
|
+
import { d as runCancellationSignal, f as withNativeBuildRun, r as cancelledFailure, u as runCancellation } from "./native-run-D1Q56rAD.mjs";
|
|
39
|
+
import { a as isEasBuildFailure, o as planEasDevelopmentBuild, s as resolveEasDevelopmentBuild } from "./simslim-BWNrc3M3.mjs";
|
|
40
|
+
import { c as startDevServer, m as detectAppIds, p as detectAndroidPackage } from "./start-uee1wWjY.mjs";
|
|
41
|
+
import { i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-DhJI3IVQ.mjs";
|
|
42
|
+
import { t as selectFromPool } from "./device-pool-3o7s5lo4.mjs";
|
|
43
|
+
import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-C-NMnhrk.mjs";
|
|
44
|
+
import { n as resolveAndroidCas, r as resolveAndroidCompilerCache } from "./android-cas-ZFpjJBL_.mjs";
|
|
42
45
|
import { constants, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync } from "node:fs";
|
|
43
46
|
import { basename, dirname, isAbsolute, join } from "node:path";
|
|
47
|
+
import { workspaceId } from "@stim-cli/core";
|
|
44
48
|
import { InvalidArgumentError } from "commander";
|
|
45
|
-
import { buildDiagnostics, machineCapacity } from "@stim-cli/core/state";
|
|
49
|
+
import { buildDiagnostics, hostedAndroidStatus, machineCapacity, parseMachine } from "@stim-cli/core/state";
|
|
46
50
|
import chalk from "chalk";
|
|
47
51
|
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
52
|
+
//#region src/commands/android/remote.ts
|
|
53
|
+
async function connectAndroidHosting({ root, slot, machine, release, metroCheck, selectors, read = readHostedAndroid, resolveSerial = resolveOwnedAvdSerial, prepare = prepareHostedAndroid }) {
|
|
54
|
+
let recorded;
|
|
55
|
+
try {
|
|
56
|
+
recorded = read(root, slot)[slot];
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return { failure: {
|
|
59
|
+
code: "STIM_HOSTING_REFUSED",
|
|
60
|
+
message: error.message,
|
|
61
|
+
remedy: `Restore that slot's recorded machine and session from the host, then run stim stop${slot === "default" ? "" : ` --slot ${slot}`} to reconcile it.`
|
|
62
|
+
} };
|
|
63
|
+
}
|
|
64
|
+
if (recorded && recorded.machine !== machine) return { failure: {
|
|
65
|
+
code: "STIM_BAD_ARG",
|
|
66
|
+
message: `This workspace's Android emulator runs on ${recorded.machine}; run stim stop first.`
|
|
67
|
+
} };
|
|
68
|
+
if (!machine) return { target: null };
|
|
69
|
+
if (!release && !metroCheck) return { failure: {
|
|
70
|
+
code: "STIM_BAD_ARG",
|
|
71
|
+
message: "Hosted Debug runs require the local Metro supervisor; --no-metro-check cannot be used.",
|
|
72
|
+
remedy: "Run stim stop; stim start, then retry without --no-metro-check."
|
|
73
|
+
} };
|
|
74
|
+
const local = deviceSlotPlatforms(getProject(root), slot)?.android;
|
|
75
|
+
if (local?.owned && local.avdName) {
|
|
76
|
+
let running = true;
|
|
77
|
+
try {
|
|
78
|
+
const resolved = resolveSerial(local.avdName, { timeoutMs: 5e3 });
|
|
79
|
+
running = Boolean(resolved.serial) || !resolved.notRunning && !resolved.missing;
|
|
80
|
+
} catch {}
|
|
81
|
+
if (running) return { failure: {
|
|
82
|
+
code: "STIM_BAD_ARG",
|
|
83
|
+
message: `This workspace's Android emulator for slot ${slot} runs on this Mac; run stim stop first.`
|
|
84
|
+
} };
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
return { target: await prepare(machine, selectors, recorded) };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return { failure: {
|
|
90
|
+
code: error.code ?? "STIM_HOSTING_REFUSED",
|
|
91
|
+
message: error.message,
|
|
92
|
+
...error instanceof Error && "remedy" in error && typeof error.remedy === "string" ? { remedy: error.remedy } : {}
|
|
93
|
+
} };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function selectAndroidPlacement({ target: selected, automatic = automaticDevicePlacement, checkBudget = budgetGate, note, phase, noWait, buildMachine, localSelectors, ...args }) {
|
|
97
|
+
const selectors = selected.kind === "hosted" ? {
|
|
98
|
+
...selected.systemImage ? { systemImage: selected.systemImage } : {},
|
|
99
|
+
...selected.deviceProfile ? { deviceProfile: selected.deviceProfile } : {}
|
|
100
|
+
} : {};
|
|
101
|
+
if (selected.kind !== "hosted" || selected.machine !== "auto") {
|
|
102
|
+
const connected = await connectAndroidHosting({
|
|
103
|
+
...args,
|
|
104
|
+
selectors,
|
|
105
|
+
machine: selected.kind === "hosted" ? selected.machine : null
|
|
106
|
+
});
|
|
107
|
+
if ("failure" in connected) return connected;
|
|
108
|
+
return {
|
|
109
|
+
target: selected,
|
|
110
|
+
hostedTarget: connected.target,
|
|
111
|
+
selectors,
|
|
112
|
+
budget: connected.target ? {
|
|
113
|
+
reclaimed: [],
|
|
114
|
+
refusal: null
|
|
115
|
+
} : await checkBudget({
|
|
116
|
+
root: args.root,
|
|
117
|
+
note
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const refusal = localSelectors(selected);
|
|
122
|
+
if (refusal) return { failure: refusal };
|
|
123
|
+
try {
|
|
124
|
+
const placed = await automatic({
|
|
125
|
+
root: args.root,
|
|
126
|
+
slot: args.slot,
|
|
127
|
+
platform: "android",
|
|
128
|
+
selectors,
|
|
129
|
+
buildMachine,
|
|
130
|
+
noWait
|
|
131
|
+
});
|
|
132
|
+
phase("placement:", devicePlacementLine(placed.placement, placed.skipped));
|
|
133
|
+
if (placed.target && !args.release && !args.metroCheck) return { failure: {
|
|
134
|
+
code: "STIM_BAD_ARG",
|
|
135
|
+
message: "Hosted Debug runs require the local Metro supervisor; --no-metro-check cannot be used.",
|
|
136
|
+
remedy: "Run stim stop; stim start, then retry without --no-metro-check."
|
|
137
|
+
} };
|
|
138
|
+
return {
|
|
139
|
+
target: placed.target ? {
|
|
140
|
+
...selected,
|
|
141
|
+
machine: placed.target.host.machine
|
|
142
|
+
} : {
|
|
143
|
+
kind: "emulator",
|
|
144
|
+
systemImage: selected.systemImage,
|
|
145
|
+
deviceProfile: selected.deviceProfile
|
|
146
|
+
},
|
|
147
|
+
hostedTarget: placed.target,
|
|
148
|
+
selectors,
|
|
149
|
+
budget: placed.target ? {
|
|
150
|
+
reclaimed: [],
|
|
151
|
+
refusal: null
|
|
152
|
+
} : await checkBudget({
|
|
153
|
+
root: args.root,
|
|
154
|
+
note
|
|
155
|
+
}),
|
|
156
|
+
devicePlacement: placed.placement
|
|
157
|
+
};
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return { failure: {
|
|
160
|
+
code: error.code ?? "STIM_HOSTING_REFUSED",
|
|
161
|
+
message: error.message,
|
|
162
|
+
...error instanceof Error && "remedy" in error && typeof error.remedy === "string" ? { remedy: error.remedy } : {}
|
|
163
|
+
} };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/commands/android/result.ts
|
|
168
|
+
function androidFacts({ root, slot, serial, avdName = null, deviceName = null, systemImage = null, deviceProfile = null, fingerprint, cacheKey = null, variant = null, metroPort = null, cacheHit, cacheSkipped = false, waitedForBuild = null, appPath, bundleId, installSkipped = false, launched, ccache = CCACHE_UNAVAILABLE, logs, debugHttpHost = null, debugHttpHostNote = null, devClientUrl = null, durationMs, lease, devServer = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null, host }) {
|
|
169
|
+
return {
|
|
170
|
+
platform: PLATFORM,
|
|
171
|
+
...host ? { host } : {},
|
|
172
|
+
...slot && slot !== "default" ? { slot } : {},
|
|
173
|
+
serial: serial ?? null,
|
|
174
|
+
avdName: avdName ?? null,
|
|
175
|
+
deviceName: deviceName ?? avdName ?? null,
|
|
176
|
+
systemImage: systemImage ?? null,
|
|
177
|
+
deviceProfile: deviceProfile ?? null,
|
|
178
|
+
fingerprint: fingerprint ?? null,
|
|
179
|
+
cacheKey: cacheKey ?? null,
|
|
180
|
+
variant: variant ?? null,
|
|
181
|
+
metroPort: metroPort ?? null,
|
|
182
|
+
cacheHit: cacheLevel(cacheHit),
|
|
183
|
+
cacheSkipped: Boolean(cacheSkipped),
|
|
184
|
+
buildMachine,
|
|
185
|
+
...builtOn ? { builtOn } : {},
|
|
186
|
+
...offloadedTo ? { offloadedTo } : {},
|
|
187
|
+
...offloadFallback ? { offloadFallback } : {},
|
|
188
|
+
waitedForBuild: waitedForBuild ? {
|
|
189
|
+
pid: waitedForBuild.pid ?? null,
|
|
190
|
+
ms: waitedForBuild.ms ?? 0
|
|
191
|
+
} : null,
|
|
192
|
+
appPath: appPath ?? null,
|
|
193
|
+
bundleId: bundleId ?? null,
|
|
194
|
+
installSkipped: Boolean(installSkipped),
|
|
195
|
+
launched: launched === "unverified" || launched === "bundling" ? launched : Boolean(launched),
|
|
196
|
+
ccache,
|
|
197
|
+
debugHttpHost: debugHttpHost ?? null,
|
|
198
|
+
debugHttpHostNote: debugHttpHostNote ?? null,
|
|
199
|
+
devClientUrl: devClientUrl ?? null,
|
|
200
|
+
logs: logs ?? null,
|
|
201
|
+
...root && !host ? { agentDevice: { stateDir: workspaceAgentDeviceDir(root) } } : {},
|
|
202
|
+
durationMs: typeof durationMs === "number" && Number.isFinite(durationMs) ? durationMs : null,
|
|
203
|
+
...lease === void 0 ? {} : { lease },
|
|
204
|
+
...devServer ? { devServer } : {}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function lastBuildRecord({ devicePlacement, fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null, diagnostics = null, configuration = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
|
|
208
|
+
const record = {
|
|
209
|
+
platform: PLATFORM,
|
|
210
|
+
avdName: avdName ?? null,
|
|
211
|
+
deviceName: deviceName ?? avdName ?? null,
|
|
212
|
+
fingerprint: fingerprint ?? null,
|
|
213
|
+
cacheKey: cacheKey ?? null,
|
|
214
|
+
cacheHit: cacheLevel(cacheHit),
|
|
215
|
+
cacheSkipped: Boolean(cacheSkipped),
|
|
216
|
+
durationMs: Number.isFinite(durationMs) ? durationMs : null,
|
|
217
|
+
appPath: appPath ?? null,
|
|
218
|
+
bundleId: bundleId ?? null,
|
|
219
|
+
startedAt,
|
|
220
|
+
status,
|
|
221
|
+
configuration: configuration ?? null
|
|
222
|
+
};
|
|
223
|
+
if (errorCode) record.errorCode = errorCode;
|
|
224
|
+
if (devicePlacement) record.devicePlacement = devicePlacement;
|
|
225
|
+
record.buildMachine = buildMachine;
|
|
226
|
+
if (builtOn) record.builtOn = builtOn;
|
|
227
|
+
if (offloadedTo) record.offloadedTo = offloadedTo;
|
|
228
|
+
if (offloadFallback) record.offloadFallback = offloadFallback;
|
|
229
|
+
if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
|
|
230
|
+
const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
|
|
231
|
+
if (recorded.length) record.diagnostics = recorded;
|
|
232
|
+
return record;
|
|
233
|
+
}
|
|
234
|
+
async function finishAndroidUpload(uploadPending, remote, phase) {
|
|
235
|
+
if (!uploadPending) return false;
|
|
236
|
+
const upload = await uploadPending;
|
|
237
|
+
if (upload?.uploaded) phase("cache", `uploaded (${remote?.name})`);
|
|
238
|
+
else if (upload?.timedOut) {
|
|
239
|
+
phase("cache", chalk.yellow(`${remote?.name} upload still running after ${formatDuration(UPLOAD_TIMEOUT_MS)}; not waiting`));
|
|
240
|
+
return true;
|
|
241
|
+
} else if (upload?.failed) {
|
|
242
|
+
const authNote = remote?.name === "eas" && isEasAuthFailureText(upload.failed) ? easAuthNote({
|
|
243
|
+
code: "logged-out",
|
|
244
|
+
reason: upload.failed,
|
|
245
|
+
phase: "upload"
|
|
246
|
+
}) : null;
|
|
247
|
+
phase("cache", chalk.yellow(authNote || `${remote?.name} upload failed: ${upload.failed}`));
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
function reportAndroidResult({ host, root, slot, json, useBuildCache, variant, release, metroCheck, metroPort, logsDir, serial, apkPath, androidPackage, installSkipped, record, waitedForBuild, remote, providerName, launchState, launchWarning, launched, ccache, durationMs, writer, emit, lease, recordRun, reclaimed = [], devServer = null, links }) {
|
|
252
|
+
const offloadedTo = record.offloadedTo ?? null;
|
|
253
|
+
recordRun({
|
|
254
|
+
failed: false,
|
|
255
|
+
cacheHit: cacheLevel(record.cacheHit),
|
|
256
|
+
waited: waitedForBuild,
|
|
257
|
+
durationMs,
|
|
258
|
+
offloadedTo
|
|
259
|
+
});
|
|
260
|
+
const facts = androidFacts({
|
|
261
|
+
host,
|
|
262
|
+
root,
|
|
263
|
+
slot,
|
|
264
|
+
serial,
|
|
265
|
+
avdName: record.avdName,
|
|
266
|
+
deviceName: record.deviceName,
|
|
267
|
+
systemImage: record.systemImage,
|
|
268
|
+
deviceProfile: record.deviceProfile,
|
|
269
|
+
debugHttpHost: launched.debugHttpHost ?? null,
|
|
270
|
+
debugHttpHostNote: launched.debugHttpHostNote ?? null,
|
|
271
|
+
devClientUrl: launched.devClientUrl ?? null,
|
|
272
|
+
fingerprint: record.fingerprint,
|
|
273
|
+
cacheKey: record.cacheKey,
|
|
274
|
+
variant,
|
|
275
|
+
metroPort,
|
|
276
|
+
cacheHit: record.cacheHit,
|
|
277
|
+
cacheSkipped: !useBuildCache,
|
|
278
|
+
waitedForBuild,
|
|
279
|
+
appPath: apkPath,
|
|
280
|
+
bundleId: androidPackage,
|
|
281
|
+
installSkipped,
|
|
282
|
+
launched: launchState,
|
|
283
|
+
ccache,
|
|
284
|
+
logs: logsDir,
|
|
285
|
+
durationMs,
|
|
286
|
+
lease,
|
|
287
|
+
devServer,
|
|
288
|
+
buildMachine: record.buildMachine,
|
|
289
|
+
builtOn: record.builtOn ?? void 0,
|
|
290
|
+
offloadedTo,
|
|
291
|
+
offloadFallback: record.offloadFallback ?? null
|
|
292
|
+
});
|
|
293
|
+
writer.close();
|
|
294
|
+
if (record.devicePlacement) facts.devicePlacement = record.devicePlacement;
|
|
295
|
+
if (json) emit(JSON.stringify({
|
|
296
|
+
...facts,
|
|
297
|
+
...links ? { links } : {},
|
|
298
|
+
...reclaimed.length ? { reclaimed } : {}
|
|
299
|
+
}));
|
|
300
|
+
else {
|
|
301
|
+
const summary = `${launchWarning ? "WARNING" : "OK"}: ${androidPackage} launched on ${host ? `${host.device?.name ?? "Android emulator"} on ${host.machine}` : serial}, ${release ? `${variant} (embedded JS, no Metro)` : `Metro port ${metroPort}`} (${cacheOutcome(record.cacheHit, remote?.name ?? providerName, offloadedTo)})`;
|
|
302
|
+
const outcome = launchWarning ? chalk.yellow(`${summary} -- ${launchWarning}`) : launchState === "unverified" ? chalk.yellow(`${summary} -- launch UNVERIFIED`) : launchState === "bundling" ? chalk.green(`${summary} -- bundle requested, still building`) : chalk.green(summary);
|
|
303
|
+
const deviceName = record.avdName || record.deviceName || serial;
|
|
304
|
+
const cacheResult = useBuildCache ? cacheOutcome(record.cacheHit, remote?.name ?? providerName, offloadedTo) : `bypassed; ${cacheOutcome(false, null, offloadedTo)}`;
|
|
305
|
+
const metroResult = release ? `embedded (${variant})` : !metroCheck ? `check skipped on port ${metroPort}` : launchState === "unverified" ? `state unverified on port ${metroPort}` : `running on port ${metroPort}${devServer ? ` (started: ${devServer.reason})` : ""}`;
|
|
306
|
+
emit([
|
|
307
|
+
outcome,
|
|
308
|
+
phaseLine("device", host ? `${deviceName} on ${host.machine}` : `${deviceName} (${serial})`),
|
|
309
|
+
phaseLine("app", androidPackage),
|
|
310
|
+
phaseLine("metro", metroResult),
|
|
311
|
+
phaseLine("cache", cacheResult),
|
|
312
|
+
...ccache.status === "not-run" ? [phaseLine("compilation cache", ccacheActivityLine(ccache))] : [],
|
|
313
|
+
phaseLine("logs", logsDir || "unavailable (remote device)"),
|
|
314
|
+
...!host ? [phaseLine("agent-device", `AGENT_DEVICE_STATE_DIR=${workspaceAgentDeviceDir(root)}`)] : []
|
|
315
|
+
].join("\n"));
|
|
316
|
+
if (links) console.error(chalk.dim(workspaceLinkLine(links)));
|
|
317
|
+
}
|
|
318
|
+
return facts;
|
|
319
|
+
}
|
|
320
|
+
function cacheOutcome(cacheHit, providerName = null, offloadedTo = null) {
|
|
321
|
+
if (cacheHit === "remote") return `cache hit from ${providerName || "the remote cache"}`;
|
|
322
|
+
if (cacheHit === "local") return "cache hit";
|
|
323
|
+
return offloadedTo ? `built on ${offloadedTo}` : "built";
|
|
324
|
+
}
|
|
325
|
+
function persistLastBuild({ recordBuild = recordFinishedBuild, root, record, startedAt, durationMs, status, errorCode = null, diagnostics = null, out }) {
|
|
326
|
+
const lastBuild = lastBuildRecord({
|
|
327
|
+
...record,
|
|
328
|
+
startedAt,
|
|
329
|
+
durationMs,
|
|
330
|
+
status,
|
|
331
|
+
errorCode,
|
|
332
|
+
diagnostics
|
|
333
|
+
});
|
|
334
|
+
try {
|
|
335
|
+
recordBuild(root, lastBuild);
|
|
336
|
+
} catch (err) {
|
|
337
|
+
out(phaseLine("state", chalk.yellow(`could not record lastBuild: ${err?.message || err}`)));
|
|
338
|
+
}
|
|
339
|
+
return lastBuild;
|
|
340
|
+
}
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/commands/android/hosted.ts
|
|
343
|
+
async function finishHostedAndroidRun({ target, artifact, root, slot = "default", release, isExpo, metroPort, logsDir, selectors, place, writePlacement, verifyLaunch: verify, writeLaunch, readApkPackage, resolveDevClientScheme, now, started, startedAt, fail, phase, out, recordBuild, ...report }) {
|
|
344
|
+
const packageName = artifact.androidPackage ?? readApkPackage(artifact.apkPath);
|
|
345
|
+
if (!artifact.apkPath || !packageName) return fail("STIM_INSTALL_FAILED", "The built APK has no package identity.");
|
|
346
|
+
const launchedAt = now();
|
|
347
|
+
try {
|
|
348
|
+
const run = await place(target, {
|
|
349
|
+
root,
|
|
350
|
+
slot,
|
|
351
|
+
bundle: artifact.apkPath,
|
|
352
|
+
handoff: artifact.handoff,
|
|
353
|
+
bundleId: packageName,
|
|
354
|
+
release,
|
|
355
|
+
metroPort,
|
|
356
|
+
selectors,
|
|
357
|
+
...!release && isExpo ? { devClientScheme: resolveDevClientScheme(root, artifact.apkPath) ?? void 0 } : {},
|
|
358
|
+
reserved: (placement) => writePlacement(root, slot, placement),
|
|
359
|
+
note: out
|
|
360
|
+
});
|
|
361
|
+
writePlacement(root, slot, run.placement);
|
|
362
|
+
writeLaunch(root, "android", {
|
|
363
|
+
appId: packageName,
|
|
364
|
+
deviceId: run.placement.session,
|
|
365
|
+
metroPort,
|
|
366
|
+
release,
|
|
367
|
+
launchedAt: new Date(launchedAt).toISOString()
|
|
368
|
+
});
|
|
369
|
+
let launched = run.launched;
|
|
370
|
+
if (!release) {
|
|
371
|
+
const evidence = await verify({
|
|
372
|
+
requireBundleResponse: true,
|
|
373
|
+
platform: "android",
|
|
374
|
+
logsDir: logsDir ?? void 0,
|
|
375
|
+
since: launchedAt,
|
|
376
|
+
metroPort,
|
|
377
|
+
mode: isExpo ? MODE_EXPO : MODE_BARE,
|
|
378
|
+
slot: launchSlotScope(root, slot),
|
|
379
|
+
platformShared: siblingPlatformSlots(root, "android", slot).length > 0
|
|
380
|
+
});
|
|
381
|
+
if (evidence.fatal) return fail("STIM_LAUNCH_FAILED", "Metro could not deliver the hosted app bundle.", "Run stim logs --errors and fix the bundle error.");
|
|
382
|
+
launched = evidence.verified ? true : evidence.requested ? "bundling" : "unverified";
|
|
383
|
+
}
|
|
384
|
+
if (launched === "unverified") out(`Launch on ${target.host.machine} is unverified; check the hosted app, then retry stim android --remote ${target.host.machine}.`);
|
|
385
|
+
const host = hostedAndroidStatus(run.placement);
|
|
386
|
+
report.record.deviceName = host.device?.name ?? null;
|
|
387
|
+
report.record.bundleId = packageName;
|
|
388
|
+
persistLastBuild({
|
|
389
|
+
recordBuild,
|
|
390
|
+
root,
|
|
391
|
+
record: report.record,
|
|
392
|
+
startedAt,
|
|
393
|
+
durationMs: now() - started,
|
|
394
|
+
status: "success",
|
|
395
|
+
out
|
|
396
|
+
});
|
|
397
|
+
await finishAndroidUpload(artifact.uploadPending, artifact.remote, phase);
|
|
398
|
+
await artifact.providerUpload;
|
|
399
|
+
return {
|
|
400
|
+
ok: true,
|
|
401
|
+
facts: reportAndroidResult({
|
|
402
|
+
...report,
|
|
403
|
+
root,
|
|
404
|
+
slot,
|
|
405
|
+
release,
|
|
406
|
+
metroPort,
|
|
407
|
+
logsDir,
|
|
408
|
+
host,
|
|
409
|
+
serial: null,
|
|
410
|
+
apkPath: artifact.apkPath,
|
|
411
|
+
androidPackage: packageName,
|
|
412
|
+
installSkipped: false,
|
|
413
|
+
waitedForBuild: artifact.waitedForBuild,
|
|
414
|
+
remote: artifact.remote,
|
|
415
|
+
providerName: artifact.providerName,
|
|
416
|
+
launchState: launched,
|
|
417
|
+
launched: {},
|
|
418
|
+
ccache: artifact.ccache,
|
|
419
|
+
durationMs: now() - started
|
|
420
|
+
})
|
|
421
|
+
};
|
|
422
|
+
} catch (error) {
|
|
423
|
+
return fail(error.code ?? "STIM_HOSTING_REFUSED", error.message, `Retry stim android --remote ${target.host.machine}, or run stim stop to reconcile the recorded placement.`);
|
|
424
|
+
} finally {
|
|
425
|
+
if (artifact.swapDir) rmSync(artifact.swapDir, {
|
|
426
|
+
recursive: true,
|
|
427
|
+
force: true
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
//#endregion
|
|
48
432
|
//#region src/engine/apk-swap.ts
|
|
49
433
|
const ANDROID_BUNDLE_NAME = "index.android.bundle";
|
|
50
434
|
const LAST_LINES = 5;
|
|
@@ -419,10 +803,11 @@ function fail$1(code, message, remedy, extra = {}) {
|
|
|
419
803
|
extra
|
|
420
804
|
};
|
|
421
805
|
}
|
|
422
|
-
async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo, device, physical, remote: remoteTarget, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { deviceAbi, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, acquireSlot, releaseSlot, planPrebuildFor, prebuild, build, ccacheFor, swapApk, readState, now }) {
|
|
423
|
-
const { phase, out, estimates, stats, step, miss, hit: lateHit, place, waitingOn } = progress;
|
|
806
|
+
async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo, device, physical, hostedAbi, remote: remoteTarget, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { deviceAbi, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, acquireSlot, releaseSlot, planPrebuildFor, prebuild, build, ccacheFor, swapApk, readState, now }) {
|
|
807
|
+
const { phase, out, estimates, stats, step, miss, hit: lateHit, place, waitingOn, waitingFor } = progress;
|
|
424
808
|
let fallbackMachine = null;
|
|
425
|
-
let hereReason =
|
|
809
|
+
let hereReason = "no build machine is paired";
|
|
810
|
+
let slotWaitMs;
|
|
426
811
|
const buildMachine = record.buildMachine ?? "auto";
|
|
427
812
|
const fallBack = (reason, line = reason) => {
|
|
428
813
|
if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, reason);
|
|
@@ -469,7 +854,8 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
469
854
|
deviceAbi,
|
|
470
855
|
compiler: cas?.id,
|
|
471
856
|
buildProfile,
|
|
472
|
-
targetAbiOnly: buildPlan.targetAbiOnly
|
|
857
|
+
targetAbiOnly: buildPlan.targetAbiOnly,
|
|
858
|
+
hostedAbi
|
|
473
859
|
});
|
|
474
860
|
let hash = "";
|
|
475
861
|
let providerUpload = null;
|
|
@@ -486,6 +872,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
486
872
|
let storeKey = "";
|
|
487
873
|
let storeSources = [];
|
|
488
874
|
let apkPath = null;
|
|
875
|
+
let handoff = null;
|
|
489
876
|
let swapFellBack = false;
|
|
490
877
|
async function resolveInitialFingerprint() {
|
|
491
878
|
if (easBuild?.ok) {
|
|
@@ -500,7 +887,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
500
887
|
stats.setCacheKey(cacheKey);
|
|
501
888
|
return true;
|
|
502
889
|
}
|
|
503
|
-
step("cache-lookup");
|
|
890
|
+
if (useBuildCache) step("cache-lookup");
|
|
504
891
|
const fingerprintTimer = stepTimer(now);
|
|
505
892
|
try {
|
|
506
893
|
const computed = await fingerprint(root, { platform: PLATFORM });
|
|
@@ -726,8 +1113,10 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
726
1113
|
max: maxBuilds,
|
|
727
1114
|
root,
|
|
728
1115
|
logFile: buildLog,
|
|
729
|
-
out
|
|
1116
|
+
out,
|
|
1117
|
+
waitingFor: (info) => waitingFor?.(info, "build-slot")
|
|
730
1118
|
});
|
|
1119
|
+
slotWaitMs = buildSlot.slotWaitMs;
|
|
731
1120
|
} catch (err) {
|
|
732
1121
|
const refusal = (0, ownership_claim_exports.claimFailure)(err, "stim android");
|
|
733
1122
|
if (refusal) {
|
|
@@ -868,6 +1257,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
868
1257
|
}
|
|
869
1258
|
const { timings } = outcome;
|
|
870
1259
|
apkPath = stored;
|
|
1260
|
+
handoff = outcome.handoff ?? null;
|
|
871
1261
|
record.builtOn = outcome.machine;
|
|
872
1262
|
record.offloadedTo = outcome.machine;
|
|
873
1263
|
stats.setPlacement({
|
|
@@ -974,12 +1364,16 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
974
1364
|
}
|
|
975
1365
|
if (offload) stats.setPlacement({
|
|
976
1366
|
decision: "fell-back",
|
|
1367
|
+
slotWaitMs,
|
|
1368
|
+
deviceSlotWaitMs: stats.deviceSlotWaitMs(),
|
|
977
1369
|
reason: record.offloadFallback ?? "offload failed",
|
|
978
1370
|
...fallbackMachine ? { machine: fallbackMachine } : {}
|
|
979
1371
|
});
|
|
980
|
-
else
|
|
1372
|
+
else stats.setPlacement({
|
|
981
1373
|
decision: "here",
|
|
982
|
-
reason: hereReason
|
|
1374
|
+
reason: hereReason,
|
|
1375
|
+
slotWaitMs,
|
|
1376
|
+
deviceSlotWaitMs: stats.deviceSlotWaitMs()
|
|
983
1377
|
});
|
|
984
1378
|
record.builtOn = "here";
|
|
985
1379
|
phase("build", `compiling ${variant || "debug"} with Gradle`);
|
|
@@ -1078,221 +1472,54 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
1078
1472
|
phase("cache", chalk.yellow(`could not store the build: ${err?.message || err}`));
|
|
1079
1473
|
}
|
|
1080
1474
|
}
|
|
1081
|
-
if (remote) uploadPending = uploadRemoteBuild({
|
|
1082
|
-
logWriter: writer,
|
|
1083
|
-
provider: remote.provider,
|
|
1084
|
-
platform: PLATFORM,
|
|
1085
|
-
projectRoot: root,
|
|
1086
|
-
fingerprintHash: storeHash,
|
|
1087
|
-
buildPath: apkPath,
|
|
1088
|
-
runOptions: remoteRunOptions
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
} catch (error) {
|
|
1093
|
-
if (!(error instanceof OffloadRefusal)) throw error;
|
|
1094
|
-
const refusal = error;
|
|
1095
|
-
phaseFailure = fail$1(refusal.code, refusal.message, refusal.remedy, { lastBuildStatus: true });
|
|
1096
|
-
return false;
|
|
1097
|
-
} finally {
|
|
1098
|
-
if (openOffload.choice) closeOffload(openOffload.choice);
|
|
1099
|
-
releaseHeldLock();
|
|
1100
|
-
releaseHeldSlot();
|
|
1101
|
-
}
|
|
1102
|
-
return true;
|
|
1103
|
-
}
|
|
1104
|
-
if (!easBuild) {
|
|
1105
|
-
await prepareCachedArtifact();
|
|
1106
|
-
if (apkPath) lateHit();
|
|
1107
|
-
else if (swapFellBack) miss(reasonForMiss([]).reason);
|
|
1108
|
-
if (!await buildArtifact()) return refused();
|
|
1109
|
-
}
|
|
1110
|
-
return {
|
|
1111
|
-
ok: true,
|
|
1112
|
-
artifact: {
|
|
1113
|
-
apkPath,
|
|
1114
|
-
androidPackage,
|
|
1115
|
-
swapDir,
|
|
1116
|
-
waitedForBuild,
|
|
1117
|
-
ccache: ccacheActivity,
|
|
1118
|
-
uploadPending,
|
|
1119
|
-
providerUpload,
|
|
1120
|
-
providerName,
|
|
1121
|
-
remote,
|
|
1122
|
-
abandonedRemote
|
|
1123
|
-
}
|
|
1124
|
-
};
|
|
1125
|
-
}
|
|
1126
|
-
function tail(lines, n = FALLBACK_LINES) {
|
|
1127
|
-
return (Array.isArray(lines) ? lines : []).slice(-n);
|
|
1128
|
-
}
|
|
1129
|
-
//#endregion
|
|
1130
|
-
//#region src/commands/android/result.ts
|
|
1131
|
-
function androidFacts({ slot, serial, avdName = null, deviceName = null, systemImage = null, deviceProfile = null, fingerprint, cacheKey = null, variant = null, metroPort = null, cacheHit, cacheSkipped = false, waitedForBuild = null, appPath, bundleId, installSkipped = false, launched, ccache = CCACHE_UNAVAILABLE, logs, debugHttpHost = null, debugHttpHostNote = null, devClientUrl = null, durationMs, lease, devServer = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
|
|
1132
|
-
return {
|
|
1133
|
-
platform: PLATFORM,
|
|
1134
|
-
...slot && slot !== "default" ? { slot } : {},
|
|
1135
|
-
serial: serial ?? null,
|
|
1136
|
-
avdName: avdName ?? null,
|
|
1137
|
-
deviceName: deviceName ?? avdName ?? null,
|
|
1138
|
-
systemImage: systemImage ?? null,
|
|
1139
|
-
deviceProfile: deviceProfile ?? null,
|
|
1140
|
-
fingerprint: fingerprint ?? null,
|
|
1141
|
-
cacheKey: cacheKey ?? null,
|
|
1142
|
-
variant: variant ?? null,
|
|
1143
|
-
metroPort: metroPort ?? null,
|
|
1144
|
-
cacheHit: cacheLevel(cacheHit),
|
|
1145
|
-
cacheSkipped: Boolean(cacheSkipped),
|
|
1146
|
-
buildMachine,
|
|
1147
|
-
...builtOn ? { builtOn } : {},
|
|
1148
|
-
...offloadedTo ? { offloadedTo } : {},
|
|
1149
|
-
...offloadFallback ? { offloadFallback } : {},
|
|
1150
|
-
waitedForBuild: waitedForBuild ? {
|
|
1151
|
-
pid: waitedForBuild.pid ?? null,
|
|
1152
|
-
ms: waitedForBuild.ms ?? 0
|
|
1153
|
-
} : null,
|
|
1154
|
-
appPath: appPath ?? null,
|
|
1155
|
-
bundleId: bundleId ?? null,
|
|
1156
|
-
installSkipped: Boolean(installSkipped),
|
|
1157
|
-
launched: launched === "unverified" || launched === "bundling" ? launched : Boolean(launched),
|
|
1158
|
-
ccache,
|
|
1159
|
-
debugHttpHost: debugHttpHost ?? null,
|
|
1160
|
-
debugHttpHostNote: debugHttpHostNote ?? null,
|
|
1161
|
-
devClientUrl: devClientUrl ?? null,
|
|
1162
|
-
logs: logs ?? null,
|
|
1163
|
-
durationMs: typeof durationMs === "number" && Number.isFinite(durationMs) ? durationMs : null,
|
|
1164
|
-
...lease === void 0 ? {} : { lease },
|
|
1165
|
-
...devServer ? { devServer } : {}
|
|
1166
|
-
};
|
|
1167
|
-
}
|
|
1168
|
-
function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null, diagnostics = null, configuration = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
|
|
1169
|
-
const record = {
|
|
1170
|
-
platform: PLATFORM,
|
|
1171
|
-
avdName: avdName ?? null,
|
|
1172
|
-
deviceName: deviceName ?? avdName ?? null,
|
|
1173
|
-
fingerprint: fingerprint ?? null,
|
|
1174
|
-
cacheKey: cacheKey ?? null,
|
|
1175
|
-
cacheHit: cacheLevel(cacheHit),
|
|
1176
|
-
cacheSkipped: Boolean(cacheSkipped),
|
|
1177
|
-
durationMs: Number.isFinite(durationMs) ? durationMs : null,
|
|
1178
|
-
appPath: appPath ?? null,
|
|
1179
|
-
bundleId: bundleId ?? null,
|
|
1180
|
-
startedAt,
|
|
1181
|
-
status,
|
|
1182
|
-
configuration: configuration ?? null
|
|
1183
|
-
};
|
|
1184
|
-
if (errorCode) record.errorCode = errorCode;
|
|
1185
|
-
record.buildMachine = buildMachine;
|
|
1186
|
-
if (builtOn) record.builtOn = builtOn;
|
|
1187
|
-
if (offloadedTo) record.offloadedTo = offloadedTo;
|
|
1188
|
-
if (offloadFallback) record.offloadFallback = offloadFallback;
|
|
1189
|
-
if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
|
|
1190
|
-
const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
|
|
1191
|
-
if (recorded.length) record.diagnostics = recorded;
|
|
1192
|
-
return record;
|
|
1193
|
-
}
|
|
1194
|
-
async function finishAndroidUpload(uploadPending, remote, phase) {
|
|
1195
|
-
if (!uploadPending) return false;
|
|
1196
|
-
const upload = await uploadPending;
|
|
1197
|
-
if (upload?.uploaded) phase("cache", `uploaded (${remote?.name})`);
|
|
1198
|
-
else if (upload?.timedOut) {
|
|
1199
|
-
phase("cache", chalk.yellow(`${remote?.name} upload still running after ${formatDuration(UPLOAD_TIMEOUT_MS)}; not waiting`));
|
|
1475
|
+
if (remote) uploadPending = uploadRemoteBuild({
|
|
1476
|
+
logWriter: writer,
|
|
1477
|
+
provider: remote.provider,
|
|
1478
|
+
platform: PLATFORM,
|
|
1479
|
+
projectRoot: root,
|
|
1480
|
+
fingerprintHash: storeHash,
|
|
1481
|
+
buildPath: apkPath,
|
|
1482
|
+
runOptions: remoteRunOptions
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
} catch (error) {
|
|
1487
|
+
if (!(error instanceof OffloadRefusal)) throw error;
|
|
1488
|
+
const refusal = error;
|
|
1489
|
+
phaseFailure = fail$1(refusal.code, refusal.message, refusal.remedy, { lastBuildStatus: true });
|
|
1490
|
+
return false;
|
|
1491
|
+
} finally {
|
|
1492
|
+
if (openOffload.choice) closeOffload(openOffload.choice);
|
|
1493
|
+
releaseHeldLock();
|
|
1494
|
+
releaseHeldSlot();
|
|
1495
|
+
}
|
|
1200
1496
|
return true;
|
|
1201
|
-
} else if (upload?.failed) {
|
|
1202
|
-
const authNote = remote?.name === "eas" && isEasAuthFailureText(upload.failed) ? easAuthNote({
|
|
1203
|
-
code: "logged-out",
|
|
1204
|
-
reason: upload.failed,
|
|
1205
|
-
phase: "upload"
|
|
1206
|
-
}) : null;
|
|
1207
|
-
phase("cache", chalk.yellow(authNote || `${remote?.name} upload failed: ${upload.failed}`));
|
|
1208
1497
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
failed: false,
|
|
1215
|
-
cacheHit: cacheLevel(record.cacheHit),
|
|
1216
|
-
waited: waitedForBuild,
|
|
1217
|
-
durationMs,
|
|
1218
|
-
offloadedTo
|
|
1219
|
-
});
|
|
1220
|
-
const facts = androidFacts({
|
|
1221
|
-
slot,
|
|
1222
|
-
serial,
|
|
1223
|
-
avdName: record.avdName,
|
|
1224
|
-
deviceName: record.deviceName,
|
|
1225
|
-
systemImage: record.systemImage,
|
|
1226
|
-
deviceProfile: record.deviceProfile,
|
|
1227
|
-
debugHttpHost: launched.debugHttpHost ?? null,
|
|
1228
|
-
debugHttpHostNote: launched.debugHttpHostNote ?? null,
|
|
1229
|
-
devClientUrl: launched.devClientUrl ?? null,
|
|
1230
|
-
fingerprint: record.fingerprint,
|
|
1231
|
-
cacheKey: record.cacheKey,
|
|
1232
|
-
variant,
|
|
1233
|
-
metroPort,
|
|
1234
|
-
cacheHit: record.cacheHit,
|
|
1235
|
-
cacheSkipped: !useBuildCache,
|
|
1236
|
-
waitedForBuild,
|
|
1237
|
-
appPath: apkPath,
|
|
1238
|
-
bundleId: androidPackage,
|
|
1239
|
-
installSkipped,
|
|
1240
|
-
launched: launchState,
|
|
1241
|
-
ccache,
|
|
1242
|
-
logs: logsDir,
|
|
1243
|
-
durationMs,
|
|
1244
|
-
lease,
|
|
1245
|
-
devServer,
|
|
1246
|
-
buildMachine: record.buildMachine,
|
|
1247
|
-
builtOn: record.builtOn ?? void 0,
|
|
1248
|
-
offloadedTo,
|
|
1249
|
-
offloadFallback: record.offloadFallback ?? null
|
|
1250
|
-
});
|
|
1251
|
-
writer.close();
|
|
1252
|
-
if (json) emit(JSON.stringify({
|
|
1253
|
-
...facts,
|
|
1254
|
-
...links ? { links } : {},
|
|
1255
|
-
...reclaimed.length ? { reclaimed } : {}
|
|
1256
|
-
}));
|
|
1257
|
-
else {
|
|
1258
|
-
const summary = `${launchWarning ? "WARNING" : "OK"}: ${androidPackage} launched on ${serial}, ${release ? `${variant} (embedded JS, no Metro)` : `Metro port ${metroPort}`} (${cacheOutcome(record.cacheHit, remote?.name ?? providerName, offloadedTo)})`;
|
|
1259
|
-
const outcome = launchWarning ? chalk.yellow(`${summary} -- ${launchWarning}`) : launchState === "unverified" ? chalk.yellow(`${summary} -- launch UNVERIFIED`) : launchState === "bundling" ? chalk.green(`${summary} -- bundle requested, still building`) : chalk.green(summary);
|
|
1260
|
-
const deviceName = record.avdName || record.deviceName || serial;
|
|
1261
|
-
const cacheResult = useBuildCache ? cacheOutcome(record.cacheHit, remote?.name ?? providerName, offloadedTo) : `bypassed; ${cacheOutcome(false, null, offloadedTo)}`;
|
|
1262
|
-
const metroResult = release ? `embedded (${variant})` : !metroCheck ? `check skipped on port ${metroPort}` : launchState === "unverified" ? `state unverified on port ${metroPort}` : `running on port ${metroPort}${devServer ? ` (started: ${devServer.reason})` : ""}`;
|
|
1263
|
-
emit([
|
|
1264
|
-
outcome,
|
|
1265
|
-
phaseLine("device", `${deviceName} (${serial})`),
|
|
1266
|
-
phaseLine("app", androidPackage),
|
|
1267
|
-
phaseLine("metro", metroResult),
|
|
1268
|
-
phaseLine("cache", cacheResult),
|
|
1269
|
-
...ccache.status === "not-run" ? [phaseLine("compilation cache", ccacheActivityLine(ccache))] : [],
|
|
1270
|
-
phaseLine("logs", logsDir || "unavailable (remote device)")
|
|
1271
|
-
].join("\n"));
|
|
1272
|
-
if (links) console.error(chalk.dim(workspaceLinkLine(links)));
|
|
1498
|
+
if (!easBuild) {
|
|
1499
|
+
await prepareCachedArtifact();
|
|
1500
|
+
if (apkPath) lateHit();
|
|
1501
|
+
else if (swapFellBack) miss(reasonForMiss([]).reason);
|
|
1502
|
+
if (!await buildArtifact()) return refused();
|
|
1273
1503
|
}
|
|
1274
|
-
return
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1504
|
+
return {
|
|
1505
|
+
ok: true,
|
|
1506
|
+
artifact: {
|
|
1507
|
+
apkPath,
|
|
1508
|
+
handoff,
|
|
1509
|
+
androidPackage,
|
|
1510
|
+
swapDir,
|
|
1511
|
+
waitedForBuild,
|
|
1512
|
+
ccache: ccacheActivity,
|
|
1513
|
+
uploadPending,
|
|
1514
|
+
providerUpload,
|
|
1515
|
+
providerName,
|
|
1516
|
+
remote,
|
|
1517
|
+
abandonedRemote
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1280
1520
|
}
|
|
1281
|
-
function
|
|
1282
|
-
|
|
1283
|
-
...record,
|
|
1284
|
-
startedAt,
|
|
1285
|
-
durationMs,
|
|
1286
|
-
status,
|
|
1287
|
-
errorCode,
|
|
1288
|
-
diagnostics
|
|
1289
|
-
});
|
|
1290
|
-
try {
|
|
1291
|
-
recordBuild(root, lastBuild);
|
|
1292
|
-
} catch (err) {
|
|
1293
|
-
out(phaseLine("state", chalk.yellow(`could not record lastBuild: ${err?.message || err}`)));
|
|
1294
|
-
}
|
|
1295
|
-
return lastBuild;
|
|
1521
|
+
function tail(lines, n = FALLBACK_LINES) {
|
|
1522
|
+
return (Array.isArray(lines) ? lines : []).slice(-n);
|
|
1296
1523
|
}
|
|
1297
1524
|
//#endregion
|
|
1298
1525
|
//#region src/commands/android/collector.ts
|
|
@@ -1300,7 +1527,7 @@ function collectorEntry() {
|
|
|
1300
1527
|
return spawnEntry("collector-run");
|
|
1301
1528
|
}
|
|
1302
1529
|
function collectorLogFile(root, slot = "default") {
|
|
1303
|
-
return join(workspaceLogsDir(root), `collector-${deviceSlotFileKey(PLATFORM, slot)}.log`);
|
|
1530
|
+
return join(workspaceLogsDir$1(root), `collector-${deviceSlotFileKey(PLATFORM, slot)}.log`);
|
|
1304
1531
|
}
|
|
1305
1532
|
const COLLECTOR_EXIT_WAIT_MS = 2e3;
|
|
1306
1533
|
const COLLECTOR_POLL_MS = 25;
|
|
@@ -1341,7 +1568,7 @@ async function startCollector({ root, slot = "default", serial, packageName, spa
|
|
|
1341
1568
|
}
|
|
1342
1569
|
let stdio = "ignore";
|
|
1343
1570
|
try {
|
|
1344
|
-
mkdirSync(workspaceLogsDir(root), { recursive: true });
|
|
1571
|
+
mkdirSync(workspaceLogsDir$1(root), { recursive: true });
|
|
1345
1572
|
const fd = openSync(collectorLogFile(root, slot), "a");
|
|
1346
1573
|
stdio = [
|
|
1347
1574
|
"ignore",
|
|
@@ -1611,7 +1838,7 @@ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCh
|
|
|
1611
1838
|
});
|
|
1612
1839
|
if (booted.failed) {
|
|
1613
1840
|
const diag = diagnoseBootFailure(booted, emuLog, runCommand, physical);
|
|
1614
|
-
return fail(
|
|
1841
|
+
return fail(diag.code, diag.message, diag.remedy, {
|
|
1615
1842
|
lines: diag.lines,
|
|
1616
1843
|
logPath: diag.logPath ? displayPath(root, diag.logPath) : null
|
|
1617
1844
|
});
|
|
@@ -1877,6 +2104,7 @@ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCh
|
|
|
1877
2104
|
const leaseFacts = lease?.facts() ?? null;
|
|
1878
2105
|
releaseLease();
|
|
1879
2106
|
const facts = reportAndroidResult({
|
|
2107
|
+
root,
|
|
1880
2108
|
slot,
|
|
1881
2109
|
json,
|
|
1882
2110
|
useBuildCache,
|
|
@@ -1943,12 +2171,23 @@ function reportMetroRoute({ launched, remote, metroPort, androidPackage, serial,
|
|
|
1943
2171
|
});
|
|
1944
2172
|
}
|
|
1945
2173
|
function diagnoseBootFailure(booted, logFile, runCommand, physical) {
|
|
1946
|
-
return
|
|
2174
|
+
if (booted.code) return {
|
|
2175
|
+
code: booted.code,
|
|
2176
|
+
message: booted.reason ?? "The emulator did not boot.",
|
|
2177
|
+
remedy: booted.remedy ?? null,
|
|
2178
|
+
lines: [],
|
|
2179
|
+
logPath: null
|
|
2180
|
+
};
|
|
2181
|
+
const diag = noDeviceDiagnostic({
|
|
1947
2182
|
reason: booted.reason ?? "The emulator did not boot.",
|
|
1948
2183
|
logFile,
|
|
1949
2184
|
remedy: booted.remedy ?? `Run \`stim status\` to see what Stim thinks it owns; re-running \`${runCommand}\` creates a fresh owned AVD.`,
|
|
1950
2185
|
localEmulator: !physical
|
|
1951
2186
|
});
|
|
2187
|
+
return {
|
|
2188
|
+
code: NO_DEVICE,
|
|
2189
|
+
...diag
|
|
2190
|
+
};
|
|
1952
2191
|
}
|
|
1953
2192
|
//#endregion
|
|
1954
2193
|
//#region src/commands/android/plan.ts
|
|
@@ -2037,13 +2276,78 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
2037
2276
|
if (physical && deviceFlag === "") return fail("STIM_BAD_ARG", "--device was given an empty serial.", "Pass `--device` on its own to take the first connected device this workspace can lease, or `--device <serial>` to name one.");
|
|
2038
2277
|
if (physical && commandRemoteBackend) return fail("STIM_BAD_ARG", "--device installs on a device connected to this machine, and --remote installs on a remote one.", "Pass only one of --device and --remote.");
|
|
2039
2278
|
const noWait = waitFlag === false;
|
|
2040
|
-
|
|
2041
|
-
if (waitConflict) return fail("STIM_BAD_ARG", "--wait and --no-wait ask for opposite things.", "Pass `--wait <seconds>` to wait for the lease, or `--no-wait` to install without one.");
|
|
2042
|
-
if (waitFlagged && !physical) return fail("STIM_BAD_ARG", "--wait and --no-wait only apply to a `--device` run.", "This workspace owns its emulator, so nothing contends for it. Drop the flag, or pass `--device`.");
|
|
2279
|
+
if (waitConflict) return fail("STIM_BAD_ARG", "--wait and --no-wait ask for opposite things.", "Pass only one of `--wait <seconds>` and `--no-wait`.");
|
|
2043
2280
|
const waitParsed = parseDeviceWait(noWait ? void 0 : waitFlag);
|
|
2044
|
-
if ("error" in waitParsed) return fail("STIM_BAD_ARG", waitParsed.error, "Pass a whole number of seconds, e.g. --wait 90. `--wait 0` refuses a
|
|
2281
|
+
if ("error" in waitParsed) return fail("STIM_BAD_ARG", waitParsed.error, "Pass a whole number of seconds, e.g. --wait 90. `--wait 0` refuses a busy lease or device slot at once.");
|
|
2045
2282
|
const waitSeconds = waitParsed.seconds;
|
|
2046
|
-
const
|
|
2283
|
+
const remoteTarget = commandRemoteBackend !== null ? parseIosRemote(commandRemoteBackend) : remoteAndroidSetting(settings);
|
|
2284
|
+
if (physical && remoteTarget?.kind === "machine") return fail("STIM_BAD_ARG", "--device installs on a phone connected to this machine, and --remote installs on a remote one.", "Pass only one of --device and --remote; unset android.remote for a local phone.");
|
|
2285
|
+
const machine = remoteTarget?.kind === "machine" ? remoteTarget.machine : null;
|
|
2286
|
+
const remoteBackend = !physical && remoteTarget?.kind === "backend" ? remoteTarget.backend : null;
|
|
2287
|
+
if (!machine) {
|
|
2288
|
+
const refusal = androidDeviceSelectorRefusal({
|
|
2289
|
+
settingsContext,
|
|
2290
|
+
slot,
|
|
2291
|
+
systemImageFlag,
|
|
2292
|
+
deviceProfileFlag,
|
|
2293
|
+
systemImage,
|
|
2294
|
+
deviceProfile,
|
|
2295
|
+
physical,
|
|
2296
|
+
remoteBackend
|
|
2297
|
+
}, {
|
|
2298
|
+
listSystemImages,
|
|
2299
|
+
listDeviceProfiles,
|
|
2300
|
+
supportsFold,
|
|
2301
|
+
ownedAvd
|
|
2302
|
+
});
|
|
2303
|
+
if (refusal) return refusal;
|
|
2304
|
+
}
|
|
2305
|
+
const target = physical ? {
|
|
2306
|
+
kind: "physical",
|
|
2307
|
+
serial: typeof deviceFlag === "string" ? deviceFlag : null,
|
|
2308
|
+
lease: {
|
|
2309
|
+
waitSeconds,
|
|
2310
|
+
noWait
|
|
2311
|
+
}
|
|
2312
|
+
} : machine ? {
|
|
2313
|
+
kind: "hosted",
|
|
2314
|
+
machine,
|
|
2315
|
+
systemImage,
|
|
2316
|
+
deviceProfile
|
|
2317
|
+
} : remoteBackend ? {
|
|
2318
|
+
kind: "remote",
|
|
2319
|
+
backend: remoteBackend,
|
|
2320
|
+
systemImage,
|
|
2321
|
+
deviceProfile
|
|
2322
|
+
} : {
|
|
2323
|
+
kind: "emulator",
|
|
2324
|
+
systemImage,
|
|
2325
|
+
deviceProfile
|
|
2326
|
+
};
|
|
2327
|
+
return {
|
|
2328
|
+
ok: true,
|
|
2329
|
+
plan: {
|
|
2330
|
+
build: {
|
|
2331
|
+
variant,
|
|
2332
|
+
release,
|
|
2333
|
+
profile: buildProfile,
|
|
2334
|
+
cas,
|
|
2335
|
+
cache: cachePolicy,
|
|
2336
|
+
compilerCache: optimizations.android.compilerCache,
|
|
2337
|
+
gradleBuildCache: optimizations.android.gradleBuildCache,
|
|
2338
|
+
pch: optimizations.android.pch,
|
|
2339
|
+
targetAbiOnly: optimizations.android.targetAbiOnly
|
|
2340
|
+
},
|
|
2341
|
+
target,
|
|
2342
|
+
deviceSlotWaitMs: noWait ? 0 : waitFlag === void 0 && !physical ? DEFAULT_DEVICE_SLOT_WAIT_MS : waitSeconds * 1e3,
|
|
2343
|
+
isExpo,
|
|
2344
|
+
metroWarmup: optimizations.metroWarmup,
|
|
2345
|
+
cacheProviderConfig
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
function androidDeviceSelectorRefusal({ settingsContext, slot, systemImageFlag, deviceProfileFlag, systemImage, deviceProfile, physical, remoteBackend }, { listSystemImages = listInstalledSystemImages, listDeviceProfiles = listAvdDeviceProfiles, supportsFold = systemImageSupportsFold, ownedAvd = slotOwnedAvd } = {}) {
|
|
2350
|
+
const root = settingsContext.projectPath;
|
|
2047
2351
|
const settingsLayersForOrigin = settingsLayers(settingsContext);
|
|
2048
2352
|
const imageRefusal = systemImageRefusal({
|
|
2049
2353
|
slot,
|
|
@@ -2085,43 +2389,7 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
2085
2389
|
});
|
|
2086
2390
|
if (foldRefusal) return fail(foldRefusal.code, foldRefusal.message, foldRefusal.remedy);
|
|
2087
2391
|
}
|
|
2088
|
-
|
|
2089
|
-
kind: "physical",
|
|
2090
|
-
serial: typeof deviceFlag === "string" ? deviceFlag : null,
|
|
2091
|
-
lease: {
|
|
2092
|
-
waitSeconds,
|
|
2093
|
-
noWait
|
|
2094
|
-
}
|
|
2095
|
-
} : remoteBackend ? {
|
|
2096
|
-
kind: "remote",
|
|
2097
|
-
backend: remoteBackend,
|
|
2098
|
-
systemImage,
|
|
2099
|
-
deviceProfile
|
|
2100
|
-
} : {
|
|
2101
|
-
kind: "emulator",
|
|
2102
|
-
systemImage,
|
|
2103
|
-
deviceProfile
|
|
2104
|
-
};
|
|
2105
|
-
return {
|
|
2106
|
-
ok: true,
|
|
2107
|
-
plan: {
|
|
2108
|
-
build: {
|
|
2109
|
-
variant,
|
|
2110
|
-
release,
|
|
2111
|
-
profile: buildProfile,
|
|
2112
|
-
cas,
|
|
2113
|
-
cache: cachePolicy,
|
|
2114
|
-
compilerCache: optimizations.android.compilerCache,
|
|
2115
|
-
gradleBuildCache: optimizations.android.gradleBuildCache,
|
|
2116
|
-
pch: optimizations.android.pch,
|
|
2117
|
-
targetAbiOnly: optimizations.android.targetAbiOnly
|
|
2118
|
-
},
|
|
2119
|
-
target,
|
|
2120
|
-
isExpo,
|
|
2121
|
-
metroWarmup: optimizations.metroWarmup,
|
|
2122
|
-
cacheProviderConfig
|
|
2123
|
-
}
|
|
2124
|
-
};
|
|
2392
|
+
return null;
|
|
2125
2393
|
}
|
|
2126
2394
|
//#endregion
|
|
2127
2395
|
//#region src/commands/android/next-build.ts
|
|
@@ -2260,7 +2528,7 @@ async function planAndroid(opts, overrides = {}) {
|
|
|
2260
2528
|
if (target.kind === "physical") return refuse(planFlagRefusal("--device"));
|
|
2261
2529
|
return refuse({
|
|
2262
2530
|
code: "STIM_BAD_ARG",
|
|
2263
|
-
message: `android.remote routes this workspace's runs to a ${target.backend} device, whose ABI --plan cannot read without a session.`,
|
|
2531
|
+
message: `android.remote routes this workspace's runs to a ${target.kind === "hosted" ? target.machine : target.backend} device, whose ABI --plan cannot read without a session.`,
|
|
2264
2532
|
remedy: "Run `stim android` to build for the remote device, or unset android.remote to plan the owned emulator."
|
|
2265
2533
|
});
|
|
2266
2534
|
}
|
|
@@ -2316,10 +2584,10 @@ function androidCommand(program) {
|
|
|
2316
2584
|
registerAndroid(program);
|
|
2317
2585
|
}
|
|
2318
2586
|
function registerAndroid(program) {
|
|
2319
|
-
program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--build-machine <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device-profile <id>", "Hardware profile to create this workspace's owned AVD with, as an `avdmanager list device -c` id (e.g. \"pixel_fold\", \"pixel_tablet\"). Overrides the android.deviceProfile setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the available ids.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. Stim never creates, boots, or deletes a physical device.").option("--remote <
|
|
2320
|
-
if (
|
|
2321
|
-
|
|
2322
|
-
}).option("--wait <seconds>", "How long to wait for another workspace to release the device it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once).
|
|
2587
|
+
program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--build-machine <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device-profile <id>", "Hardware profile to create this workspace's owned AVD with, as an `avdmanager list device -c` id (e.g. \"pixel_fold\", \"pixel_tablet\"). Overrides the android.deviceProfile setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the available ids.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. Stim never creates, boots, or deletes a physical device.").option("--remote <target>", "Run on eas, proxy, or a named approved Mac from hosting.machines; auto places on an approved Mac when this Mac is full or busy", (value) => {
|
|
2588
|
+
if (!parseMachine(value)) throw new InvalidArgumentError("expected eas, proxy, auto, or a tailnet machine name");
|
|
2589
|
+
return value;
|
|
2590
|
+
}).option("--wait <seconds>", "How long to wait for another workspace to release the device it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once). Without --device, wait for an owned-device slot (default 600 seconds; --no-wait refuses immediately).").option("--no-wait", "Install on a device another workspace leases instead of waiting: this run takes no lease and, when both workspaces build the same app id, the install terminates the holder's running app. Without --device, refuse a full device cap or existing slot queue immediately.").action(async (opts) => {
|
|
2323
2591
|
if (opts.plan) return planAndroid(opts);
|
|
2324
2592
|
const root = findProjectRoot$1(process.cwd());
|
|
2325
2593
|
if (!root) {
|
|
@@ -2363,7 +2631,7 @@ function registerAndroid(program) {
|
|
|
2363
2631
|
}, { write: (line) => console.error(chalk.dim(phaseLine("lock", line))) })).ok) process.exit(runCancellation() ? 130 : 1);
|
|
2364
2632
|
});
|
|
2365
2633
|
}
|
|
2366
|
-
function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, deviceProfile: deviceProfileFlag, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, listDeviceProfiles, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, dataFreeBytes, trimCaches, wipeDevice, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState$1, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordBuild, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
2634
|
+
function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, deviceProfile: deviceProfileFlag, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, listDeviceProfiles, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, dataFreeBytes, trimCaches, wipeDevice, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState$1, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordBuild, recordStats = recordRunStats, recordCapacityRefusal: recordRefusal, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
2367
2635
|
return {
|
|
2368
2636
|
root,
|
|
2369
2637
|
json,
|
|
@@ -2447,6 +2715,7 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
|
|
|
2447
2715
|
writeState,
|
|
2448
2716
|
recordBuild,
|
|
2449
2717
|
recordStats,
|
|
2718
|
+
recordCapacityRefusal: recordRefusal,
|
|
2450
2719
|
readEstimates,
|
|
2451
2720
|
now,
|
|
2452
2721
|
out,
|
|
@@ -2489,6 +2758,11 @@ function androidSlotOptions(options) {
|
|
|
2489
2758
|
function avdSetupFailure(error, root, logFile) {
|
|
2490
2759
|
const refusal = (0, ownership_claim_exports.claimFailure)(error, "stim android");
|
|
2491
2760
|
if (refusal) return refusal;
|
|
2761
|
+
if (error instanceof DeviceAdmissionRefusal) return {
|
|
2762
|
+
code: error.code,
|
|
2763
|
+
message: error.message,
|
|
2764
|
+
remedy: error.remedy
|
|
2765
|
+
};
|
|
2492
2766
|
const diag = noDeviceDiagnostic({
|
|
2493
2767
|
reason: `Could not ensure an owned Android emulator: ${error?.message || error}`,
|
|
2494
2768
|
logFile,
|
|
@@ -2506,7 +2780,7 @@ function avdSetupFailure(error, root, logFile) {
|
|
|
2506
2780
|
};
|
|
2507
2781
|
}
|
|
2508
2782
|
async function runAndroid(options = {}) {
|
|
2509
|
-
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceProfileFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, listDeviceProfiles, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, dataFreeBytes, trimCaches, wipeDevice, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordBuild, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
|
|
2783
|
+
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceProfileFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, listDeviceProfiles, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, dataFreeBytes, trimCaches, wipeDevice, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordBuild, recordStats, recordCapacityRefusal: recordRefusal = recordCapacityRefusal, readEstimates, now, out, emit } = androidSlotOptions(options);
|
|
2510
2784
|
const progress = options.progress ?? NO_BUILD_PROGRESS;
|
|
2511
2785
|
const slot = validateDeviceSlot(options.slot);
|
|
2512
2786
|
const started = now();
|
|
@@ -2552,7 +2826,7 @@ async function runAndroid(options = {}) {
|
|
|
2552
2826
|
}
|
|
2553
2827
|
};
|
|
2554
2828
|
}
|
|
2555
|
-
const logsDir = workspaceLogsDir(root);
|
|
2829
|
+
const logsDir = workspaceLogsDir$1(root);
|
|
2556
2830
|
const buildLog = join(logsDir, `build-${deviceSlotFileKey("android", slot)}.ndjson`);
|
|
2557
2831
|
const writer = tapBuildLog(createWriter(buildLog, {
|
|
2558
2832
|
truncate: true,
|
|
@@ -2612,6 +2886,7 @@ async function runAndroid(options = {}) {
|
|
|
2612
2886
|
code,
|
|
2613
2887
|
message,
|
|
2614
2888
|
remedy: remedy ?? null,
|
|
2889
|
+
...record.devicePlacement ? { devicePlacement: record.devicePlacement } : {},
|
|
2615
2890
|
...ccacheActivity.status === "not-run" ? {} : { ccache: ccacheActivity },
|
|
2616
2891
|
...lease === void 0 ? {} : { lease },
|
|
2617
2892
|
...reclaimed.length ? { reclaimed } : {}
|
|
@@ -2673,16 +2948,59 @@ async function runAndroid(options = {}) {
|
|
|
2673
2948
|
});
|
|
2674
2949
|
if (!planned.ok) return fail(planned.code, planned.message, planned.remedy, { lines: planned.lines });
|
|
2675
2950
|
const { plan } = planned;
|
|
2676
|
-
const
|
|
2951
|
+
const deviceSlotWait = {
|
|
2952
|
+
signal: runCancellationSignal(),
|
|
2953
|
+
waitMs: plan.deviceSlotWaitMs,
|
|
2954
|
+
displayName: basename(root),
|
|
2955
|
+
waitingFor: (info) => progress.waitingFor(info, "device-slot"),
|
|
2956
|
+
onWait: (ms) => {
|
|
2957
|
+
stats.addDeviceSlotWaitMs(ms);
|
|
2958
|
+
if (record.devicePlacement?.decision === "local" && ms > 0) record.devicePlacement.decision = "waited-locally";
|
|
2959
|
+
}
|
|
2960
|
+
};
|
|
2961
|
+
const { build: buildPlan, isExpo, cacheProviderConfig } = plan;
|
|
2677
2962
|
const { variant, release, cache: cachePolicy } = buildPlan;
|
|
2678
2963
|
record.configuration = variant ?? "debug";
|
|
2679
2964
|
const useBuildCache = cachePolicy.read;
|
|
2680
|
-
const
|
|
2681
|
-
const remoteBackend = target.kind === "remote" ? target.backend : null;
|
|
2682
|
-
const budget = await (options.checkBudget ?? budgetGate)({
|
|
2965
|
+
const hosting = await selectAndroidPlacement({
|
|
2683
2966
|
root,
|
|
2684
|
-
|
|
2967
|
+
slot,
|
|
2968
|
+
target: plan.target,
|
|
2969
|
+
release,
|
|
2970
|
+
metroCheck,
|
|
2971
|
+
noWait: plan.deviceSlotWaitMs === 0,
|
|
2972
|
+
buildMachine: options.buildMachine,
|
|
2973
|
+
read: options.readHostedAndroid,
|
|
2974
|
+
resolveSerial: resolveAvdSerial,
|
|
2975
|
+
prepare: options.prepareHostedAndroid,
|
|
2976
|
+
automatic: options.automaticDevicePlacement,
|
|
2977
|
+
localSelectors: (target) => androidDeviceSelectorRefusal({
|
|
2978
|
+
settingsContext,
|
|
2979
|
+
slot,
|
|
2980
|
+
systemImageFlag,
|
|
2981
|
+
deviceProfileFlag,
|
|
2982
|
+
systemImage: target.systemImage,
|
|
2983
|
+
deviceProfile: target.deviceProfile,
|
|
2984
|
+
physical: false,
|
|
2985
|
+
remoteBackend: null
|
|
2986
|
+
}, {
|
|
2987
|
+
listSystemImages,
|
|
2988
|
+
listDeviceProfiles
|
|
2989
|
+
}),
|
|
2990
|
+
checkBudget: options.checkBudget,
|
|
2991
|
+
note: out,
|
|
2992
|
+
phase
|
|
2685
2993
|
});
|
|
2994
|
+
if ("failure" in hosting) return fail(hosting.failure.code, hosting.failure.message, hosting.failure.remedy);
|
|
2995
|
+
const { target, hostedTarget, budget, selectors } = hosting;
|
|
2996
|
+
record.devicePlacement = hosting.devicePlacement;
|
|
2997
|
+
writeDevicePlacement(root, slot, PLATFORM, record.devicePlacement);
|
|
2998
|
+
const physical = target.kind === "physical";
|
|
2999
|
+
const remoteBackend = target.kind === "remote" ? target.backend : null;
|
|
3000
|
+
if (hostedTarget) {
|
|
3001
|
+
if (settings.androidEmulatorApp !== void 0) phase("device", "androidEmulatorApp is ignored on a hosting Mac; the emulator boots headless.");
|
|
3002
|
+
if (publicUrlSetting(settings) || tunnelModeSetting(settings)) phase("metro", "metro.publicUrl and metro.tunnel are ignored on a hosting Mac; Metro uses the private tailnet bridge.");
|
|
3003
|
+
}
|
|
2686
3004
|
reclaimed = budget.reclaimed;
|
|
2687
3005
|
if (budget.refusal) return fail(budget.refusal.code, budget.refusal.message, budget.refusal.remedy);
|
|
2688
3006
|
const remoteContext = remoteBackend ? await resolveRemoteDeviceContext({
|
|
@@ -2725,7 +3043,7 @@ async function runAndroid(options = {}) {
|
|
|
2725
3043
|
const gate = await ensureDevServer({
|
|
2726
3044
|
root,
|
|
2727
3045
|
port: reservedPort,
|
|
2728
|
-
settings,
|
|
3046
|
+
settings: hostedMetroSettings(settings, Boolean(hostedTarget)),
|
|
2729
3047
|
remote: remoteContext !== null,
|
|
2730
3048
|
note: out,
|
|
2731
3049
|
resolve: resolveMetro,
|
|
@@ -2779,7 +3097,14 @@ async function runAndroid(options = {}) {
|
|
|
2779
3097
|
let bootDuration = "";
|
|
2780
3098
|
let bootPromise;
|
|
2781
3099
|
let startRemoteBoot = null;
|
|
2782
|
-
if (
|
|
3100
|
+
if (hostedTarget) {
|
|
3101
|
+
device = {
|
|
3102
|
+
owned: false,
|
|
3103
|
+
systemImage: hostedTarget.choice.systemImage,
|
|
3104
|
+
deviceProfile: hostedTarget.choice.deviceProfile
|
|
3105
|
+
};
|
|
3106
|
+
bootPromise = Promise.resolve({ ok: true });
|
|
3107
|
+
} else if (target.kind === "physical" && !target.serial) {
|
|
2783
3108
|
const pooled = await pooledAndroidDevice({
|
|
2784
3109
|
root,
|
|
2785
3110
|
selectPool,
|
|
@@ -2815,12 +3140,19 @@ async function runAndroid(options = {}) {
|
|
|
2815
3140
|
} catch (err) {
|
|
2816
3141
|
return fail("STIM_BAD_ARG", err.message, "Run `stim settings set androidEmulatorApp emulator` or `stim settings set androidEmulatorApp stim-desktop`.");
|
|
2817
3142
|
}
|
|
2818
|
-
const capacity = checkCapacity({
|
|
3143
|
+
const capacity = plan.deviceSlotWaitMs === 0 ? checkCapacity({
|
|
2819
3144
|
platform: PLATFORM,
|
|
2820
3145
|
project,
|
|
2821
3146
|
max: limits.maxDevices
|
|
2822
|
-
});
|
|
2823
|
-
if (capacity)
|
|
3147
|
+
}) : null;
|
|
3148
|
+
if (capacity) {
|
|
3149
|
+
if (capacity.code === "STIM_AT_CAPACITY") recordRefusal({
|
|
3150
|
+
platform: PLATFORM,
|
|
3151
|
+
max: limits.maxDevices,
|
|
3152
|
+
workspace: workspaceId(root)
|
|
3153
|
+
}, now());
|
|
3154
|
+
return fail(capacity.code, capacity.message, capacity.remedy);
|
|
3155
|
+
}
|
|
2824
3156
|
const prepare = stepClock(now);
|
|
2825
3157
|
try {
|
|
2826
3158
|
device = await ensureDevice({
|
|
@@ -2830,6 +3162,7 @@ async function runAndroid(options = {}) {
|
|
|
2830
3162
|
settingsRoot,
|
|
2831
3163
|
settings,
|
|
2832
3164
|
flags: {
|
|
3165
|
+
deviceSlotWait,
|
|
2833
3166
|
systemImage: target.systemImage,
|
|
2834
3167
|
systemImageFlag: systemImageFlag?.trim() || null,
|
|
2835
3168
|
deviceProfile: target.deviceProfile
|
|
@@ -2849,6 +3182,7 @@ async function runAndroid(options = {}) {
|
|
|
2849
3182
|
platform: PLATFORM,
|
|
2850
3183
|
device,
|
|
2851
3184
|
projectPath: root,
|
|
3185
|
+
deviceSlotWait,
|
|
2852
3186
|
out,
|
|
2853
3187
|
logFile: emuLog
|
|
2854
3188
|
})).catch((e) => ({
|
|
@@ -2898,6 +3232,7 @@ async function runAndroid(options = {}) {
|
|
|
2898
3232
|
isExpo,
|
|
2899
3233
|
device,
|
|
2900
3234
|
physical,
|
|
3235
|
+
hostedAbi: hostedTarget?.choice.architecture,
|
|
2901
3236
|
remote: Boolean(remoteDevice),
|
|
2902
3237
|
buildPlan,
|
|
2903
3238
|
cacheProviderConfig,
|
|
@@ -2915,7 +3250,8 @@ async function runAndroid(options = {}) {
|
|
|
2915
3250
|
miss: progress.miss,
|
|
2916
3251
|
hit: progress.hit,
|
|
2917
3252
|
place: progress.place,
|
|
2918
|
-
waitingOn: progress.waitingOn
|
|
3253
|
+
waitingOn: progress.waitingOn,
|
|
3254
|
+
waitingFor: progress.waitingFor
|
|
2919
3255
|
}
|
|
2920
3256
|
}, {
|
|
2921
3257
|
deviceAbi,
|
|
@@ -2954,6 +3290,40 @@ async function runAndroid(options = {}) {
|
|
|
2954
3290
|
androidPackage = artifact.androidPackage;
|
|
2955
3291
|
record.appPath = apkPath;
|
|
2956
3292
|
if (runCancellation()) return fail("STIM_CANCELLED", "before install");
|
|
3293
|
+
if (hostedTarget) return finishHostedAndroidRun({
|
|
3294
|
+
target: hostedTarget,
|
|
3295
|
+
artifact,
|
|
3296
|
+
root,
|
|
3297
|
+
slot,
|
|
3298
|
+
release,
|
|
3299
|
+
isExpo,
|
|
3300
|
+
metroPort,
|
|
3301
|
+
logsDir,
|
|
3302
|
+
selectors,
|
|
3303
|
+
place: options.placeHostedAndroid ?? placeHostedAndroid,
|
|
3304
|
+
writePlacement: options.writeHostedAndroid ?? writeHostedAndroid,
|
|
3305
|
+
verifyLaunch: verifyLaunched,
|
|
3306
|
+
writeLaunch,
|
|
3307
|
+
readApkPackage,
|
|
3308
|
+
resolveDevClientScheme,
|
|
3309
|
+
now,
|
|
3310
|
+
started,
|
|
3311
|
+
startedAt,
|
|
3312
|
+
record,
|
|
3313
|
+
fail,
|
|
3314
|
+
phase,
|
|
3315
|
+
out,
|
|
3316
|
+
json,
|
|
3317
|
+
useBuildCache,
|
|
3318
|
+
variant,
|
|
3319
|
+
metroCheck,
|
|
3320
|
+
writer,
|
|
3321
|
+
emit,
|
|
3322
|
+
recordRun,
|
|
3323
|
+
reclaimed,
|
|
3324
|
+
devServer,
|
|
3325
|
+
recordBuild
|
|
3326
|
+
});
|
|
2957
3327
|
if (startRemoteBoot) {
|
|
2958
3328
|
progress.step("device");
|
|
2959
3329
|
bootPromise = startRemoteBoot();
|
|
@@ -3082,6 +3452,7 @@ async function runAndroid(options = {}) {
|
|
|
3082
3452
|
serial: void 0
|
|
3083
3453
|
},
|
|
3084
3454
|
projectPath: root,
|
|
3455
|
+
deviceSlotWait,
|
|
3085
3456
|
out,
|
|
3086
3457
|
logFile: emuLog
|
|
3087
3458
|
})).catch((e) => ({
|