stim 1.10.0 → 1.11.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/{build-progress-BXx-ZBe4.mjs → activity-BtG4Va9l.mjs} +8 -182
- package/dist/{android-DPov-fv2.mjs → android-BA2i_KAV.mjs} +1 -1
- package/dist/{android-DBkeHwpm.mjs → android-C1q4l523.mjs} +376 -99
- package/dist/{android-787HhP5w.mjs → android-C4zG2Tuc.mjs} +63 -18
- package/dist/{android-cas-CITmIeWY.mjs → android-cas-DfJkwCXW.mjs} +3 -3
- package/dist/{app-install-CrJ6t_bv.mjs → app-install-DHut6JnV.mjs} +1 -1
- package/dist/{budget-BP4jZZL4.mjs → budget-De3P2rq_.mjs} +9 -9
- package/dist/{dev-client-92U593KT.mjs → build-plan-CeAYgKAx.mjs} +415 -24
- package/dist/build-progress-CDwogz6R.mjs +179 -0
- package/dist/cli.mjs +14 -14
- package/dist/collector-run.mjs +1 -1
- package/dist/{deps-DP4eWqea.mjs → deps-OF7CD5Dx.mjs} +2 -2
- package/dist/{device-DhTZe7L4.mjs → device-BwH2iI3O.mjs} +47 -9
- package/dist/{device-lease-CbEaIk7b.mjs → device-lease-D83nqeMX.mjs} +51 -51
- package/dist/{device-pool-Di8Q-9Ro.mjs → device-pool-DHj7cdPy.mjs} +2 -2
- package/dist/{device-remote-Dy1jGj3U.mjs → device-remote-BQZSnnmE.mjs} +7 -7
- package/dist/{doctor-B-inAJmt.mjs → doctor-D8QdMRMf.mjs} +12 -12
- package/dist/{error-diagnostics-xxWKNO3-.mjs → error-diagnostics-UYFSQwRy.mjs} +3 -3
- package/dist/{gc-ChPFZMRC.mjs → gc-COZteyiq.mjs} +27 -253
- package/dist/{guide-DwmaD_Wa.mjs → guide-NDvTmMi-.mjs} +336 -48
- package/dist/{idle-DpRLp5lj.mjs → idle-NETbeNiQ.mjs} +4 -3
- package/dist/{in-use-CjUluqIX.mjs → in-use-DVhlSoyn.mjs} +4 -4
- package/dist/{ios-Dd-hYJBh.mjs → ios-CQLKpNfr.mjs} +294 -81
- package/dist/{ios-B2Fpqvlb.mjs → ios-DArbmwer.mjs} +16 -7
- package/dist/{ios-device-CtRdEVjx.mjs → ios-device-CwDZo0X4.mjs} +1 -1
- package/dist/{launch-verify-CQS_Kg-C.mjs → launch-verify-CuPDGXdr.mjs} +1 -1
- package/dist/logs-B44a1UeU.mjs +485 -0
- package/dist/merge-state-DDxS-XIZ.mjs +232 -0
- package/dist/{named-ports-DiTfSz6p.mjs → named-ports-Dc7neAlc.mjs} +1 -1
- package/dist/native-run-D7yB_AsB.mjs +143 -0
- package/dist/{ownership-DZjdx8Gq.mjs → ownership-BiojdtAp.mjs} +3 -3
- package/dist/{ports-CLSSFOuz.mjs → ports-DwBaRFJs.mjs} +1 -1
- package/dist/{reload-DoETJ3rl.mjs → reload-By9Dwsrt.mjs} +4 -4
- package/dist/{server-bare-DVbb7kXH.mjs → server-bare-D_RK1RCj.mjs} +1 -1
- package/dist/server-expo-B-CCUJZj.mjs +2 -0
- package/dist/{server-expo-BvOCeakp.mjs → server-expo-o6H5gcBc.mjs} +1 -1
- package/dist/{settings-DOugPlPz.mjs → settings-B5oFZEri.mjs} +12 -3
- package/dist/{settings-EWYNwe72.mjs → settings-C0ugALSC.mjs} +1 -1
- package/dist/settings.schema.json +52 -0
- package/dist/{simslim-Ca3487H6.mjs → simslim-CIR3IYJO.mjs} +150 -95
- package/dist/{slot-launch-C5cg0fmk.mjs → slot-launch-rggO1Esw.mjs} +2 -2
- package/dist/{spawn-claims-CUleC2cM.mjs → spawn-claims-BJwXTMPt.mjs} +24 -1
- package/dist/{start-F9gv5dcC.mjs → start-BSsf2tUs.mjs} +4 -4
- package/dist/{start-VoFsPSes.mjs → start-i8zc9VmS.mjs} +1 -1
- package/dist/{status-DLCD-o3s.mjs → status-CitcBRsC.mjs} +227 -22
- package/dist/{status-Dr4fRkym.mjs → status-Q-WDEGCB.mjs} +20 -6
- package/dist/{stop-Dj4pfmyv.mjs → stop-DIhrvu0B.mjs} +188 -27
- package/dist/stop-rst5mL14.mjs +3 -0
- package/dist/supervisor-run.mjs +7 -7
- package/dist/{workspace-process-lock-BXA96myD.mjs → workspace-process-lock-Cx74RSDZ.mjs} +9 -4
- package/dist/{workspaces-BTUyFfkv.mjs → workspaces-COD2xCz-.mjs} +15 -5
- package/dist/{worktree-4aZg2NnI.mjs → worktree-DhxDTK44.mjs} +1 -1
- package/dist/{worktree-BMS7GeqB.mjs → worktree-KOjMX3zA.mjs} +8 -8
- package/dist/{xcode-B2tBkf0m.mjs → xcode-B5SPD--o.mjs} +3 -3
- package/package.json +5 -5
- package/dist/logs-MARIy6m9.mjs +0 -209
- package/dist/server-expo-DBVTdult.mjs +0 -2
- package/dist/stop-ZvOeTmKb.mjs +0 -3
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
import { L as deviceSlotFileKey, R as deviceSlotKey, V as parseDeviceSlotOption, W as validateDeviceSlot, f as getProject, k as ownership_claim_exports, l as getConcurrencyLimits, w as upsertProject } from "./config-BEq0Qw_a.mjs";
|
|
2
2
|
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
3
|
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
4
|
-
import { O as workspaceDir, c as signalProcessTree, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState, s as resolveProjectMetro, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
|
|
4
|
+
import { O as workspaceDir, c as signalProcessTree, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, s as resolveProjectMetro, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
|
|
5
5
|
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
|
|
6
6
|
import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
|
|
7
7
|
import { n as MODE_EXPO, p as writeWorkspaceLaunch, t as MODE_BARE } from "./state-WGdIbi_d.mjs";
|
|
8
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
|
|
9
8
|
import { _ as stepTimer, c as launchErrorReport, g as stepClock, h as shortUdid, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-D5z2_bcF.mjs";
|
|
10
|
-
import { A as resolveBuild, C as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-
|
|
9
|
+
import { A as resolveBuild, C as filesystemBuildCapability, D as providerDownloadPath, E as prepareProviderDownloadDir, F as untrackedNativeFiles, O as providerUploadOutcome, P as untrackedMissLine, T as fingerprintProject, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as storeBuild, k as refingerprintAfterMutation, m as acquireBuildLock, v as waitForSharedBuild, w as fingerprintDiffRecord } from "./device-lease-D83nqeMX.mjs";
|
|
10
|
+
import { A as resolveCacheProviderConfig, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, P as settingShapeErrors, S as metroWarmupUrlSetting, U as optimizationBuildProfile, V as artifactCachePolicy, W as resolveOptimizations, _ as iosSigningIdentitySha1SettingError, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as iosLanHostSetting, g as iosSigningIdentitySha1Setting, h as iosSigningIdentitySettingError, j as resolveSettings, k as remoteIosSetting, m as iosSigningIdentitySetting, p as iosLanHostSettingError, r as REMOTE_DEVICE_BACKENDS, z as detectProviders } from "./settings-B5oFZEri.mjs";
|
|
11
|
+
import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
|
|
12
|
+
import { D as parseIosSimulatorApp, f as listIosRuntimes } from "./ios-DArbmwer.mjs";
|
|
13
|
+
import { c as startBuildProgress, n as NO_BUILD_PROGRESS } from "./build-progress-CDwogz6R.mjs";
|
|
14
|
+
import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-DVhlSoyn.mjs";
|
|
16
15
|
import { n as verifyCollectorOwnership } from "./ownership-D2xbLVoz.mjs";
|
|
17
|
-
import { A as UPLOAD_TIMEOUT_MS, B as resolveRemote, F as isEasAuthFailureText, I as loadProjectProvider, M as checkEasAuth, N as easAuthNote, O as gateMetroOrigin, P as exitAfterFlush, V as uploadRemote, a as ensureMetroReachable, j as cacheLevel, k as RESOLVE_TIMEOUT_MS, l as remoteIosDeps, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, u as resolveRemoteContext, w as ownedSessionName, z as resolveEasCliBin } from "./device-remote-
|
|
18
|
-
import { c as clearOtherUserApps, h as iosAppProcess, m as installIosApp, r as DEFAULT_METRO_PORT, u as devClientUrl, v as launchIosApp } from "./app-install-
|
|
19
|
-
import { c as readMetroRecords, d as verifyLaunch, f as verifyReleaseLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unverifiedLaunchLines, n as LAUNCH_FATAL, o as isBundleProof, r as LAUNCH_UNVERIFIED, s as readCollectorRecords, t as LAUNCH_BUNDLING } from "./launch-verify-
|
|
20
|
-
import { c as
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { t as
|
|
24
|
-
import {
|
|
16
|
+
import { A as UPLOAD_TIMEOUT_MS, B as resolveRemote, F as isEasAuthFailureText, I as loadProjectProvider, M as checkEasAuth, N as easAuthNote, O as gateMetroOrigin, P as exitAfterFlush, V as uploadRemote, a as ensureMetroReachable, j as cacheLevel, k as RESOLVE_TIMEOUT_MS, l as remoteIosDeps, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, u as resolveRemoteContext, w as ownedSessionName, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
|
|
17
|
+
import { c as clearOtherUserApps, h as iosAppProcess, m as installIosApp, r as DEFAULT_METRO_PORT, u as devClientUrl, v as launchIosApp } from "./app-install-DHut6JnV.mjs";
|
|
18
|
+
import { c as readMetroRecords, d as verifyLaunch, f as verifyReleaseLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unverifiedLaunchLines, n as LAUNCH_FATAL, o as isBundleProof, r as LAUNCH_UNVERIFIED, s as readCollectorRecords, t as LAUNCH_BUNDLING } from "./launch-verify-CuPDGXdr.mjs";
|
|
19
|
+
import { c as unknownIosDeviceTypeRefusal, d as easDeviceBuildRemedy, f as isEasBuildFailure, l as unknownIosRuntimeRefusal, m as resolveEasDevelopmentBuild, p as planEasDevelopmentBuild, r as checkDeviceCapacity } from "./simslim-CIR3IYJO.mjs";
|
|
20
|
+
import { d as withNativeBuildRun, r as cancelledFailure, u as runCancellation } from "./native-run-D7yB_AsB.mjs";
|
|
21
|
+
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-DHj7cdPy.mjs";
|
|
22
|
+
import { C as ensureDevServer, D as sleep, E as launchOutcomeRecord, O as warmMetro, S as clearIosAdoptionPending, T as isPhysicalDeviceRequest, _ as staleNativeDirRefusal, a as refusePlan, c as skippedMissReason, d as schemesFromInfoPlist, g as runPrebuild, h as recordPrebuild, i as printPlan, l as devClientScheme, m as planPrebuild, n as planFlagRefusal, o as explainBuildMiss, p as swapJsBundle, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as pickDevClientScheme, v as ensureBooted, w as ensureWorkspaceStorageSafely, y as ensureOwnedDevice } from "./build-plan-CeAYgKAx.mjs";
|
|
23
|
+
import { t as budgetGate } from "./budget-De3P2rq_.mjs";
|
|
24
|
+
import { f as spawnEntry, s as startDevServer } from "./start-BSsf2tUs.mjs";
|
|
25
25
|
import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BAgJaLA4.mjs";
|
|
26
|
-
import { a as compilationCacheActivityLine, c as readBundleExecutable, l as readBundleId, p as describeDiagnostic, r as buildIos, s as discoverXcodeProject, t as COMPILATION_CACHE_NOT_RUN, u as resolveScheme } from "./xcode-
|
|
27
|
-
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-
|
|
28
|
-
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-
|
|
29
|
-
import { a as iosPoolCandidates, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as iosDeviceProcess, l as localNetworkPending, n as installIosDeviceApp, o as iosPoolNoCandidatesRefusal, r as iosDeviceBounds, s as isWirelessIosDevice, t as awaitIosDeviceLaunch, u as resolveIosPhysicalDevice } from "./ios-device-
|
|
30
|
-
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-
|
|
26
|
+
import { a as compilationCacheActivityLine, c as readBundleExecutable, l as readBundleId, p as describeDiagnostic, r as buildIos, s as discoverXcodeProject, t as COMPILATION_CACHE_NOT_RUN, u as resolveScheme } from "./xcode-B5SPD--o.mjs";
|
|
27
|
+
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-rggO1Esw.mjs";
|
|
28
|
+
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-UYFSQwRy.mjs";
|
|
29
|
+
import { a as iosPoolCandidates, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as iosDeviceProcess, l as localNetworkPending, n as installIosDeviceApp, o as iosPoolNoCandidatesRefusal, r as iosDeviceBounds, s as isWirelessIosDevice, t as awaitIosDeviceLaunch, u as resolveIosPhysicalDevice } from "./ios-device-CwDZo0X4.mjs";
|
|
30
|
+
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-OF7CD5Dx.mjs";
|
|
31
31
|
import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
|
|
32
32
|
import { InvalidArgumentError } from "commander";
|
|
33
|
+
import { LAST_BUILD_KEYS } from "@stim-cli/core/state";
|
|
33
34
|
import { basename, join } from "node:path";
|
|
34
35
|
import { X509Certificate } from "node:crypto";
|
|
35
36
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
@@ -235,7 +236,7 @@ function printDiagnostics(note, result) {
|
|
|
235
236
|
}
|
|
236
237
|
//#endregion
|
|
237
238
|
//#region src/commands/ios/result.ts
|
|
238
|
-
function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false, cacheSkipped = false, durationMs = 0, appPath = null, bundleId = null, startedAt, status, errorCode = null }) {
|
|
239
|
+
function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false, cacheSkipped = false, durationMs = 0, appPath = null, bundleId = null, startedAt, status, errorCode = null, missReason = null }) {
|
|
239
240
|
const record = {
|
|
240
241
|
platform: "ios",
|
|
241
242
|
fingerprint,
|
|
@@ -249,6 +250,7 @@ function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false
|
|
|
249
250
|
status
|
|
250
251
|
};
|
|
251
252
|
if (errorCode) record.errorCode = errorCode;
|
|
253
|
+
if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
|
|
252
254
|
return record;
|
|
253
255
|
}
|
|
254
256
|
function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, fingerprint, configuration = null, scheme = null, cacheKey, cacheHit, cacheSkipped = false, compilationCache = COMPILATION_CACHE_NOT_RUN, waitedForBuild = null, appPath, bundleId, installSkipped = false, metroPort, logsDir, durationMs, launched = true, webPreviewUrl = null, lease, devServer = null }) {
|
|
@@ -284,7 +286,10 @@ function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, f
|
|
|
284
286
|
}
|
|
285
287
|
function writeLastBuild(root, record, { write = writeWorkspaceState } = {}) {
|
|
286
288
|
try {
|
|
287
|
-
write(root, {
|
|
289
|
+
write(root, {
|
|
290
|
+
lastBuild: record,
|
|
291
|
+
[LAST_BUILD_KEYS["ios"]]: record
|
|
292
|
+
});
|
|
288
293
|
} catch {}
|
|
289
294
|
return record;
|
|
290
295
|
}
|
|
@@ -305,7 +310,7 @@ async function finishIosUpload(uploadPending, remote, phase, note) {
|
|
|
305
310
|
}
|
|
306
311
|
return false;
|
|
307
312
|
}
|
|
308
|
-
function reportIosResult({ slot, d, root, json, release, configuration, buildScheme = null, metroCheck, metroPort, logsDir, device, udid, appPath, bundleId, installSkipped, elapsed, startedAt, storeHash, storeKey, cacheHit, compilationCache, useBuildCache, waitedForBuild, launchState, launchWarning, providerName, closeWriter, webPreviewUrl, lease, recordRun, reclaimed = [], devServer = null }) {
|
|
313
|
+
function reportIosResult({ slot, d, root, json, release, configuration, buildScheme = null, metroCheck, metroPort, logsDir, device, udid, appPath, bundleId, installSkipped, elapsed, startedAt, storeHash, storeKey, cacheHit, missReason, compilationCache, useBuildCache, waitedForBuild, launchState, launchWarning, providerName, closeWriter, webPreviewUrl, lease, recordRun, reclaimed = [], devServer = null }) {
|
|
309
314
|
const durationMs = elapsed();
|
|
310
315
|
recordRun({
|
|
311
316
|
failed: false,
|
|
@@ -318,6 +323,7 @@ function reportIosResult({ slot, d, root, json, release, configuration, buildSch
|
|
|
318
323
|
cacheKey: storeKey,
|
|
319
324
|
cacheHit,
|
|
320
325
|
cacheSkipped: !useBuildCache,
|
|
326
|
+
missReason,
|
|
321
327
|
durationMs,
|
|
322
328
|
appPath,
|
|
323
329
|
bundleId,
|
|
@@ -462,6 +468,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
462
468
|
let releasedWait = null;
|
|
463
469
|
let swapFellBack = false;
|
|
464
470
|
let buildFailure = {};
|
|
471
|
+
let missReason = null;
|
|
465
472
|
async function resolveInitialFingerprint() {
|
|
466
473
|
if (easBuild?.ok) {
|
|
467
474
|
fingerprint = storeHash = easBuild.fingerprint;
|
|
@@ -492,18 +499,24 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
492
499
|
step("cache-lookup");
|
|
493
500
|
const fingerprintTimer = stepTimer(d.now);
|
|
494
501
|
let computedFingerprint;
|
|
502
|
+
let fingerprintError = "no hash";
|
|
495
503
|
try {
|
|
496
504
|
const computed = await d.fingerprintProject(root, { platform: "ios" });
|
|
497
505
|
computedFingerprint = computed?.hash ?? null;
|
|
498
506
|
fingerprintSources = computed?.sources ?? [];
|
|
499
507
|
} catch (e) {
|
|
500
508
|
computedFingerprint = null;
|
|
501
|
-
|
|
509
|
+
fingerprintError = String(e?.message || e);
|
|
510
|
+
note(chalk.dim(`Fingerprinting failed: ${fingerprintError}`));
|
|
502
511
|
}
|
|
503
512
|
if (!computedFingerprint) fail({
|
|
504
513
|
code: "STIM_NO_FINGERPRINT",
|
|
505
514
|
message: `Could not fingerprint ${root}: @expo/fingerprint produced no hash for it.`,
|
|
506
|
-
remedy: "Check the project native inputs and the @expo/fingerprint error above, then retry."
|
|
515
|
+
remedy: "Check the project native inputs and the @expo/fingerprint error above, then retry.",
|
|
516
|
+
build: {
|
|
517
|
+
cacheSkipped: !useBuildCache,
|
|
518
|
+
missReason: fingerprintErrorMissReason(fingerprintError)
|
|
519
|
+
}
|
|
507
520
|
});
|
|
508
521
|
fingerprint = computedFingerprint;
|
|
509
522
|
cacheKey = buildCacheKey("ios", fingerprint, {
|
|
@@ -535,29 +548,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
535
548
|
});
|
|
536
549
|
const cached = found?.tier === "local" ? found.path : null;
|
|
537
550
|
cacheHit = cached ? "local" : false;
|
|
538
|
-
|
|
539
|
-
let missUntracked = null;
|
|
540
|
-
if (!cached) {
|
|
541
|
-
const lastBuild = d.readWorkspaceState(root)?.lastBuild ?? null;
|
|
542
|
-
const miss = describeFingerprintMiss({
|
|
543
|
-
platform: "ios",
|
|
544
|
-
current: {
|
|
545
|
-
hash: fingerprint,
|
|
546
|
-
sources: fingerprintSources
|
|
547
|
-
},
|
|
548
|
-
lastBuild
|
|
549
|
-
});
|
|
550
|
-
if (miss) {
|
|
551
|
-
missDiff = fingerprintDiffSuffix(miss.changed);
|
|
552
|
-
logWriter().write(fingerprintDiffRecord({
|
|
553
|
-
changed: miss.changed,
|
|
554
|
-
previousHash: miss.previousHash,
|
|
555
|
-
hash: fingerprint
|
|
556
|
-
}));
|
|
557
|
-
} else if (useBuildCache) missUntracked = untrackedMissLine(d.untrackedNativeFiles({ projectRoot: root }));
|
|
558
|
-
}
|
|
559
|
-
phase("fingerprint", `${shortHash(fingerprint)} ${cached ? "hit" : "miss"}${useBuildCache ? "" : cache.disabledByFlag ? " (--no-build-cache)" : " (cache reuse off in config)"} ${fingerprintTimer()}${missDiff}`);
|
|
560
|
-
if (missUntracked) note(chalk.dim(phaseLine("fingerprint", missUntracked)));
|
|
551
|
+
phase("fingerprint", `${shortHash(fingerprint)} ${cached ? "hit" : "miss"}${useBuildCache ? "" : cache.disabledByFlag ? " (--no-build-cache)" : " (cache reuse off in config)"} ${fingerprintTimer()}`);
|
|
561
552
|
if (found?.tier === "provider") {
|
|
562
553
|
cacheHit = "remote";
|
|
563
554
|
providerName = found.providerName ?? null;
|
|
@@ -742,6 +733,38 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
742
733
|
}
|
|
743
734
|
}
|
|
744
735
|
}
|
|
736
|
+
function explainMiss(rekeyedBy) {
|
|
737
|
+
if (swapFellBack) missReason = skippedMissReason("the cached app could not be reused, so this run built it fresh");
|
|
738
|
+
else if (!useBuildCache) missReason = skippedMissReason(cache.disabledByFlag ? "cache reuse turned off by --no-build-cache" : "cache reuse off in config");
|
|
739
|
+
else {
|
|
740
|
+
const current = {
|
|
741
|
+
hash: storeHash ?? fingerprint,
|
|
742
|
+
sources: storeSources
|
|
743
|
+
};
|
|
744
|
+
const explained = explainBuildMiss({
|
|
745
|
+
root,
|
|
746
|
+
platform: "ios",
|
|
747
|
+
current,
|
|
748
|
+
rekeyedBy,
|
|
749
|
+
baselineDeps: { readState: d.readWorkspaceState }
|
|
750
|
+
});
|
|
751
|
+
missReason = explained.reason;
|
|
752
|
+
if (explained.previousHash && explained.changedNames.length) logWriter().write(fingerprintDiffRecord({
|
|
753
|
+
changed: explained.changedNames,
|
|
754
|
+
previousHash: explained.previousHash,
|
|
755
|
+
hash: current.hash
|
|
756
|
+
}));
|
|
757
|
+
}
|
|
758
|
+
buildFailure = {
|
|
759
|
+
...buildFailure,
|
|
760
|
+
missReason
|
|
761
|
+
};
|
|
762
|
+
phase("cache", `miss: ${missReason.summary}`);
|
|
763
|
+
if (missReason.kind === "no-baseline") {
|
|
764
|
+
const untracked = untrackedMissLine(d.untrackedNativeFiles({ projectRoot: root }));
|
|
765
|
+
if (untracked) note(chalk.dim(phaseLine("fingerprint", untracked)));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
745
768
|
async function buildArtifact() {
|
|
746
769
|
buildFailure = {
|
|
747
770
|
fingerprint,
|
|
@@ -768,6 +791,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
768
791
|
note(chalk.yellow(phaseLine("build", `could not take a build slot: ${e?.message || e}; building anyway`)));
|
|
769
792
|
}
|
|
770
793
|
const mutatingSteps = [];
|
|
794
|
+
const rekeyedBy = [];
|
|
771
795
|
const prebuild = d.planPrebuild(root, "ios", {
|
|
772
796
|
isExpo,
|
|
773
797
|
fingerprint,
|
|
@@ -845,6 +869,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
845
869
|
};
|
|
846
870
|
note(chalk.yellow(phaseLine("fingerprint", `unavailable after ${mutatingSteps.join(", ")}; the build will be installed but not cached`)));
|
|
847
871
|
} else if (after.moved) {
|
|
872
|
+
rekeyedBy.push(...mutatingSteps.map((mutation) => mutation === "prebuild" ? mutation : "pod install"));
|
|
848
873
|
storeHash = after.hash;
|
|
849
874
|
storeSources = after.sources;
|
|
850
875
|
storeKey = buildCacheKey("ios", after.hash, {
|
|
@@ -853,6 +878,11 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
853
878
|
isSimulator: !physical,
|
|
854
879
|
...buildProfile ? { buildProfile } : {}
|
|
855
880
|
});
|
|
881
|
+
buildFailure = {
|
|
882
|
+
...buildFailure,
|
|
883
|
+
fingerprint: storeHash,
|
|
884
|
+
cacheKey: storeKey
|
|
885
|
+
};
|
|
856
886
|
note(chalk.dim(phaseLine("fingerprint", `${shortHash(fingerprint)} -> ${shortHash(storeHash)} (after ${mutatingSteps.join(", ")})`)));
|
|
857
887
|
const late = useBuildCache ? d.resolveBuild("ios", storeKey) : null;
|
|
858
888
|
if (late) {
|
|
@@ -870,6 +900,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
870
900
|
}
|
|
871
901
|
}
|
|
872
902
|
if (!appPath) {
|
|
903
|
+
explainMiss(rekeyedBy);
|
|
873
904
|
step("compile");
|
|
874
905
|
phase("build", `compiling ${configuration || "Debug"} with xcodebuild`);
|
|
875
906
|
const result = await d.buildIos({
|
|
@@ -960,10 +991,17 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
960
991
|
hit: cacheHit,
|
|
961
992
|
providerName: remote?.name ?? providerName,
|
|
962
993
|
readEnabled: useBuildCache,
|
|
994
|
+
missReason: cacheHit ? null : missReason,
|
|
963
995
|
waitedForBuild,
|
|
964
996
|
compilation: compilationCache
|
|
965
997
|
},
|
|
966
|
-
failureFields:
|
|
998
|
+
failureFields: {
|
|
999
|
+
...buildFailure,
|
|
1000
|
+
fingerprint: storeHash,
|
|
1001
|
+
cacheKey: storeKey,
|
|
1002
|
+
cacheHit,
|
|
1003
|
+
cacheSkipped: !useBuildCache
|
|
1004
|
+
},
|
|
967
1005
|
completeUploads: async () => {
|
|
968
1006
|
const uploadWasAbandoned = await finishIosUpload(uploadPending, remote, phase, note);
|
|
969
1007
|
const outcome = providerUploadOutcome(providerUpload ? await providerUpload : null, providerName);
|
|
@@ -1499,7 +1537,7 @@ function collectorEntry() {
|
|
|
1499
1537
|
}
|
|
1500
1538
|
const COLLECTOR_EXIT_WAIT_MS = 2e3;
|
|
1501
1539
|
const COLLECTOR_POLL_MS = 25;
|
|
1502
|
-
async function stopPreviousCollector({ root, slot = "default", kill = (pid, signal) => signalProcessTree(pid, signal), alive = pidExists, readState = readWorkspaceState, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, note = (_line) => {} }) {
|
|
1540
|
+
async function stopPreviousCollector({ root, slot = "default", kill = (pid, signal) => signalProcessTree(pid, signal), alive = pidExists, readState = readWorkspaceState$1, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, note = (_line) => {} }) {
|
|
1503
1541
|
const previous = (readState(root)?.collectors)?.[deviceSlotKey("ios", slot)] || null;
|
|
1504
1542
|
const previousPid = Number(previous?.pid) || null;
|
|
1505
1543
|
let killed = null;
|
|
@@ -1524,7 +1562,7 @@ async function stopPreviousCollector({ root, slot = "default", kill = (pid, sign
|
|
|
1524
1562
|
}
|
|
1525
1563
|
return { killed };
|
|
1526
1564
|
}
|
|
1527
|
-
async function replaceCollector({ root, slot = "default", udid, bundleId, appName, appExecutable, physical = false, payloadUrl = null, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), alive = pidExists, readState = readWorkspaceState, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, note = (_line) => {} }) {
|
|
1565
|
+
async function replaceCollector({ root, slot = "default", udid, bundleId, appName, appExecutable, physical = false, payloadUrl = null, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), alive = pidExists, readState = readWorkspaceState$1, verify = verifyCollectorOwnership, waitMs = COLLECTOR_EXIT_WAIT_MS, note = (_line) => {} }) {
|
|
1528
1566
|
const { killed } = await stopPreviousCollector({
|
|
1529
1567
|
root,
|
|
1530
1568
|
slot,
|
|
@@ -1608,7 +1646,7 @@ const DEFAULT_DEPS = {
|
|
|
1608
1646
|
resolveProjectMetro,
|
|
1609
1647
|
startDevServer,
|
|
1610
1648
|
warmMetro,
|
|
1611
|
-
readWorkspaceState,
|
|
1649
|
+
readWorkspaceState: readWorkspaceState$1,
|
|
1612
1650
|
pidExists,
|
|
1613
1651
|
getConcurrencyLimits,
|
|
1614
1652
|
fingerprintProject,
|
|
@@ -1861,7 +1899,7 @@ function launchFailureRemedy(remoteDevice, udid, bundleId, logFile) {
|
|
|
1861
1899
|
}
|
|
1862
1900
|
async function finishIosRun({ artifact, d, root, slot, json, release, configuration, buildScheme, isExpo, metroCheck, metroPort, logsDir, logFile, device, udid, physical, wireless, lanAddress, lanOriginUrl, remoteDevice, bootPromise, bootDuration, fail, phase, note, logWriter, elapsed, startedAt, closeWriter, lease, releaseLease, recordRun, reclaimed, devServer, enterPhase }) {
|
|
1863
1901
|
const { path: appPath, bundleId: initialBundleId, failureFields: buildFailure, cache } = artifact;
|
|
1864
|
-
const { hit: cacheHit, providerName, readEnabled: useBuildCache, waitedForBuild, compilation: compilationCache } = cache;
|
|
1902
|
+
const { hit: cacheHit, providerName, readEnabled: useBuildCache, missReason, waitedForBuild, compilation: compilationCache } = cache;
|
|
1865
1903
|
const storeHash = cache.identity?.fingerprint ?? null;
|
|
1866
1904
|
const storeKey = cache.identity?.key ?? null;
|
|
1867
1905
|
const runCommand = nativeRunCommand("ios", slot, {
|
|
@@ -2219,6 +2257,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2219
2257
|
storeHash,
|
|
2220
2258
|
storeKey,
|
|
2221
2259
|
cacheHit,
|
|
2260
|
+
missReason,
|
|
2222
2261
|
compilationCache,
|
|
2223
2262
|
useBuildCache,
|
|
2224
2263
|
waitedForBuild,
|
|
@@ -2236,6 +2275,144 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2236
2275
|
};
|
|
2237
2276
|
}
|
|
2238
2277
|
//#endregion
|
|
2278
|
+
//#region src/commands/ios/next-build.ts
|
|
2279
|
+
function note(line) {
|
|
2280
|
+
console.error(line);
|
|
2281
|
+
}
|
|
2282
|
+
function runOnlyFlag(opts) {
|
|
2283
|
+
if (isPhysicalDeviceRequest(opts.device)) return "--device";
|
|
2284
|
+
if (opts.remote) return "--remote";
|
|
2285
|
+
if (opts.wait !== void 0) return opts.wait === false ? "--no-wait" : "--wait";
|
|
2286
|
+
if (opts.simulatorApp !== void 0) return "--simulator-app";
|
|
2287
|
+
if (opts.metroCheck === false) return "--no-metro-check";
|
|
2288
|
+
return null;
|
|
2289
|
+
}
|
|
2290
|
+
async function planIos(opts, d, schemeRefusal) {
|
|
2291
|
+
const json = Boolean(opts.json);
|
|
2292
|
+
const refuse = (refusal, lines = []) => refusePlan(refusal, json, lines);
|
|
2293
|
+
const flag = runOnlyFlag(opts);
|
|
2294
|
+
if (flag) return refuse(planFlagRefusal(flag));
|
|
2295
|
+
const root = d.findProjectRoot(process.cwd());
|
|
2296
|
+
if (!root) return refuse(NO_PROJECT_REFUSAL);
|
|
2297
|
+
const projectProblem = appProjectProblem(root);
|
|
2298
|
+
if (projectProblem) return refuse({
|
|
2299
|
+
code: "STIM_NO_PROJECT",
|
|
2300
|
+
...projectProblem
|
|
2301
|
+
});
|
|
2302
|
+
const settingsContext = {
|
|
2303
|
+
projectPath: root,
|
|
2304
|
+
gitCommonDir: d.gitCommonDir(root),
|
|
2305
|
+
repoRoot: d.repoRoot(root)
|
|
2306
|
+
};
|
|
2307
|
+
const settings = d.resolveSettings(settingsContext);
|
|
2308
|
+
const [shapeError, ...moreShapeErrors] = settingShapeErrors(settings);
|
|
2309
|
+
if (shapeError) return refuse({
|
|
2310
|
+
code: "STIM_BAD_ARG",
|
|
2311
|
+
message: shapeError,
|
|
2312
|
+
remedy: SETTING_SHAPE_REMEDY
|
|
2313
|
+
}, moreShapeErrors);
|
|
2314
|
+
let optimizations;
|
|
2315
|
+
try {
|
|
2316
|
+
optimizations = resolveOptimizations(settings);
|
|
2317
|
+
} catch (error) {
|
|
2318
|
+
return refuse({
|
|
2319
|
+
code: "STIM_BAD_ARG",
|
|
2320
|
+
message: error.message,
|
|
2321
|
+
remedy: SETTING_SHAPE_REMEDY
|
|
2322
|
+
});
|
|
2323
|
+
}
|
|
2324
|
+
const cacheProviderError = cacheProviderSettingError(settings);
|
|
2325
|
+
if (cacheProviderError) note(chalk.yellow(phaseLine("cache", `${cacheProviderError} Using the local cache.`)));
|
|
2326
|
+
const slot = opts.slot ?? "default";
|
|
2327
|
+
const target = {
|
|
2328
|
+
platform: "ios",
|
|
2329
|
+
slot,
|
|
2330
|
+
root,
|
|
2331
|
+
projectKey: statsProjectKey({
|
|
2332
|
+
root,
|
|
2333
|
+
commonDir: settingsContext.gitCommonDir,
|
|
2334
|
+
repoRoot: settingsContext.repoRoot
|
|
2335
|
+
})
|
|
2336
|
+
};
|
|
2337
|
+
const isExpo = d.detectIsExpo(root);
|
|
2338
|
+
const modelRefusal = deviceModelRefusal({
|
|
2339
|
+
slot,
|
|
2340
|
+
deviceTypeFlag: opts.deviceType,
|
|
2341
|
+
runtimeFlag: opts.runtime,
|
|
2342
|
+
deviceType: resolveDeviceType(opts.deviceType, settings),
|
|
2343
|
+
runtime: resolveRuntime(opts.runtime, settings),
|
|
2344
|
+
physical: false,
|
|
2345
|
+
remoteBackend: remoteIosSetting(settings),
|
|
2346
|
+
listRuntimes: d.listIosRuntimes
|
|
2347
|
+
});
|
|
2348
|
+
if (modelRefusal) return refuse(modelRefusal);
|
|
2349
|
+
if (opts.easProfile !== void 0) {
|
|
2350
|
+
const eas = await planEasDevelopmentBuild({
|
|
2351
|
+
root,
|
|
2352
|
+
platform: "ios",
|
|
2353
|
+
profile: opts.easProfile,
|
|
2354
|
+
note,
|
|
2355
|
+
isExpo,
|
|
2356
|
+
selectors: [opts.scheme, opts.configuration],
|
|
2357
|
+
buildCache: opts.buildCache
|
|
2358
|
+
});
|
|
2359
|
+
if (!eas.ok) return refuse(eas);
|
|
2360
|
+
return printPlan(planPayload(target, {
|
|
2361
|
+
fingerprint: eas.fingerprint,
|
|
2362
|
+
cacheKey: eas.cacheKey,
|
|
2363
|
+
cacheHit: eas.buildId ? "remote" : false,
|
|
2364
|
+
provider: "eas",
|
|
2365
|
+
cacheSkipped: false,
|
|
2366
|
+
prebuild: null,
|
|
2367
|
+
refusal: eas.missing
|
|
2368
|
+
}), json);
|
|
2369
|
+
}
|
|
2370
|
+
const refusal = schemeRefusal(root, opts.scheme, isExpo);
|
|
2371
|
+
if (refusal) return refuse({
|
|
2372
|
+
code: refusal.code,
|
|
2373
|
+
message: refusal.message ?? "",
|
|
2374
|
+
remedy: refusal.remedy ?? ""
|
|
2375
|
+
});
|
|
2376
|
+
const configuration = resolveConfiguration(opts.configuration, settings);
|
|
2377
|
+
const buildProfile = optimizationBuildProfile("ios", optimizations);
|
|
2378
|
+
const cachePolicy = artifactCachePolicy(optimizations, opts.buildCache !== false, isReleaseConfiguration(configuration));
|
|
2379
|
+
let fingerprint;
|
|
2380
|
+
try {
|
|
2381
|
+
fingerprint = await d.fingerprintProject(root, { platform: "ios" });
|
|
2382
|
+
} catch (error) {
|
|
2383
|
+
note(chalk.dim(`Fingerprinting failed: ${error?.message || error}`));
|
|
2384
|
+
}
|
|
2385
|
+
if (!fingerprint?.hash) return refuse({
|
|
2386
|
+
code: "STIM_NO_FINGERPRINT",
|
|
2387
|
+
message: `Could not fingerprint ${root}: @expo/fingerprint produced no hash for it.`,
|
|
2388
|
+
remedy: "Check the project native inputs and the @expo/fingerprint error above, then retry."
|
|
2389
|
+
});
|
|
2390
|
+
const cacheKey = buildCacheKey("ios", fingerprint.hash, {
|
|
2391
|
+
scheme: opts.scheme,
|
|
2392
|
+
...configuration ? { configuration } : {},
|
|
2393
|
+
isSimulator: true,
|
|
2394
|
+
...buildProfile ? { buildProfile } : {}
|
|
2395
|
+
});
|
|
2396
|
+
const plan = await planCachedBuild({
|
|
2397
|
+
...target,
|
|
2398
|
+
isExpo,
|
|
2399
|
+
fingerprint: fingerprint.hash,
|
|
2400
|
+
sources: fingerprint.sources ?? [],
|
|
2401
|
+
cacheKey,
|
|
2402
|
+
cachePolicy,
|
|
2403
|
+
providerConfig: d.resolveCacheProviderConfig(settingsContext),
|
|
2404
|
+
expoRemote: cachePolicy.remote && !buildProfile && !opts.scheme ? { runOptions: configuration ? { configuration } : null } : null
|
|
2405
|
+
}, {
|
|
2406
|
+
loadCacheProvider: d.loadCacheProvider,
|
|
2407
|
+
loadProjectProvider: d.loadProjectProvider,
|
|
2408
|
+
checkEasAuth: d.checkEasAuth,
|
|
2409
|
+
resolveRemote: d.resolveRemote,
|
|
2410
|
+
planPrebuild: d.planPrebuild,
|
|
2411
|
+
note
|
|
2412
|
+
});
|
|
2413
|
+
printPlan(plan, json);
|
|
2414
|
+
}
|
|
2415
|
+
//#endregion
|
|
2239
2416
|
//#region src/commands/ios.ts
|
|
2240
2417
|
function writeNote(line) {
|
|
2241
2418
|
console.error(line);
|
|
@@ -2247,16 +2424,28 @@ function iosCommand(program) {
|
|
|
2247
2424
|
registerIos(program);
|
|
2248
2425
|
}
|
|
2249
2426
|
function registerIos(program, deps = {}) {
|
|
2250
|
-
program.command("ios").description("Build (or restore from the fingerprint cache), install and launch this workspace's app on its owned simulator, 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("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--scheme <name>", "Shared Xcode app scheme to build; overrides automatic scheme selection, not the app URL scheme").option("--no-metro-check", "Skip the \"is this workspace's dev server running?\" check: do not start it, and build anyway").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("--configuration <name>", "Xcode configuration to build (e.g. Release). A non-Debug configuration embeds the JS bundle and skips Metro entirely. Overrides the ios.configuration setting. Default: Debug").option("--device-type <name>", "Simulator model to create this workspace's owned sim as, exactly as `xcrun simctl list devicetypes` names it (e.g. \"iPad Pro 13-inch (M5)\"). Overrides the ios.deviceType setting for this invocation. A model no installed runtime can create refuses with STIM_BAD_ARG and prints the models they do offer.").option("--runtime <version>", "Simulator runtime to create this workspace's owned sim on, as a version (\"18.5\") or a runtime's full name (\"iOS 18.5\"); nothing else matches. Overrides the ios.runtime setting for this invocation. An unknown version refuses with STIM_BAD_ARG and prints the installed runtimes.").option("--simulator-app <app>", "Open the owned simulator in xcode, siniulator, or stim-desktop for this run, overriding the machine iosSimulatorApp setting. Also opens an already running simulator; local simulators only.").option("--device [udid]", "Build the iphoneos slice for a connected iPhone, install it, and launch it, instead of using this workspace's owned simulator. The phone can be cabled or paired over Wi-Fi. With no UDID, the first cabled device this workspace can lease is used, waiting for one that is busy; a Wi-Fi device is used only when no cabled one is connected and ready. In Debug the app is wired to this workspace's Metro over the LAN. 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) => {
|
|
2427
|
+
program.command("ios").description("Build (or restore from the fingerprint cache), install and launch this workspace's app on its owned simulator, 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("--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("--scheme <name>", "Shared Xcode app scheme to build; overrides automatic scheme selection, not the app URL scheme").option("--no-metro-check", "Skip the \"is this workspace's dev server running?\" check: do not start it, and build anyway").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("--configuration <name>", "Xcode configuration to build (e.g. Release). A non-Debug configuration embeds the JS bundle and skips Metro entirely. Overrides the ios.configuration setting. Default: Debug").option("--device-type <name>", "Simulator model to create this workspace's owned sim as, exactly as `xcrun simctl list devicetypes` names it (e.g. \"iPad Pro 13-inch (M5)\"). Overrides the ios.deviceType setting for this invocation. A model no installed runtime can create refuses with STIM_BAD_ARG and prints the models they do offer.").option("--runtime <version>", "Simulator runtime to create this workspace's owned sim on, as a version (\"18.5\") or a runtime's full name (\"iOS 18.5\"); nothing else matches. Overrides the ios.runtime setting for this invocation. An unknown version refuses with STIM_BAD_ARG and prints the installed runtimes.").option("--simulator-app <app>", "Open the owned simulator in xcode, siniulator, or stim-desktop for this run, overriding the machine iosSimulatorApp setting. Also opens an already running simulator; local simulators only.").option("--device [udid]", "Build the iphoneos slice for a connected iPhone, install it, and launch it, instead of using this workspace's owned simulator. The phone can be cabled or paired over Wi-Fi. With no UDID, the first cabled device this workspace can lease is used, waiting for one that is busy; a Wi-Fi device is used only when no cabled one is connected and ready. In Debug the app is wired to this workspace's Metro over the LAN. 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) => {
|
|
2251
2428
|
if (REMOTE_DEVICE_BACKENDS.includes(value)) return value;
|
|
2252
2429
|
throw new InvalidArgumentError(`expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}`);
|
|
2253
2430
|
}).option("--wait <seconds>", "How long to wait for another workspace to release the phone it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once). Only with --device.").option("--no-wait", "Install on a phone 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) => {
|
|
2431
|
+
if (opts.plan) {
|
|
2432
|
+
const d = {
|
|
2433
|
+
...DEFAULT_DEPS,
|
|
2434
|
+
...deps
|
|
2435
|
+
};
|
|
2436
|
+
await planIos(opts, d, (root, scheme, isExpo) => explicitSchemeRefusal(root, scheme, isExpo, d));
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2254
2439
|
const root = (deps.findProjectRoot ?? DEFAULT_DEPS.findProjectRoot)(process.cwd());
|
|
2255
2440
|
const run = (progress) => runIos({
|
|
2256
2441
|
...opts,
|
|
2257
2442
|
waitConflict: waitFlagConflict(process.argv)
|
|
2258
2443
|
}, deps, progress);
|
|
2259
|
-
const completion = root ? await
|
|
2444
|
+
const completion = root ? await withNativeBuildRun(root, {
|
|
2445
|
+
command: "ios",
|
|
2446
|
+
platform: "ios",
|
|
2447
|
+
slot: opts.slot ?? "default"
|
|
2448
|
+
}, async (claim) => {
|
|
2260
2449
|
recordWorkspaceUse(root);
|
|
2261
2450
|
const progress = startBuildProgress({
|
|
2262
2451
|
root,
|
|
@@ -2270,15 +2459,22 @@ function registerIos(program, deps = {}) {
|
|
|
2270
2459
|
} finally {
|
|
2271
2460
|
progress.clear();
|
|
2272
2461
|
}
|
|
2273
|
-
}, {
|
|
2274
|
-
|
|
2275
|
-
waitMs: 18e5,
|
|
2276
|
-
declareSpawns: true
|
|
2277
|
-
}) : await run();
|
|
2278
|
-
if (!completion) process.exit(1);
|
|
2462
|
+
}, { write: (line) => writeNote(chalk.dim(phaseLine("lock", line))) }) : await run();
|
|
2463
|
+
if (!completion) process.exit(runCancellation() ? 130 : 1);
|
|
2279
2464
|
else if (completion.uploadsAbandoned) exitAfterFlush(0);
|
|
2280
2465
|
});
|
|
2281
2466
|
}
|
|
2467
|
+
function unlessCancelled(result) {
|
|
2468
|
+
if (!result.ok || !runCancellation()) return result;
|
|
2469
|
+
return {
|
|
2470
|
+
ok: false,
|
|
2471
|
+
failure: {
|
|
2472
|
+
code: "STIM_CANCELLED",
|
|
2473
|
+
message: "before install"
|
|
2474
|
+
},
|
|
2475
|
+
compilationCache: result.artifact.cache.compilation
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2282
2478
|
function explicitSchemeRefusal(root, scheme, isExpo, d) {
|
|
2283
2479
|
if (scheme === void 0) return null;
|
|
2284
2480
|
if (!scheme.trim()) return {
|
|
@@ -2412,6 +2608,15 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2412
2608
|
let compilationCache = COMPILATION_CACHE_NOT_RUN;
|
|
2413
2609
|
let reclaimed = [];
|
|
2414
2610
|
const fail = ({ code, message, remedy = null, lines = [], logPath = null, build = null, lease }) => {
|
|
2611
|
+
({code, message, remedy, lines} = cancelledFailure("ios", {
|
|
2612
|
+
code,
|
|
2613
|
+
message
|
|
2614
|
+
}) ?? {
|
|
2615
|
+
code,
|
|
2616
|
+
message,
|
|
2617
|
+
remedy,
|
|
2618
|
+
lines
|
|
2619
|
+
});
|
|
2415
2620
|
releaseLease();
|
|
2416
2621
|
if (message) note(chalk.red(phaseLine("error", message)));
|
|
2417
2622
|
for (const line of lines) note(chalk.dim(phaseLine("", line)));
|
|
@@ -2794,7 +2999,6 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2794
2999
|
}
|
|
2795
3000
|
let artifact = null;
|
|
2796
3001
|
try {
|
|
2797
|
-
const bootTimer = stepTimer(d.now);
|
|
2798
3002
|
const boot = () => physicalDevice ? Promise.resolve({
|
|
2799
3003
|
ok: true,
|
|
2800
3004
|
udid: physicalDevice.udid
|
|
@@ -2807,23 +3011,28 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2807
3011
|
ok: false,
|
|
2808
3012
|
reason: String(e?.message || e)
|
|
2809
3013
|
}));
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
3014
|
+
const startBoot = () => {
|
|
3015
|
+
const bootTimer = stepTimer(d.now);
|
|
3016
|
+
bootPromise = (remoteDevice?.ctx.backend === "eas" ? d.ensureRemoteBootOwned({
|
|
3017
|
+
root,
|
|
3018
|
+
platform: "ios",
|
|
3019
|
+
sessionName: ownedSessionName(remoteDevice.ctx.label),
|
|
3020
|
+
startedAt: new Date(d.now()).toISOString(),
|
|
3021
|
+
boot,
|
|
3022
|
+
createdSessionId: remoteDevice.createdSessionId,
|
|
3023
|
+
abandonCreatedSession: remoteDevice.abandonCreatedSession,
|
|
3024
|
+
webPreviewUrl: remoteDevice.webPreviewUrl,
|
|
3025
|
+
writeState: d.writeWorkspaceState,
|
|
3026
|
+
register: registerProject
|
|
3027
|
+
}) : boot()).then((result) => {
|
|
3028
|
+
bootDuration = bootTimer();
|
|
3029
|
+
return result;
|
|
3030
|
+
});
|
|
3031
|
+
return bootPromise.then((result) => result?.udid ?? "");
|
|
3032
|
+
};
|
|
3033
|
+
const localBoot = remoteDevice ? null : startBoot();
|
|
3034
|
+
udid = device.deviceUdid ?? await localBoot ?? "";
|
|
3035
|
+
const acquiredArtifact = unlessCancelled(await acquireIosArtifact({
|
|
2827
3036
|
root,
|
|
2828
3037
|
logFile,
|
|
2829
3038
|
udid,
|
|
@@ -2855,13 +3064,17 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2855
3064
|
stats,
|
|
2856
3065
|
step: progress.step
|
|
2857
3066
|
}
|
|
2858
|
-
}, d);
|
|
3067
|
+
}, d));
|
|
2859
3068
|
if (!acquiredArtifact.ok) {
|
|
2860
3069
|
compilationCache = acquiredArtifact.compilationCache;
|
|
2861
3070
|
return fail(acquiredArtifact.failure);
|
|
2862
3071
|
}
|
|
2863
3072
|
artifact = acquiredArtifact.artifact;
|
|
2864
3073
|
compilationCache = artifact.cache.compilation;
|
|
3074
|
+
if (!localBoot) {
|
|
3075
|
+
progress.step("install");
|
|
3076
|
+
udid = await startBoot();
|
|
3077
|
+
}
|
|
2865
3078
|
if (physicalDevice) {
|
|
2866
3079
|
const acquired = await d.acquireRunLease({
|
|
2867
3080
|
root,
|