stim 1.2.0 → 1.3.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 +30 -0
- package/dist/android-BqVIJoG7.mjs +1368 -0
- package/dist/{android-Bcmev2s2.mjs → android-CqcW1hrP.mjs} +148 -56
- package/dist/{android-cas-D6HPZ6UQ.mjs → android-cas-BR5YJBYv.mjs} +5 -5
- package/dist/{app-install-NFxUahnH.mjs → app-install-DIp9riNx.mjs} +6 -6
- package/dist/{build-slots-D0b6sJyo.mjs → build-slots-C3-R4XQr.mjs} +2 -2
- package/dist/{cache-manifest-Cu4_Znw9.mjs → cache-manifest-CXR-Y8pH.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +13 -13
- package/dist/collector-run.d.mts +3 -1
- package/dist/collector-run.mjs +33 -8
- package/dist/{config-CMtIaTk9.mjs → config-CcefMY2Q.mjs} +93 -12
- package/dist/{deps-BLBsTNDS.mjs → deps-Spz8ozgo.mjs} +1 -1
- package/dist/{dev-client-RpvXxCXV.mjs → dev-client-BjisHDB5.mjs} +186 -9
- package/dist/{device-CoCPmazS.mjs → device-BkiW-gkk.mjs} +19 -11
- package/dist/{device-lease-Dpik41RY.mjs → device-lease-BJYybF-2.mjs} +107 -83
- package/dist/{device-pool-B5pEVa3t.mjs → device-pool-CPbLGfrB.mjs} +18 -12
- package/dist/{device-remote-E81KAdXf.mjs → device-remote-AkYCKS8U.mjs} +7 -7
- package/dist/{doctor-CqPeMsSm.mjs → doctor-Bmv86UUW.mjs} +11 -12
- package/dist/{doctor-D_CX7ib5.mjs → doctor-fAMXC4vl.mjs} +4 -4
- package/dist/{error-diagnostics-Dw8Gn3yw.mjs → error-diagnostics-DHC31rXA.mjs} +62 -52
- package/dist/{gc-B7KkDinF.mjs → gc-GGu-8ULN.mjs} +66 -57
- package/dist/{guide-BS2Xc24o.mjs → guide-92CPA21s.mjs} +196 -13
- package/dist/{ios-B7KLgIp5.mjs → ios-BSXFeO5H.mjs} +183 -54
- package/dist/{ios-D1h1Di39.mjs → ios-Deh5js5V.mjs} +78 -40
- package/dist/{ios-device-xNt0Lg6v.mjs → ios-device-CWOM_S44.mjs} +1 -1
- package/dist/{logs-DcX9AvRF.mjs → logs-DPNF4C9s.mjs} +9 -6
- package/dist/{logs-query-oqn47Ffx.mjs → logs-query-R-Cqc6Qv.mjs} +22 -5
- package/dist/{metro-COslRK_F.mjs → metro-CORqXyTL.mjs} +2 -2
- package/dist/{ndjson-DcAtEx_K.mjs → ndjson-BZwI1NBv.mjs} +5 -2
- package/dist/{ownership-CGPart6T.mjs → ownership-8O073GIC.mjs} +3 -3
- package/dist/{ownership-CYOyqxUo.mjs → ownership-BpCKiRlQ.mjs} +3 -3
- package/dist/{ownership-claim-7zRxxTfZ.mjs → ownership-claim-Bf2CAfw3.mjs} +4 -3
- package/dist/{project-BBTVABUz.mjs → project-fKmuIaMI.mjs} +2 -2
- package/dist/{reclaim-C5Jmuahx.mjs → reclaim-iW9Cad7k.mjs} +80 -74
- package/dist/{reload-Z8nKifAk.mjs → reload-DazHDSFA.mjs} +32 -24
- package/dist/{server-bare-DEk37Mz2.mjs → server-bare-DEzPZLvf.mjs} +2 -2
- package/dist/server-expo-44em5Pmg.mjs +2 -0
- package/dist/{server-expo-C3ktAwUG.mjs → server-expo-DizT4OMk.mjs} +4 -4
- package/dist/{settings-DwU1_U_q.mjs → settings-DEJf6_kJ.mjs} +2 -2
- package/dist/slot-launch-cci0xvmC.mjs +19 -0
- package/dist/{start-BrY4EuIg.mjs → start-mObjQH2W.mjs} +11 -11
- package/dist/{state-CZ-ER-8d.mjs → state-B3XA2wp2.mjs} +9 -9
- package/dist/{stats-BCWEVLrM.mjs → stats-BR-kwj0B.mjs} +1 -1
- package/dist/{stats-BsF15Bti.mjs → stats-CaaQr4yN.mjs} +3 -3
- package/dist/{status-DFI1Hfpg.mjs → status-BxQNqu9t.mjs} +55 -24
- package/dist/{stop-B7DR4awK.mjs → stop-CrHGcjrV.mjs} +2 -2
- package/dist/{stop-Btg770vV.mjs → stop-DimGXEKY.mjs} +93 -42
- package/dist/supervisor-run.d.mts +1 -2
- package/dist/supervisor-run.mjs +5 -5
- package/dist/{remote-cache-DDmJ1Roq.mjs → teardown-ClFp1Aax.mjs} +887 -888
- package/dist/{workspace-process-lock-BKfdys1q.mjs → workspace-process-lock-3NcQnZ0X.mjs} +1 -1
- package/dist/{worktree-BPTbI-LN.mjs → worktree-DxTgN1CJ.mjs} +12 -12
- package/dist/{worktree-C79xx_kM.mjs → worktree-Eq6TLH8N.mjs} +1 -1
- package/dist/{xcode-DeKCribl.mjs → xcode-D7sAp-Zy.mjs} +82 -56
- package/package.json +5 -5
- package/dist/android-K63_0UfF.mjs +0 -727
- package/dist/build-lock-BsVoLDaq.mjs +0 -645
- package/dist/server-expo-Drd7ksHu.mjs +0 -2
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { C as withConfigLock, S as upsertProject, b as setDevice, f as getProject, g as loadConfig, l as getConcurrencyLimits, y as saveConfig } from "./config-
|
|
3
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
4
|
-
import { D as workspaceLogsDir, T as workspaceDir, _ as writeWorkspaceState, g as writeWorkspaceLaunch, n as MODE_EXPO, p as readWorkspaceState, t as MODE_BARE, v as emulatorLogFile } from "./state-
|
|
5
|
-
import { C as removeTemporaryEntry, S as makeTemporaryDirectory, g as repoRoot, s as gitCommonDir } from "./worktree-
|
|
6
|
-
import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, n as detectAndroidPackage, r as detectBundleId, t as appProjectProblem } from "./project-
|
|
2
|
+
import { C as withConfigLock, I as deviceSlotKey, L as deviceSlotPlatforms, S as upsertProject, V as validateDeviceSlot, b as setDevice, f as getProject, g as loadConfig, l as getConcurrencyLimits, y as saveConfig } from "./config-CcefMY2Q.mjs";
|
|
3
|
+
import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
|
|
4
|
+
import { D as workspaceLogsDir, T as workspaceDir, _ as writeWorkspaceState, g as writeWorkspaceLaunch, n as MODE_EXPO, p as readWorkspaceState, t as MODE_BARE, v as emulatorLogFile } from "./state-B3XA2wp2.mjs";
|
|
5
|
+
import { C as removeTemporaryEntry, S as makeTemporaryDirectory, g as repoRoot, s as gitCommonDir } from "./worktree-Eq6TLH8N.mjs";
|
|
6
|
+
import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, n as detectAndroidPackage, r as detectBundleId, t as appProjectProblem } from "./project-fKmuIaMI.mjs";
|
|
7
7
|
import { r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
|
|
8
|
-
import { i as resolveProjectMetro, r as pidExists } from "./metro-
|
|
9
|
-
import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-
|
|
10
|
-
import { a as easAuthNote, c as loadProjectProvider, d as resolveEasCliBin, f as resolveRemote, i as checkEasAuth, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as uploadRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
|
|
11
|
-
import { A as resolveSettings, B as artifactCachePolicy, D as remoteDeviceSettingError, E as remoteAndroidSetting, F as tunnelModeSetting, H as optimizationBuildProfile, I as unknownSettingKeys, N as settingShapeErrors, R as detectProviders, T as publicUrlSetting, U as resolveOptimizations, V as compilerCacheFallbackMessage, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, j as settingFile, k as resolveCacheProviderConfig, r as REMOTE_DEVICE_BACKENDS, s as androidAvdConfigSettingError, u as androidDataPartitionSizeGbSettingError, x as metroWarmupUrlSetting } from "./settings-DwU1_U_q.mjs";
|
|
8
|
+
import { i as resolveProjectMetro, r as pidExists } from "./metro-CORqXyTL.mjs";
|
|
9
|
+
import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-8O073GIC.mjs";
|
|
12
10
|
import { _ as launchErrorPreview, c as launchErrorReport, g as stepTimer, h as stepClock, i as formatDuration, l as phaseLine, n as appReadinessMessage, p as shortHash } from "./command-output-8wHMEde0.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import { C as
|
|
15
|
-
import { r as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { c as ensureWorkspaceStorageSafely, d as
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { t as
|
|
24
|
-
import {
|
|
11
|
+
import { r as claimFailure } from "./ownership-claim-Bf2CAfw3.mjs";
|
|
12
|
+
import { $ as providerDownloadPath, C as memoizeEmulatorProbe, G as buildCacheKey, J as filesystemBuildCapability, K as describeFingerprintMiss, L as waitForBoot, M as resetAdoptedAvd, N as resolveOwnedAvdSerial, P as resolvePhysicalDevice, Q as prepareProviderDownloadDir, R as WAIT_CEILING_MS, U as takeoverLine, V as releaseBuildLock, W as waitForBuild, X as fingerprintDiffSuffix, Y as fingerprintDiffRecord, Z as fingerprintProject, _ as findBuildTool, a as androidSystemImageAbi, at as untrackedMissLine, ct as captureAssetManifest, et as providerUploadOutcome, g as extractEmulatorFailure, h as emulatorFailureRemedy, i as androidPoolNoCandidatesRefusal, it as storedAssetManifest, j as probeEmulatorSerial, k as physicalDeviceModel, lt as compareAssetManifests, m as emulatorDiskSpaceRemedy, n as androidHome, nt as resolveBuild, ot as untrackedNativeFiles, r as androidPoolCandidates, rt as storeBuild, st as assetDiffReason, t as androidDeviceAbi, tt as refingerprintAfterMutation, ut as readAssetManifest, x as listInstalledSystemImages, y as listAdbDevices, z as acquireBuildLock } from "./android-BqVIJoG7.mjs";
|
|
13
|
+
import { A as resolveSettings, B as artifactCachePolicy, D as remoteDeviceSettingError, E as remoteAndroidSetting, F as tunnelModeSetting, H as optimizationBuildProfile, I as unknownSettingKeys, N as settingShapeErrors, R as detectProviders, T as publicUrlSetting, U as resolveOptimizations, V as compilerCacheFallbackMessage, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, j as settingFile, k as resolveCacheProviderConfig, r as REMOTE_DEVICE_BACKENDS, s as androidAvdConfigSettingError, u as androidDataPartitionSizeGbSettingError, x as metroWarmupUrlSetting } from "./settings-DEJf6_kJ.mjs";
|
|
14
|
+
import { t as cleanLine } from "./server-expo-DizT4OMk.mjs";
|
|
15
|
+
import { C as uploadRemote, S as resolveRemote, _ as isEasAuthFailureText, c as parkedMaxSetting, d as RESOLVE_TIMEOUT_MS, f as UPLOAD_TIMEOUT_MS, g as exitAfterFlush, h as easAuthNote, m as checkEasAuth, p as cacheLevel, v as loadProjectProvider, x as resolveEasCliBin } from "./teardown-ClFp1Aax.mjs";
|
|
16
|
+
import { c as ensureWorkspaceStorageSafely, d as launchOutcomeRecord, f as noMetroMessage, g as warmMetro, i as detectEntryFile, m as resolveMetroWithRetry, n as pickDevClientScheme, o as needsPrebuild, p as noMetroRemedy, s as runPrebuild, t as devClientScheme, u as isPhysicalDeviceRequest, v as isEasBuildFailure, y as resolveEasDevelopmentBuild } from "./dev-client-BjisHDB5.mjs";
|
|
17
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-3NcQnZ0X.mjs";
|
|
18
|
+
import { D as verifyAndroidReleaseLaunch, E as unverifiedLaunchLines, O as verifyLaunch, S as launchAndroidReleaseApp, _ as installConflictKind, c as RELEASE_VERIFY_WAIT_MS, d as androidDevClientUrl, g as installAndroidApp, h as deviceShellArg, i as LAUNCH_BUNDLING, l as VERIFY_TIMEOUT_MS, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, t as ADB_INSTALL_TIMEOUT_MS, u as androidAppProcess, x as launchAndroidApp } from "./app-install-DIp9riNx.mjs";
|
|
19
|
+
import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-CPbLGfrB.mjs";
|
|
20
|
+
import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-C3-R4XQr.mjs";
|
|
21
|
+
import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BR-kwj0B.mjs";
|
|
22
|
+
import { C as unknownAndroidSystemImageRefusal, _ as AvdRecoveryError, b as ensureBooted, f as startBuildHeartbeat, p as tailLines, r as HEARTBEAT_INTERVAL_MS, v as checkDeviceCapacity, x as ensureOwnedDevice } from "./xcode-D7sAp-Zy.mjs";
|
|
23
|
+
import { a as ensureMetroReachable, b as ownedSessionName, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, s as remoteAndroidDeps } from "./device-remote-AkYCKS8U.mjs";
|
|
24
|
+
import { a as buildAndroid, c as CCACHE_NOT_RUN, f as resolveCcache, l as CCACHE_UNAVAILABLE, n as resolveAndroidCas, o as productFlavorRefusal, p as formatDiagnostic, r as resolveAndroidCompilerCache, s as readProductFlavors, u as ccacheActivityLine } from "./android-cas-BR5YJBYv.mjs";
|
|
25
|
+
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-cci0xvmC.mjs";
|
|
25
26
|
import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
|
|
26
|
-
import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-
|
|
27
|
+
import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-DHC31rXA.mjs";
|
|
27
28
|
import { existsSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
28
29
|
import { InvalidArgumentError } from "commander";
|
|
29
30
|
import { basename, dirname, join, relative } from "node:path";
|
|
30
|
-
import chalk from "chalk";
|
|
31
31
|
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
32
|
+
import chalk from "chalk";
|
|
32
33
|
//#region src/engine/apk-swap.ts
|
|
33
34
|
const ANDROID_BUNDLE_NAME = "index.android.bundle";
|
|
34
35
|
const ANDROID_BUNDLE_ENTRY = `assets/${ANDROID_BUNDLE_NAME}`;
|
|
@@ -399,7 +400,12 @@ function androidSystemImageSetting(settings) {
|
|
|
399
400
|
function resolveSystemImage(flag, settings) {
|
|
400
401
|
return (typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null) || androidSystemImageSetting(settings);
|
|
401
402
|
}
|
|
402
|
-
function systemImageRefusal({ flag, resolved, physical, remoteBackend, listImages }) {
|
|
403
|
+
function systemImageRefusal({ slot, flag, resolved, physical, remoteBackend, listImages }) {
|
|
404
|
+
if (slot && slot !== "default" && remoteBackend) return {
|
|
405
|
+
code: "STIM_BAD_ARG",
|
|
406
|
+
message: "Named slots currently support local simulators and physical devices.",
|
|
407
|
+
remedy: "Use the default slot for a remote session."
|
|
408
|
+
};
|
|
403
409
|
if (typeof flag === "string" && flag.trim() === "") return {
|
|
404
410
|
code: "STIM_BAD_ARG",
|
|
405
411
|
message: "--system-image was given an empty id.",
|
|
@@ -624,9 +630,10 @@ function androidBuildOptions({ release, physical, device, variant, deviceAbi, co
|
|
|
624
630
|
}
|
|
625
631
|
//#endregion
|
|
626
632
|
//#region src/commands/android/result.ts
|
|
627
|
-
function androidFacts({ serial, avdName = null, deviceName = null, systemImage = 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 }) {
|
|
633
|
+
function androidFacts({ slot, serial, avdName = null, deviceName = null, systemImage = 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 }) {
|
|
628
634
|
return {
|
|
629
635
|
platform: PLATFORM,
|
|
636
|
+
...slot && slot !== "default" ? { slot } : {},
|
|
630
637
|
serial: serial ?? null,
|
|
631
638
|
avdName: avdName ?? null,
|
|
632
639
|
deviceName: deviceName ?? avdName ?? null,
|
|
@@ -689,7 +696,7 @@ async function finishAndroidUpload(uploadPending, remote, phase) {
|
|
|
689
696
|
}
|
|
690
697
|
return false;
|
|
691
698
|
}
|
|
692
|
-
function reportAndroidResult({ json, useBuildCache, variant, release, metroCheck, metroPort, logsDir, serial, apkPath, androidPackage, installSkipped, record, waitedForBuild, remote, providerName, launchState, launchWarning, launched, ccache, durationMs, writer, emit, lease, recordRun }) {
|
|
699
|
+
function reportAndroidResult({ 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 }) {
|
|
693
700
|
recordRun({
|
|
694
701
|
failed: false,
|
|
695
702
|
cacheHit: cacheLevel(record.cacheHit),
|
|
@@ -697,6 +704,7 @@ function reportAndroidResult({ json, useBuildCache, variant, release, metroCheck
|
|
|
697
704
|
durationMs
|
|
698
705
|
});
|
|
699
706
|
const facts = androidFacts({
|
|
707
|
+
slot,
|
|
700
708
|
serial,
|
|
701
709
|
avdName: record.avdName,
|
|
702
710
|
deviceName: record.deviceName,
|
|
@@ -765,18 +773,18 @@ function persistLastBuild({ writeState, root, record, startedAt, durationMs, sta
|
|
|
765
773
|
function collectorEntry() {
|
|
766
774
|
return spawnEntry("collector-run");
|
|
767
775
|
}
|
|
768
|
-
function collectorLogFile(root) {
|
|
769
|
-
return join(workspaceLogsDir(root), `collector-${PLATFORM}.log`);
|
|
776
|
+
function collectorLogFile(root, slot = "default") {
|
|
777
|
+
return join(workspaceLogsDir(root), `collector-${deviceSlotKey(PLATFORM, slot)}.log`);
|
|
770
778
|
}
|
|
771
779
|
const COLLECTOR_EXIT_WAIT_MS = 2e3;
|
|
772
780
|
const COLLECTOR_POLL_MS = 25;
|
|
773
|
-
function killPreviousCollector(root, { platform = PLATFORM, kill = (pid, signal) => process.kill(pid, signal), collectors = null, verify = verifyCollectorOwnership, isAlive = pidExists, note = (_line) => {} } = {}) {
|
|
774
|
-
const record = (collectors ?? readCollectors(root))?.[platform];
|
|
781
|
+
function killPreviousCollector(root, { platform = PLATFORM, slot = "default", kill = (pid, signal) => process.kill(pid, signal), collectors = null, verify = verifyCollectorOwnership, isAlive = pidExists, note = (_line) => {} } = {}) {
|
|
782
|
+
const record = (collectors ?? readCollectors(root))?.[deviceSlotKey(platform, slot)];
|
|
775
783
|
const pid = Number(record?.pid);
|
|
776
784
|
if (!Number.isFinite(pid) || pid <= 0 || pid === process.pid) return null;
|
|
777
785
|
const ownership = verify({
|
|
778
786
|
pid,
|
|
779
|
-
platform,
|
|
787
|
+
platform: deviceSlotKey(platform, slot),
|
|
780
788
|
root,
|
|
781
789
|
isAlive,
|
|
782
790
|
expected: record
|
|
@@ -793,8 +801,9 @@ function killPreviousCollector(root, { platform = PLATFORM, kill = (pid, signal)
|
|
|
793
801
|
return null;
|
|
794
802
|
}
|
|
795
803
|
}
|
|
796
|
-
async function startCollector({ root, serial, packageName, spawn, kill, alive = pidExists, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), out }) {
|
|
804
|
+
async function startCollector({ root, slot = "default", serial, packageName, spawn, kill, alive = pidExists, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), out }) {
|
|
797
805
|
const previousPid = killPreviousCollector(root, {
|
|
806
|
+
slot,
|
|
798
807
|
kill,
|
|
799
808
|
isAlive: alive,
|
|
800
809
|
verify,
|
|
@@ -807,7 +816,7 @@ async function startCollector({ root, serial, packageName, spawn, kill, alive =
|
|
|
807
816
|
let stdio = "ignore";
|
|
808
817
|
try {
|
|
809
818
|
mkdirSync(workspaceLogsDir(root), { recursive: true });
|
|
810
|
-
const fd = openSync(collectorLogFile(root), "a");
|
|
819
|
+
const fd = openSync(collectorLogFile(root, slot), "a");
|
|
811
820
|
stdio = [
|
|
812
821
|
"ignore",
|
|
813
822
|
fd,
|
|
@@ -821,6 +830,7 @@ async function startCollector({ root, serial, packageName, spawn, kill, alive =
|
|
|
821
830
|
PLATFORM,
|
|
822
831
|
"--root",
|
|
823
832
|
root,
|
|
833
|
+
...slot === "default" ? [] : ["--slot", slot],
|
|
824
834
|
"--serial",
|
|
825
835
|
serial,
|
|
826
836
|
"--package",
|
|
@@ -840,9 +850,14 @@ async function startCollector({ root, serial, packageName, spawn, kill, alive =
|
|
|
840
850
|
}
|
|
841
851
|
//#endregion
|
|
842
852
|
//#region src/commands/android/launch.ts
|
|
843
|
-
async function verifyAndroidRun({ root, release, remoteRelease, remoteDevice, verifyReleaseLaunched, verifyLaunched, serial, androidPackage, variant, metroCheck, logsDir, launchedAt, metroPort, isExpo, physical, device, scheme, component = null, phase }) {
|
|
853
|
+
async function verifyAndroidRun({ root, slot, release, remoteRelease, remoteDevice, verifyReleaseLaunched, verifyLaunched, serial, androidPackage, variant, metroCheck, logsDir, launchedAt, metroPort, isExpo, physical, device, scheme, component = null, phase }) {
|
|
854
|
+
const runCommand = nativeRunCommand("android", slot, {
|
|
855
|
+
physical,
|
|
856
|
+
deviceId: serial
|
|
857
|
+
});
|
|
844
858
|
const readNativeCrashes = () => remoteDevice ? [] : captureNativeCrashes({
|
|
845
859
|
root,
|
|
860
|
+
slot,
|
|
846
861
|
platform: "android",
|
|
847
862
|
deviceId: serial,
|
|
848
863
|
appId: androidPackage,
|
|
@@ -878,6 +893,7 @@ async function verifyAndroidRun({ root, release, remoteRelease, remoteDevice, ve
|
|
|
878
893
|
const verification = metroCheck ? await verifyLaunched({
|
|
879
894
|
timeoutMs,
|
|
880
895
|
requireBundleResponse: true,
|
|
896
|
+
slot: launchSlotScope(root, slot),
|
|
881
897
|
onReadinessPending: () => phase("readiness", "waiting for app readiness (up to 30s after bundle load)"),
|
|
882
898
|
logsDir,
|
|
883
899
|
since: launchedAt,
|
|
@@ -909,10 +925,10 @@ async function verifyAndroidRun({ root, release, remoteRelease, remoteDevice, ve
|
|
|
909
925
|
phase("verify", chalk.red(`FATAL after ${formatDuration(verification.waitedMs ?? 0)}: ${reason}`));
|
|
910
926
|
for (const line of launchErrorPreview(verification.errors ?? [], root)) phase("", chalk.red(line));
|
|
911
927
|
if (verification.processAlive === false && !verification.errors?.some((record) => record.event === "native_crash")) phase("logs", "No attributable native crash report captured yet. Run `stim logs --errors` again for delayed reports, or `stim logs --source device` for available output.");
|
|
912
|
-
if (nativeFatal || verification.processAlive === false) phase("remedy", chalk.yellow(`Fix the crash, then restart the app: \`adb -s ${deviceShellArg(serial)} shell am force-stop ${deviceShellArg(androidPackage)}\`, then run \`
|
|
928
|
+
if (nativeFatal || verification.processAlive === false) phase("remedy", chalk.yellow(`Fix the crash, then restart the app: \`adb -s ${deviceShellArg(serial)} shell am force-stop ${deviceShellArg(androidPackage)}\`, then run \`${runCommand}\` again. A crashed Android process can remain alive behind the system crash dialog; Metro reload cannot recover it.`));
|
|
913
929
|
else if (verification.processAlive === true && metroPort !== null) {
|
|
914
930
|
const reloadRemedy = physical ? `run \`agent-device metro reload --metro-port ${metroPort}\`.` : "run `stim reload android`.";
|
|
915
|
-
phase("remedy", chalk.yellow(`The native app is still running. ${deliveryFailed ? "Check the Metro logs and device connection, then" : "Fix the JavaScript or TypeScript error, then"} ${reloadRemedy} Do not run \`
|
|
931
|
+
phase("remedy", chalk.yellow(`The native app is still running. ${deliveryFailed ? "Check the Metro logs and device connection, then" : "Fix the JavaScript or TypeScript error, then"} ${reloadRemedy} Do not run \`${runCommand}\` unless native inputs changed or the app process exits.`));
|
|
916
932
|
}
|
|
917
933
|
return { state: LAUNCH_FATAL };
|
|
918
934
|
}
|
|
@@ -923,7 +939,7 @@ async function verifyAndroidRun({ root, release, remoteRelease, remoteDevice, ve
|
|
|
923
939
|
for (const line of report.lines) phase("launch", chalk.yellow(line));
|
|
924
940
|
if (report.lines.length > 0 && verification.processAlive === true && metroPort !== null) {
|
|
925
941
|
const reloadRemedy = physical ? `run \`agent-device metro reload --metro-port ${metroPort}\`.` : "run `stim reload android`.";
|
|
926
|
-
phase("remedy", chalk.yellow(`The native app is still running. Fix the JavaScript or TypeScript error; Fast Refresh should apply the edit. If the error screen remains, ${reloadRemedy} Do not run \`
|
|
942
|
+
phase("remedy", chalk.yellow(`The native app is still running. Fix the JavaScript or TypeScript error; Fast Refresh should apply the edit. If the error screen remains, ${reloadRemedy} Do not run \`${runCommand}\` unless native inputs changed or the app process exits.`));
|
|
927
943
|
}
|
|
928
944
|
return {
|
|
929
945
|
state: true,
|
|
@@ -952,7 +968,7 @@ async function verifyAndroidRun({ root, release, remoteRelease, remoteDevice, ve
|
|
|
952
968
|
})) phase("", chalk.yellow(line));
|
|
953
969
|
return { state: LAUNCH_UNVERIFIED };
|
|
954
970
|
}
|
|
955
|
-
async function resolveInstallSerial({ root, device, physical, remoteDevice, serial, resolveAvdSerial, waitForDeviceBoot, phase }) {
|
|
971
|
+
async function resolveInstallSerial({ root, slot, device, physical, remoteDevice, serial, resolveAvdSerial, waitForDeviceBoot, phase }) {
|
|
956
972
|
if (physical || remoteDevice || !device.owned || !device.avdName) return serial;
|
|
957
973
|
const resolved = resolveAvdSerial(device.avdName, { timeoutMs: 5e3 });
|
|
958
974
|
if (!resolved.serial) throw new Error(`Could not verify a running owned AVD ${device.avdName} before installation.`);
|
|
@@ -965,16 +981,16 @@ async function resolveInstallSerial({ root, device, physical, remoteDevice, seri
|
|
|
965
981
|
}
|
|
966
982
|
const consolePort = Number(resolved.serial.replace(/^emulator-/, ""));
|
|
967
983
|
withConfigLock(() => {
|
|
968
|
-
const current = loadConfig()?.projects?.[root]?.
|
|
984
|
+
const current = deviceSlotPlatforms(loadConfig()?.projects?.[root], slot)?.android;
|
|
969
985
|
if (!current?.owned || current.avdName !== device.avdName) throw new Error("The owned emulator assignment changed before installation.");
|
|
970
986
|
if (current.consolePort !== consolePort) setDevice(root, PLATFORM, {
|
|
971
987
|
...current,
|
|
972
988
|
consolePort
|
|
973
|
-
});
|
|
989
|
+
}, slot);
|
|
974
990
|
});
|
|
975
991
|
return resolved.serial;
|
|
976
992
|
}
|
|
977
|
-
async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, useBuildCache, variant, release, isExpo, metroPort, logsDir, emuLog, device, physical, remoteDevice, bootPromise, resolveAvdSerial, waitForDeviceBoot, bootDuration, apkPath, androidPackage: initialPackage, swapDir, record, waitedForBuild, ccache, uploadPending, providerUpload, providerName, remote, abandonedRemote: remoteWasAbandoned, started, startedAt, writer, phase, fail, readApkPackage, install, launch, launchRelease, resolveDevClientScheme, verifyLaunched, verifyReleaseLaunched, spawn, kill, pidAlive, verifyCollector, writeLaunch, writeState, now, out, emit, recordRun }) {
|
|
993
|
+
async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCheck, useBuildCache, variant, release, isExpo, metroPort, logsDir, emuLog, device, physical, remoteDevice, bootPromise, resolveAvdSerial, waitForDeviceBoot, bootDuration, apkPath, androidPackage: initialPackage, swapDir, record, waitedForBuild, ccache, uploadPending, providerUpload, providerName, remote, abandonedRemote: remoteWasAbandoned, started, startedAt, writer, phase, fail, readApkPackage, install, launch, launchRelease, resolveDevClientScheme, verifyLaunched, verifyReleaseLaunched, spawn, kill, pidAlive, verifyCollector, writeLaunch, writeState, now, out, emit, recordRun }) {
|
|
978
994
|
let androidPackage = initialPackage;
|
|
979
995
|
let leaseWarned = false;
|
|
980
996
|
const raiseLeaseFor = (boundMs, beforeInstall) => {
|
|
@@ -991,11 +1007,15 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
991
1007
|
return null;
|
|
992
1008
|
};
|
|
993
1009
|
const booted = await bootPromise;
|
|
1010
|
+
const runCommand = nativeRunCommand("android", slot, {
|
|
1011
|
+
physical,
|
|
1012
|
+
deviceId: booted.serial
|
|
1013
|
+
});
|
|
994
1014
|
if (booted.failed) {
|
|
995
1015
|
const diag = noDeviceDiagnostic({
|
|
996
1016
|
reason: booted.reason ?? "The emulator did not boot.",
|
|
997
1017
|
logFile: emuLog,
|
|
998
|
-
remedy:
|
|
1018
|
+
remedy: `Run \`stim status\` to see what Stim thinks it owns; re-running \`${runCommand}\` creates a fresh owned AVD.`,
|
|
999
1019
|
localEmulator: !physical
|
|
1000
1020
|
});
|
|
1001
1021
|
return fail(NO_DEVICE, diag.message, diag.remedy, {
|
|
@@ -1007,6 +1027,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1007
1027
|
try {
|
|
1008
1028
|
serial = await resolveInstallSerial({
|
|
1009
1029
|
root,
|
|
1030
|
+
slot,
|
|
1010
1031
|
device,
|
|
1011
1032
|
physical,
|
|
1012
1033
|
remoteDevice,
|
|
@@ -1016,7 +1037,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1016
1037
|
phase
|
|
1017
1038
|
});
|
|
1018
1039
|
} catch (error) {
|
|
1019
|
-
return fail(NO_DEVICE, error instanceof Error ? error.message : String(error),
|
|
1040
|
+
return fail(NO_DEVICE, error instanceof Error ? error.message : String(error), `Run \`stim status\` to inspect the owned AVD, then retry \`${runCommand}\`; the APK was not installed.`);
|
|
1020
1041
|
}
|
|
1021
1042
|
phase("device", physical ? `${device.deviceName || serial} (${serial}) connected, not owned by Stim` : `${device.avdName || serial} (${serial}) ${device.adopted || device.adoptionPending ? "adopted" : "booted"} ${bootDuration()}`);
|
|
1022
1043
|
const packageFromApk = readApkPackage(apkPath);
|
|
@@ -1049,7 +1070,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1049
1070
|
if (adopting) try {
|
|
1050
1071
|
withConfigLock(() => {
|
|
1051
1072
|
const config = loadConfig();
|
|
1052
|
-
const current = config?.projects?.[root]?.
|
|
1073
|
+
const current = deviceSlotPlatforms(config?.projects?.[root], slot)?.android;
|
|
1053
1074
|
if (!config || !current || current.avdName !== device.avdName) throw new Error("The adopted emulator assignment changed during installation.");
|
|
1054
1075
|
delete current.adoptionPending;
|
|
1055
1076
|
saveConfig(config);
|
|
@@ -1111,6 +1132,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1111
1132
|
if (launched.failed) {
|
|
1112
1133
|
printNativeCrashReport({
|
|
1113
1134
|
root,
|
|
1135
|
+
slot,
|
|
1114
1136
|
platform: "android",
|
|
1115
1137
|
deviceId: serial,
|
|
1116
1138
|
appId: androidPackage,
|
|
@@ -1173,6 +1195,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1173
1195
|
if (physical) raiseLeaseFor(0, false);
|
|
1174
1196
|
const collectorPid = await startCollector({
|
|
1175
1197
|
root,
|
|
1198
|
+
slot,
|
|
1176
1199
|
serial,
|
|
1177
1200
|
packageName: androidPackage,
|
|
1178
1201
|
spawn,
|
|
@@ -1186,6 +1209,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1186
1209
|
if (physical) raiseLeaseFor(release ? RELEASE_VERIFY_WAIT_MS : DEBUG_VERIFY_STEP_MS, false);
|
|
1187
1210
|
const { state: launchState, warning: launchWarning } = await verifyAndroidRun({
|
|
1188
1211
|
root,
|
|
1212
|
+
slot,
|
|
1189
1213
|
release,
|
|
1190
1214
|
remoteRelease,
|
|
1191
1215
|
remoteDevice: Boolean(remoteDevice),
|
|
@@ -1219,6 +1243,7 @@ async function finishAndroidRun({ lease, releaseLease, root, json, metroCheck, u
|
|
|
1219
1243
|
const leaseFacts = lease?.facts() ?? null;
|
|
1220
1244
|
releaseLease();
|
|
1221
1245
|
const facts = reportAndroidResult({
|
|
1246
|
+
slot,
|
|
1222
1247
|
json,
|
|
1223
1248
|
useBuildCache,
|
|
1224
1249
|
variant,
|
|
@@ -1281,7 +1306,7 @@ function androidCommand(program) {
|
|
|
1281
1306
|
registerAndroid(program);
|
|
1282
1307
|
}
|
|
1283
1308
|
function registerAndroid(program) {
|
|
1284
|
-
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. Never starts the bundler -- run `stim start` first.").option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--no-metro-check", "Skip the reserved-port Metro health check (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 [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 <backend>", "Install and launch on a remote device with proxy or EAS.
|
|
1309
|
+
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. Never starts the bundler -- run `stim start` first.").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)", validateDeviceSlot).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--no-metro-check", "Skip the reserved-port Metro health check (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 [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 <backend>", "Install and launch on a remote device with proxy or EAS. Builds are local unless --eas-profile selects an existing EAS build.", (value) => {
|
|
1285
1310
|
if (REMOTE_DEVICE_BACKENDS.includes(value)) return value;
|
|
1286
1311
|
throw new InvalidArgumentError(`expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}`);
|
|
1287
1312
|
}).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). Only with --device.").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. Only with --device.").action(async (opts) => {
|
|
@@ -1291,8 +1316,10 @@ function registerAndroid(program) {
|
|
|
1291
1316
|
process.exit(1);
|
|
1292
1317
|
return;
|
|
1293
1318
|
}
|
|
1294
|
-
if (!(await runAndroid({
|
|
1319
|
+
if (!(await withWorkspaceProcessLock(workspaceDir(root), "native-run", () => runAndroid({
|
|
1295
1320
|
root,
|
|
1321
|
+
slot: opts.slot,
|
|
1322
|
+
easProfile: opts.easProfile,
|
|
1296
1323
|
json: Boolean(opts.json),
|
|
1297
1324
|
metroCheck: opts.metroCheck !== false,
|
|
1298
1325
|
useBuildCache: opts.buildCache !== false,
|
|
@@ -1302,10 +1329,13 @@ function registerAndroid(program) {
|
|
|
1302
1329
|
device: opts.device ?? null,
|
|
1303
1330
|
wait: opts.wait,
|
|
1304
1331
|
waitConflict: waitFlagConflict(process.argv)
|
|
1332
|
+
}), {
|
|
1333
|
+
external: true,
|
|
1334
|
+
waitMs: 18e5
|
|
1305
1335
|
})).ok) process.exit(1);
|
|
1306
1336
|
});
|
|
1307
1337
|
}
|
|
1308
|
-
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, variant: variantFlag = null, systemImage: systemImageFlag = null, 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, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, resolveMetroRetrying = resolveMetroWithRetry, readState = readWorkspaceState, 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, needsPrebuildFor = needsPrebuild, 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, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
1338
|
+
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, 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, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, resolveMetroRetrying = resolveMetroWithRetry, readState = readWorkspaceState, 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, needsPrebuildFor = needsPrebuild, 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, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
1309
1339
|
return {
|
|
1310
1340
|
root,
|
|
1311
1341
|
json,
|
|
@@ -1319,6 +1349,8 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
|
|
|
1319
1349
|
detectRemoteProviders,
|
|
1320
1350
|
metroCheck,
|
|
1321
1351
|
useBuildCache,
|
|
1352
|
+
easProfile,
|
|
1353
|
+
resolveEasBuild,
|
|
1322
1354
|
variantFlag,
|
|
1323
1355
|
systemImageFlag,
|
|
1324
1356
|
deviceFlag,
|
|
@@ -1387,8 +1419,38 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
|
|
|
1387
1419
|
emit
|
|
1388
1420
|
};
|
|
1389
1421
|
}
|
|
1422
|
+
function androidSlotOptions(options) {
|
|
1423
|
+
const base = resolveRunAndroidOptions(options);
|
|
1424
|
+
const slot = validateDeviceSlot(options.slot);
|
|
1425
|
+
if (slot === "default") return base;
|
|
1426
|
+
return {
|
|
1427
|
+
...base,
|
|
1428
|
+
ensureDevice: (args) => base.ensureDevice({
|
|
1429
|
+
...args,
|
|
1430
|
+
slot
|
|
1431
|
+
}),
|
|
1432
|
+
checkCapacity: (args) => base.checkCapacity({
|
|
1433
|
+
...args,
|
|
1434
|
+
slot
|
|
1435
|
+
}),
|
|
1436
|
+
selectPool: (args) => base.selectPool({
|
|
1437
|
+
...args,
|
|
1438
|
+
slot
|
|
1439
|
+
}),
|
|
1440
|
+
acquireLease: (args) => base.acquireLease({
|
|
1441
|
+
...args,
|
|
1442
|
+
slot
|
|
1443
|
+
}),
|
|
1444
|
+
makeRunLease: (args) => base.makeRunLease({
|
|
1445
|
+
...args,
|
|
1446
|
+
slot
|
|
1447
|
+
}),
|
|
1448
|
+
writeLaunch: ((projectRoot, platform, record) => base.writeLaunch(projectRoot, platform, record, slot))
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1390
1451
|
async function runAndroid(options = {}) {
|
|
1391
|
-
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, variantFlag, systemImageFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, resolveMetroRetrying, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, needsPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordStats, readEstimates, now, out, emit } =
|
|
1452
|
+
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, resolveMetroRetrying, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, needsPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
|
|
1453
|
+
const slot = validateDeviceSlot(options.slot);
|
|
1392
1454
|
const started = now();
|
|
1393
1455
|
const startedAt = new Date(started).toISOString();
|
|
1394
1456
|
const projectProblem = appProjectProblem(root);
|
|
@@ -1433,8 +1495,11 @@ async function runAndroid(options = {}) {
|
|
|
1433
1495
|
};
|
|
1434
1496
|
}
|
|
1435
1497
|
const logsDir = workspaceLogsDir(root);
|
|
1436
|
-
const buildLog = join(logsDir, "
|
|
1437
|
-
const writer = createWriter(buildLog, {
|
|
1498
|
+
const buildLog = join(logsDir, `build-${deviceSlotKey("android", slot)}.ndjson`);
|
|
1499
|
+
const writer = createWriter(buildLog, {
|
|
1500
|
+
truncate: true,
|
|
1501
|
+
fields: { slot }
|
|
1502
|
+
});
|
|
1438
1503
|
const record = {
|
|
1439
1504
|
fingerprint: null,
|
|
1440
1505
|
cacheKey: null,
|
|
@@ -1559,7 +1624,7 @@ async function runAndroid(options = {}) {
|
|
|
1559
1624
|
const remoteSettingError = remoteDeviceSettingError(settings);
|
|
1560
1625
|
if (remoteSettingError) return fail("STIM_BAD_ARG", remoteSettingError, `Set ios.remote and android.remote to one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}.`);
|
|
1561
1626
|
const systemImage = resolveSystemImage(systemImageFlag, settings);
|
|
1562
|
-
const variant = resolveVariant(variantFlag, settings);
|
|
1627
|
+
const variant = easProfile !== void 0 ? "debug" : resolveVariant(variantFlag, settings);
|
|
1563
1628
|
const flavorRefusal = productFlavorRefusal({
|
|
1564
1629
|
flavors: readProductFlavors(root),
|
|
1565
1630
|
variant
|
|
@@ -1569,7 +1634,7 @@ async function runAndroid(options = {}) {
|
|
|
1569
1634
|
const cachePolicy = artifactCachePolicy(optimizations, requestedBuildCache, release);
|
|
1570
1635
|
const useBuildCache = cachePolicy.read;
|
|
1571
1636
|
const isExpo = detectIsExpo(root);
|
|
1572
|
-
const physical = deviceFlag
|
|
1637
|
+
const physical = isPhysicalDeviceRequest(deviceFlag);
|
|
1573
1638
|
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.");
|
|
1574
1639
|
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.");
|
|
1575
1640
|
const noWait = waitFlag === false;
|
|
@@ -1581,6 +1646,7 @@ async function runAndroid(options = {}) {
|
|
|
1581
1646
|
const waitSeconds = waitParsed.seconds;
|
|
1582
1647
|
const remoteBackend = physical ? null : commandRemoteBackend ?? remoteAndroidSetting(settings);
|
|
1583
1648
|
const imageRefusal = systemImageRefusal({
|
|
1649
|
+
slot,
|
|
1584
1650
|
flag: systemImageFlag,
|
|
1585
1651
|
resolved: systemImage,
|
|
1586
1652
|
physical,
|
|
@@ -1588,6 +1654,17 @@ async function runAndroid(options = {}) {
|
|
|
1588
1654
|
listImages: listSystemImages
|
|
1589
1655
|
});
|
|
1590
1656
|
if (imageRefusal) return fail(imageRefusal.code, imageRefusal.message, imageRefusal.remedy);
|
|
1657
|
+
const easBuild = await resolveEasBuild({
|
|
1658
|
+
root,
|
|
1659
|
+
platform: PLATFORM,
|
|
1660
|
+
profile: easProfile,
|
|
1661
|
+
note: out,
|
|
1662
|
+
isExpo,
|
|
1663
|
+
physical,
|
|
1664
|
+
selectors: [variantFlag],
|
|
1665
|
+
buildCache: requestedBuildCache
|
|
1666
|
+
});
|
|
1667
|
+
if (isEasBuildFailure(easBuild)) return fail(easBuild.code, easBuild.message, easBuild.remedy);
|
|
1591
1668
|
const requestedSerial = typeof deviceFlag === "string" ? deviceFlag : null;
|
|
1592
1669
|
let androidPackage = detectAndroidPackage(root);
|
|
1593
1670
|
record.bundleId = androidPackage;
|
|
@@ -1799,6 +1876,18 @@ async function runAndroid(options = {}) {
|
|
|
1799
1876
|
let storeSources = [];
|
|
1800
1877
|
let apkPath = null;
|
|
1801
1878
|
async function resolveInitialFingerprint() {
|
|
1879
|
+
if (easBuild?.ok) {
|
|
1880
|
+
hash = storeHash = easBuild.fingerprint;
|
|
1881
|
+
cacheKey = storeKey = easBuild.cacheKey;
|
|
1882
|
+
apkPath = easBuild.path;
|
|
1883
|
+
record.fingerprint = hash;
|
|
1884
|
+
record.cacheKey = cacheKey;
|
|
1885
|
+
record.cacheHit = easBuild.cacheHit;
|
|
1886
|
+
record.cacheSkipped = !useBuildCache;
|
|
1887
|
+
providerName = "eas";
|
|
1888
|
+
stats.setCacheKey(cacheKey);
|
|
1889
|
+
return true;
|
|
1890
|
+
}
|
|
1802
1891
|
const fingerprintTimer = stepTimer(now);
|
|
1803
1892
|
try {
|
|
1804
1893
|
const computed = await fingerprint(root, { platform: PLATFORM });
|
|
@@ -1930,7 +2019,7 @@ async function runAndroid(options = {}) {
|
|
|
1930
2019
|
} else phase("cache", `remote miss (${remote.name}) ${remoteTimer()}`);
|
|
1931
2020
|
}
|
|
1932
2021
|
}
|
|
1933
|
-
await resolveRemoteArtifact();
|
|
2022
|
+
if (!easBuild) await resolveRemoteArtifact();
|
|
1934
2023
|
let waitedForBuild = null;
|
|
1935
2024
|
let releasedWait = null;
|
|
1936
2025
|
async function waitForSharedBuild() {
|
|
@@ -2014,7 +2103,7 @@ async function runAndroid(options = {}) {
|
|
|
2014
2103
|
}
|
|
2015
2104
|
return true;
|
|
2016
2105
|
}
|
|
2017
|
-
if (!await waitForSharedBuild()) return phaseFailure;
|
|
2106
|
+
if (!easBuild && !await waitForSharedBuild()) return phaseFailure;
|
|
2018
2107
|
let swapDir = null;
|
|
2019
2108
|
let swapFellBack = false;
|
|
2020
2109
|
const installableCachedApk = async (key, cachedPath) => {
|
|
@@ -2214,8 +2303,10 @@ async function runAndroid(options = {}) {
|
|
|
2214
2303
|
}
|
|
2215
2304
|
return true;
|
|
2216
2305
|
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2306
|
+
if (!easBuild) {
|
|
2307
|
+
await prepareCachedArtifact();
|
|
2308
|
+
if (!await buildArtifact()) return phaseFailure;
|
|
2309
|
+
}
|
|
2219
2310
|
record.appPath = apkPath;
|
|
2220
2311
|
let leaseHandle = null;
|
|
2221
2312
|
let stopLeaseSignals = null;
|
|
@@ -2260,6 +2351,7 @@ async function runAndroid(options = {}) {
|
|
|
2260
2351
|
}
|
|
2261
2352
|
try {
|
|
2262
2353
|
return await finishAndroidRun({
|
|
2354
|
+
slot,
|
|
2263
2355
|
lease: leaseHandle,
|
|
2264
2356
|
releaseLease,
|
|
2265
2357
|
root,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { k as withDirLock, u as getConfigDir } from "./config-
|
|
3
|
-
import { r as register } from "./cache-manifest-
|
|
4
|
-
import { D as workspaceLogsDir, x as sharedCcache, y as ensureWorkspaceStorage } from "./state-
|
|
2
|
+
import { k as withDirLock, u as getConfigDir } from "./config-CcefMY2Q.mjs";
|
|
3
|
+
import { r as register } from "./cache-manifest-CXR-Y8pH.mjs";
|
|
4
|
+
import { D as workspaceLogsDir, x as sharedCcache, y as ensureWorkspaceStorage } from "./state-B3XA2wp2.mjs";
|
|
5
5
|
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
|
|
6
6
|
import { l as phaseLine } from "./command-output-8wHMEde0.mjs";
|
|
7
|
-
import { n as androidHome } from "./android-
|
|
8
|
-
import { f as startBuildHeartbeat, r as HEARTBEAT_INTERVAL_MS } from "./xcode-
|
|
7
|
+
import { n as androidHome } from "./android-BqVIJoG7.mjs";
|
|
8
|
+
import { f as startBuildHeartbeat, r as HEARTBEAT_INTERVAL_MS } from "./xcode-D7sAp-Zy.mjs";
|
|
9
9
|
import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
11
11
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CyylIdq9.mjs";
|
|
2
|
-
import { o as parseNdjsonText } from "./ndjson-
|
|
2
|
+
import { o as parseNdjsonText } from "./ndjson-BZwI1NBv.mjs";
|
|
3
3
|
import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-D3pzTKQE.mjs";
|
|
4
4
|
import { s as isAppLaunchError } from "./command-output-8wHMEde0.mjs";
|
|
5
|
-
import { l as iosSimulatorFailureAdvice, p as listUserApps, w as uninstallIosApp } from "./ios-
|
|
5
|
+
import { l as iosSimulatorFailureAdvice, p as listUserApps, w as uninstallIosApp } from "./ios-Deh5js5V.mjs";
|
|
6
6
|
import { closeSync, lstatSync, openSync, readFileSync, readSync, readdirSync } from "node:fs";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
import { join } from "node:path";
|
|
@@ -900,7 +900,7 @@ function nativeLaunchFailure({ readCrashes, since, platform, processAlive, mode,
|
|
|
900
900
|
waitedMs
|
|
901
901
|
} : null;
|
|
902
902
|
}
|
|
903
|
-
async function verifyLaunch({ logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
|
|
903
|
+
async function verifyLaunch({ slot, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
|
|
904
904
|
const read = readRecords || (() => readMetroRecords(logsDir));
|
|
905
905
|
const readDevice = readDeviceRecords || (() => readNdjson(logsDir, "device.ndjson"));
|
|
906
906
|
const readClient = readClientRecords || (() => readNdjson(logsDir, "client.ndjson"));
|
|
@@ -915,10 +915,10 @@ async function verifyLaunch({ logsDir, since, metroPort = null, platform = null,
|
|
|
915
915
|
let runtimeStartedAt = null;
|
|
916
916
|
let nextCrashCheck = startedAt + 1e3;
|
|
917
917
|
while (true) {
|
|
918
|
-
const metroRecords = read().filter((record) => after(record, since));
|
|
918
|
+
const metroRecords = read().filter((record) => after(record, since) && (slot === void 0 || record.slot === slot));
|
|
919
919
|
const bundleRecords = metroRecords.filter((record) => !requireBundleResponse || String(record.event).startsWith("bundle_response_"));
|
|
920
|
-
const deviceRecords = readDevice().filter((record) => after(record, since));
|
|
921
|
-
const clientRecords = readClient().filter((record) => after(record, since));
|
|
920
|
+
const deviceRecords = readDevice().filter((record) => after(record, since) && (slot === void 0 || (record.slot ?? "default") === slot));
|
|
921
|
+
const clientRecords = readClient().filter((record) => after(record, since) && (slot === void 0 || record.slot === slot));
|
|
922
922
|
if (now() >= nextCrashCheck) {
|
|
923
923
|
nextCrashCheck = now() + 2e3;
|
|
924
924
|
const crash = nativeLaunchFailure({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { u as getConfigDir } from "./config-
|
|
1
|
+
import { u as getConfigDir } from "./config-CcefMY2Q.mjs";
|
|
2
2
|
import { a as formatElapsed } from "./command-output-8wHMEde0.mjs";
|
|
3
|
-
import { d as readClaimSet, f as releaseClaim, h as tryAcquireClaim, s as isClaimRefusal } from "./ownership-claim-
|
|
3
|
+
import { d as readClaimSet, f as releaseClaim, h as tryAcquireClaim, s as isClaimRefusal } from "./ownership-claim-Bf2CAfw3.mjs";
|
|
4
4
|
import { readdirSync, statSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
//#region src/engine/build-slots.ts
|
package/dist/cache-manifest.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-
|
|
1
|
+
import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-CXR-Y8pH.mjs";
|
|
2
2
|
export { manifestPath, readManifest, register, registeredCaches, unregister };
|