stim 1.8.0 → 1.10.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 +23 -155
- package/dist/{android-DWssqHQ8.mjs → android-787HhP5w.mjs} +168 -39
- package/dist/{android-BRgBYzU0.mjs → android-DBkeHwpm.mjs} +250 -200
- package/dist/{android-DeYdjjBP.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-CITmIeWY.mjs} +22 -14
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/app-install-CrJ6t_bv.mjs +819 -0
- package/dist/budget-BP4jZZL4.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Pubfp8wV.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +7 -1
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-D5z2_bcF.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-BEq0Qw_a.mjs} +134 -121
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-DP4eWqea.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-92U593KT.mjs} +1090 -660
- package/dist/{device-RdujjHLB.mjs → device-DhTZe7L4.mjs} +13 -20
- package/dist/{build-lock-CgtsB6TV.mjs → device-lease-CbEaIk7b.mjs} +481 -27
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-Di8Q-9Ro.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-Dy1jGj3U.mjs} +645 -119
- package/dist/{doctor-BMt156qe.mjs → doctor-B-inAJmt.mjs} +137 -113
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-xxWKNO3-.mjs} +22 -17
- package/dist/exec-DK8KaVHK.mjs +133 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-ChPFZMRC.mjs} +836 -813
- package/dist/{guide-BTAlD1_y.mjs → guide-DwmaD_Wa.mjs} +953 -209
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle-DpRLp5lj.mjs +157 -0
- package/dist/{build-slots-C-oAHRT1.mjs → in-use-CjUluqIX.mjs} +102 -8
- package/dist/{ios-BcCiI4TS.mjs → ios-B2Fpqvlb.mjs} +60 -71
- package/dist/{ios-BP04pY5f.mjs → ios-Dd-hYJBh.mjs} +241 -234
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-BiOsSVzd.mjs} +3 -2
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-CtRdEVjx.mjs} +149 -52
- package/dist/launch-verify-CQS_Kg-C.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-MARIy6m9.mjs} +20 -15
- package/dist/metro-BWLOJ_Wr.mjs +409 -0
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-CDY9IkVC.mjs} +23 -43
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/{teardown-BJqEzPo_.mjs → ownership-DZjdx8Gq.mjs} +664 -612
- package/dist/{ports-BIbJaKNW.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-BXZzOABt.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-DoETJ3rl.mjs} +11 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DVbb7kXH.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-BvOCeakp.mjs} +8 -7
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-BXXorVM2.mjs → settings-DOugPlPz.mjs} +59 -159
- package/dist/settings-EWYNwe72.mjs +378 -0
- package/dist/settings.schema.json +1064 -0
- package/dist/simslim-Ca3487H6.mjs +436 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
- package/dist/spawn-claims-CUleC2cM.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-F9gv5dcC.mjs} +159 -114
- package/dist/start-VoFsPSes.mjs +2 -0
- package/dist/{state-DZobzxLW.mjs → state-WGdIbi_d.mjs} +5 -3
- package/dist/{stats-BYcZ6n1h.mjs → stats-BAgJaLA4.mjs} +66 -5
- package/dist/{stats-CLg5RuDS.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/status-DLCD-o3s.mjs +764 -0
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{guide-status-Craq9z0t.mjs → stim-installations-CINXy_su.mjs} +3 -122
- package/dist/{stop-C8JW6kKp.mjs → stop-Dj4pfmyv.mjs} +111 -31
- package/dist/{stop-B1kOpYei.mjs → stop-ZvOeTmKb.mjs} +2 -2
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +228 -42
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-BXA96myD.mjs} +14 -9
- package/dist/workspaces-BTUyFfkv.mjs +1003 -0
- package/dist/worktree-4aZg2NnI.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-BMS7GeqB.mjs} +523 -61
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-BlizKDpZ.mjs} +200 -54
- package/dist/{xcode-B6YaWeg0.mjs → xcode-B2tBkf0m.mjs} +66 -57
- package/package.json +6 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/device-lease-Ffz_M5t0.mjs +0 -359
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/logs-query-BGL-Pl12.mjs +0 -290
- package/dist/metro-C7bcJ0uo.mjs +0 -233
- package/dist/ownership-wolE-0Do.mjs +0 -470
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/workspace-state-BT5E3SA2.mjs +0 -146
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { a as
|
|
7
|
-
import { n as MODE_EXPO, p as writeWorkspaceLaunch, t as MODE_BARE } from "./state-
|
|
8
|
-
import {
|
|
9
|
-
import { n as
|
|
10
|
-
import { A as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { r as
|
|
20
|
-
import {
|
|
21
|
-
import { c as
|
|
22
|
-
import { a as
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { t as
|
|
26
|
-
import { a as
|
|
27
|
-
import {
|
|
28
|
-
import { a as
|
|
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
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
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";
|
|
5
|
+
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
|
|
6
|
+
import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
|
|
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
|
+
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 fingerprintDiffRecord, D as providerDownloadPath, E as prepareProviderDownloadDir, N as untrackedMissLine, O as providerUploadOutcome, P as untrackedNativeFiles, S as filesystemBuildCapability, T as fingerprintProject, _ as waitForBuild, b as describeFingerprintMiss, g as releaseBuildLock, j as storeBuild, k as refingerprintAfterMutation, m as acquireBuildLock, v as waitForSharedBuild, w as fingerprintDiffSuffix, y as buildCacheKey } from "./device-lease-CbEaIk7b.mjs";
|
|
11
|
+
import { n as NO_BUILD_PROGRESS, s as startBuildProgress } from "./build-progress-BXx-ZBe4.mjs";
|
|
12
|
+
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-DOugPlPz.mjs";
|
|
13
|
+
import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-DZjdx8Gq.mjs";
|
|
14
|
+
import { D as parseIosSimulatorApp, f as listIosRuntimes } from "./ios-B2Fpqvlb.mjs";
|
|
15
|
+
import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-CjUluqIX.mjs";
|
|
16
|
+
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-Dy1jGj3U.mjs";
|
|
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-CrJ6t_bv.mjs";
|
|
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-CQS_Kg-C.mjs";
|
|
20
|
+
import { c as unknownIosRuntimeRefusal, d as isEasBuildFailure, f as resolveEasDevelopmentBuild, r as checkDeviceCapacity, s as unknownIosDeviceTypeRefusal, u as easDeviceBuildRemedy } from "./simslim-Ca3487H6.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-Di8Q-9Ro.mjs";
|
|
22
|
+
import { _ as isPhysicalDeviceRequest, a as swapJsBundle, b as warmMetro, c as runPrebuild, d as ensureOwnedDevice, g as ensureWorkspaceStorageSafely, h as ensureDevServer, l as staleNativeDirRefusal, m as clearIosAdoptionPending, n as pickDevClientScheme, o as planPrebuild, r as schemesFromInfoPlist, s as recordPrebuild, t as devClientScheme, u as ensureBooted, v as launchOutcomeRecord, y as sleep } from "./dev-client-92U593KT.mjs";
|
|
23
|
+
import { t as budgetGate } from "./budget-BP4jZZL4.mjs";
|
|
24
|
+
import { f as spawnEntry, s as startDevServer } from "./start-F9gv5dcC.mjs";
|
|
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-B2tBkf0m.mjs";
|
|
27
|
+
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-C5cg0fmk.mjs";
|
|
28
|
+
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-xxWKNO3-.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-CtRdEVjx.mjs";
|
|
30
|
+
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-DP4eWqea.mjs";
|
|
29
31
|
import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
|
|
30
32
|
import { InvalidArgumentError } from "commander";
|
|
31
|
-
import { X509Certificate } from "node:crypto";
|
|
32
33
|
import { basename, join } from "node:path";
|
|
34
|
+
import { X509Certificate } from "node:crypto";
|
|
33
35
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
34
|
-
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
35
36
|
import chalk from "chalk";
|
|
37
|
+
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
36
38
|
//#region src/engine/ios-lan.ts
|
|
37
39
|
const IP_TXT = "ip.txt";
|
|
38
40
|
function chooseLanAddress({ pinned = null, candidates }) {
|
|
@@ -91,6 +93,7 @@ function copyAppAside(appPath, { exec = null, mkdtemp = () => makeTemporaryDirec
|
|
|
91
93
|
]);
|
|
92
94
|
} catch {
|
|
93
95
|
try {
|
|
96
|
+
removeTemporaryEntry(copy);
|
|
94
97
|
e.runFile("cp", [
|
|
95
98
|
"-R",
|
|
96
99
|
appPath,
|
|
@@ -170,7 +173,7 @@ function deviceModelRefusal({ slot, deviceTypeFlag, runtimeFlag, deviceType, run
|
|
|
170
173
|
if (typeof deviceTypeFlag === "string" && deviceTypeFlag.trim() === "") return {
|
|
171
174
|
code: "STIM_BAD_ARG",
|
|
172
175
|
message: "--device-type was given an empty name.",
|
|
173
|
-
remedy: "Pass `--device-type <name>` with a model `xcrun simctl list devicetypes` names, e.g. \"iPad Pro 13-inch (
|
|
176
|
+
remedy: "Pass `--device-type <name>` with a model `xcrun simctl list devicetypes` names, e.g. \"iPad Pro 13-inch (M5)\"."
|
|
174
177
|
};
|
|
175
178
|
if (typeof runtimeFlag === "string" && runtimeFlag.trim() === "") return {
|
|
176
179
|
code: "STIM_BAD_ARG",
|
|
@@ -248,7 +251,7 @@ function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false
|
|
|
248
251
|
if (errorCode) record.errorCode = errorCode;
|
|
249
252
|
return record;
|
|
250
253
|
}
|
|
251
|
-
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 }) {
|
|
254
|
+
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 }) {
|
|
252
255
|
return {
|
|
253
256
|
platform: "ios",
|
|
254
257
|
...slot && slot !== "default" ? { slot } : {},
|
|
@@ -275,7 +278,8 @@ function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, f
|
|
|
275
278
|
logs: { dir: logsDir },
|
|
276
279
|
durationMs,
|
|
277
280
|
...webPreviewUrl ? { webPreviewUrl } : {},
|
|
278
|
-
...lease === void 0 ? {} : { lease }
|
|
281
|
+
...lease === void 0 ? {} : { lease },
|
|
282
|
+
...devServer ? { devServer } : {}
|
|
279
283
|
};
|
|
280
284
|
}
|
|
281
285
|
function writeLastBuild(root, record, { write = writeWorkspaceState } = {}) {
|
|
@@ -301,7 +305,7 @@ async function finishIosUpload(uploadPending, remote, phase, note) {
|
|
|
301
305
|
}
|
|
302
306
|
return false;
|
|
303
307
|
}
|
|
304
|
-
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 }) {
|
|
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 }) {
|
|
305
309
|
const durationMs = elapsed();
|
|
306
310
|
recordRun({
|
|
307
311
|
failed: false,
|
|
@@ -343,15 +347,19 @@ function reportIosResult({ slot, d, root, json, release, configuration, buildSch
|
|
|
343
347
|
durationMs,
|
|
344
348
|
launched: launchState,
|
|
345
349
|
webPreviewUrl,
|
|
346
|
-
lease
|
|
350
|
+
lease,
|
|
351
|
+
devServer
|
|
347
352
|
});
|
|
348
|
-
if (json) console.log(JSON.stringify(
|
|
353
|
+
if (json) console.log(JSON.stringify(reclaimed.length ? {
|
|
354
|
+
...facts,
|
|
355
|
+
reclaimed
|
|
356
|
+
} : facts));
|
|
349
357
|
else {
|
|
350
358
|
const summary = `${launchWarning ? "WARNING" : "OK"}: ${bundleId} on ${deviceLabel(device, udid)}, ` + (release ? `${configuration} (embedded JS, no Metro)` : `Metro port ${metroPort}`) + ` (${cacheDescription(cacheHit, providerName)}, ${formatDuration(durationMs)})`;
|
|
351
359
|
const outcome = launchWarning ? chalk.yellow(`${summary} -- ${launchWarning}`) : launchState === "unverified" ? chalk.yellow(`${summary} -- launch UNVERIFIED`) : launchState === "bundling" ? chalk.green(`${summary} -- bundle requested, still building`) : chalk.green(summary);
|
|
352
360
|
const deviceName = device?.deviceName ?? device?.name ?? udid;
|
|
353
361
|
const cacheResult = useBuildCache ? cacheDescription(cacheHit, providerName) : "bypassed; built";
|
|
354
|
-
const metroResult = release ? `embedded (${configuration})` : !metroCheck ? `check skipped on port ${metroPort}` : launchState === "unverified" ? `state unverified on port ${metroPort}` : `running on port ${metroPort}`;
|
|
362
|
+
const metroResult = release ? `embedded (${configuration})` : !metroCheck ? `check skipped on port ${metroPort}` : launchState === "unverified" ? `state unverified on port ${metroPort}` : `running on port ${metroPort}${devServer ? ` (started: ${devServer.reason})` : ""}`;
|
|
355
363
|
console.log([
|
|
356
364
|
outcome,
|
|
357
365
|
phaseLine("device", `${deviceName} (${udid})`),
|
|
@@ -383,7 +391,7 @@ var ArtifactRefusal = class extends Error {
|
|
|
383
391
|
}
|
|
384
392
|
};
|
|
385
393
|
async function acquireIosArtifact({ root, logFile, udid, remoteDestination, device, configuration, buildScheme, buildProfile, isExpo, optimizations, cache, easBuild, easProfile, maxBuilds, progress }, d) {
|
|
386
|
-
const { phase, note, logWriter, estimates, stats } = progress;
|
|
394
|
+
const { phase, note, logWriter, estimates, stats, step } = progress;
|
|
387
395
|
const physical = device !== null;
|
|
388
396
|
const lanAddress = device?.lanAddress ?? null;
|
|
389
397
|
const metroPort = device?.metroPort ?? null;
|
|
@@ -481,6 +489,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
481
489
|
}
|
|
482
490
|
return;
|
|
483
491
|
}
|
|
492
|
+
step("cache-lookup");
|
|
484
493
|
const fingerprintTimer = stepTimer(d.now);
|
|
485
494
|
let computedFingerprint;
|
|
486
495
|
try {
|
|
@@ -605,107 +614,40 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
605
614
|
}
|
|
606
615
|
return remote;
|
|
607
616
|
}
|
|
608
|
-
async function
|
|
609
|
-
if (!useBuildCache) return;
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
note(chalk.yellow(phaseLine("build", `could not take the build lock: ${e?.message || e}; building anyway`)));
|
|
617
|
+
async function awaitSharedBuild() {
|
|
618
|
+
if (!useBuildCache || appPath) return;
|
|
619
|
+
const shared = await waitForSharedBuild({
|
|
620
|
+
platform: "ios",
|
|
621
|
+
key: cacheKey,
|
|
622
|
+
fingerprint,
|
|
623
|
+
root,
|
|
624
|
+
logFile,
|
|
625
|
+
command: "stim ios",
|
|
626
|
+
acquire: d.acquireBuildLock,
|
|
627
|
+
wait: d.waitForBuild,
|
|
628
|
+
now: d.now,
|
|
629
|
+
phase: (text) => {
|
|
630
|
+
step("wait");
|
|
631
|
+
phase("build", text);
|
|
632
|
+
},
|
|
633
|
+
warn: (text) => note(chalk.yellow(phaseLine("build", text))),
|
|
634
|
+
out: note
|
|
635
|
+
});
|
|
636
|
+
if (shared.refusal) fail({
|
|
637
|
+
...shared.refusal,
|
|
638
|
+
build: {
|
|
639
|
+
fingerprint,
|
|
640
|
+
cacheKey,
|
|
641
|
+
cacheHit,
|
|
642
|
+
cacheSkipped: !useBuildCache
|
|
635
643
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const held = attempt.held;
|
|
644
|
-
const who = held.projectRoot || "another workspace";
|
|
645
|
-
phase("build", `${who} is already building ${shortHash(fingerprint)} (pid ${held.pid})${held.logFile ? ` -- tail ${held.logFile}` : ""} -- stim guide lifecycle concurrency`);
|
|
646
|
-
let waited = null;
|
|
647
|
-
try {
|
|
648
|
-
const ceilingMs = WAIT_CEILING_MS - (d.now() - waitStarted);
|
|
649
|
-
if (ceilingMs <= 0) throw Object.assign(/* @__PURE__ */ new Error(`Waited ${formatDuration(d.now() - waitStarted)} for shared builds without an artifact; ${who} (pid ${held.pid}) holds ${attempt.path}.`), {
|
|
650
|
-
code: "STIM_BUILD_WAIT_TIMEOUT",
|
|
651
|
-
lockPath: attempt.path
|
|
652
|
-
});
|
|
653
|
-
waited = await d.waitForBuild({
|
|
654
|
-
platform: "ios",
|
|
655
|
-
key: cacheKey,
|
|
656
|
-
out: note,
|
|
657
|
-
ceilingMs
|
|
658
|
-
});
|
|
659
|
-
} catch (e) {
|
|
660
|
-
const refusal = (0, ownership_claim_exports.claimFailure)(e, "stim ios");
|
|
661
|
-
if (refusal) fail({
|
|
662
|
-
code: refusal.code,
|
|
663
|
-
message: refusal.message,
|
|
664
|
-
remedy: refusal.remedy,
|
|
665
|
-
build: {
|
|
666
|
-
fingerprint,
|
|
667
|
-
cacheKey,
|
|
668
|
-
cacheHit,
|
|
669
|
-
cacheSkipped: !useBuildCache
|
|
670
|
-
}
|
|
671
|
-
});
|
|
672
|
-
const err = e;
|
|
673
|
-
if (err?.code !== "STIM_BUILD_WAIT_TIMEOUT") throw e;
|
|
674
|
-
fail({
|
|
675
|
-
code: "STIM_BUILD_WAIT_TIMEOUT",
|
|
676
|
-
message: err.message,
|
|
677
|
-
remedy: `Check pid ${held.pid}; if it is not really building, remove ${err.lockPath} and run \`stim ios\` again.`,
|
|
678
|
-
build: {
|
|
679
|
-
fingerprint,
|
|
680
|
-
cacheKey,
|
|
681
|
-
cacheHit,
|
|
682
|
-
cacheSkipped: !useBuildCache
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
if (waited?.hit) {
|
|
687
|
-
appPath = waited.hit ?? null;
|
|
688
|
-
cacheHit = "local";
|
|
689
|
-
waitedForBuild = {
|
|
690
|
-
pid: held.pid,
|
|
691
|
-
ms: waited.waitedMs
|
|
692
|
-
};
|
|
693
|
-
phase("build", `waited ${formatDuration(waited.waitedMs)} for ${who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
|
|
694
|
-
} else if (waited?.lockReleased) {
|
|
695
|
-
failedHolder = void 0;
|
|
696
|
-
releasedWait = {
|
|
697
|
-
facts: {
|
|
698
|
-
pid: held.pid,
|
|
699
|
-
ms: waited.waitedMs
|
|
700
|
-
},
|
|
701
|
-
who
|
|
702
|
-
};
|
|
703
|
-
phase("build", `${who}'s build lock was released; rechecking this workspace before building`);
|
|
704
|
-
} else {
|
|
705
|
-
note(chalk.yellow(phaseLine("build", `${who}'s build ended without an artifact (${waited?.builderFailed}); retrying the build lock`)));
|
|
706
|
-
failedHolder = held;
|
|
707
|
-
}
|
|
708
|
-
} else break;
|
|
644
|
+
});
|
|
645
|
+
buildLock = shared.lock;
|
|
646
|
+
releasedWait = shared.released;
|
|
647
|
+
if (shared.hit) {
|
|
648
|
+
appPath = shared.hit.path;
|
|
649
|
+
cacheHit = "local";
|
|
650
|
+
waitedForBuild = shared.hit.waited;
|
|
709
651
|
}
|
|
710
652
|
}
|
|
711
653
|
const prepareDeviceApp = async (path, { fresh }) => {
|
|
@@ -826,8 +768,19 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
826
768
|
note(chalk.yellow(phaseLine("build", `could not take a build slot: ${e?.message || e}; building anyway`)));
|
|
827
769
|
}
|
|
828
770
|
const mutatingSteps = [];
|
|
829
|
-
|
|
830
|
-
|
|
771
|
+
const prebuild = d.planPrebuild(root, "ios", {
|
|
772
|
+
isExpo,
|
|
773
|
+
fingerprint,
|
|
774
|
+
sources: fingerprintSources
|
|
775
|
+
});
|
|
776
|
+
if (prebuild === "refuse") fail({
|
|
777
|
+
...staleNativeDirRefusal("ios"),
|
|
778
|
+
build: buildFailure
|
|
779
|
+
});
|
|
780
|
+
if (prebuild === "generate" || prebuild === "regenerate") {
|
|
781
|
+
step("prebuild");
|
|
782
|
+
recordPrebuild(root, "ios", null);
|
|
783
|
+
const result = await d.runPrebuild(root, "ios", logWriter(), { clean: prebuild === "regenerate" });
|
|
831
784
|
if (result?.failed) {
|
|
832
785
|
phase("prebuild", "FAILED");
|
|
833
786
|
fail({
|
|
@@ -838,12 +791,25 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
838
791
|
build: buildFailure
|
|
839
792
|
});
|
|
840
793
|
}
|
|
841
|
-
phase("prebuild",
|
|
794
|
+
phase("prebuild", `${prebuild === "generate" ? "ios/ absent -> generated" : "ios/ not generated from this fingerprint -> regenerated with --clean"} (${formatDuration(result?.durationMs ?? 0)})`);
|
|
842
795
|
mutatingSteps.push("prebuild");
|
|
843
796
|
}
|
|
797
|
+
if (isExpo && buildScheme !== void 0) {
|
|
798
|
+
const project = d.discoverXcodeProject(root);
|
|
799
|
+
if (project.error) fail({
|
|
800
|
+
...project.error,
|
|
801
|
+
build: buildFailure
|
|
802
|
+
});
|
|
803
|
+
const schemeError = d.resolveScheme(project, { scheme: buildScheme }).error;
|
|
804
|
+
if (schemeError) fail({
|
|
805
|
+
...schemeError,
|
|
806
|
+
build: buildFailure
|
|
807
|
+
});
|
|
808
|
+
}
|
|
844
809
|
const podState = d.readPodState(root);
|
|
845
810
|
const action = podAction(podState, d.podsAreStale(podState.lockText, podState.manifestText));
|
|
846
811
|
if (action.install) {
|
|
812
|
+
step("pods");
|
|
847
813
|
const result = await d.runPodInstall(root, logWriter(), { estimateMs: estimates().podsMs });
|
|
848
814
|
const podCommand = result?.command || "pod install";
|
|
849
815
|
for (const line of result?.notes || []) note(chalk.dim(phaseLine("pods", line)));
|
|
@@ -868,6 +834,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
868
834
|
previousHash: fingerprint,
|
|
869
835
|
fingerprint: d.fingerprintProject
|
|
870
836
|
});
|
|
837
|
+
if (after && mutatingSteps.includes("prebuild")) recordPrebuild(root, "ios", after.hash);
|
|
871
838
|
if (!after) {
|
|
872
839
|
storeHash = null;
|
|
873
840
|
storeKey = null;
|
|
@@ -903,6 +870,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
903
870
|
}
|
|
904
871
|
}
|
|
905
872
|
if (!appPath) {
|
|
873
|
+
step("compile");
|
|
906
874
|
phase("build", `compiling ${configuration || "Debug"} with xcodebuild`);
|
|
907
875
|
const result = await d.buildIos({
|
|
908
876
|
root,
|
|
@@ -977,7 +945,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
977
945
|
await resolveInitialFingerprint();
|
|
978
946
|
if (!easBuild) {
|
|
979
947
|
remote = await resolveRemoteArtifact();
|
|
980
|
-
await
|
|
948
|
+
await awaitSharedBuild();
|
|
981
949
|
await prepareCachedArtifact();
|
|
982
950
|
await buildArtifact();
|
|
983
951
|
}
|
|
@@ -1229,7 +1197,7 @@ function profileGate(input) {
|
|
|
1229
1197
|
if (!input.profile) return {
|
|
1230
1198
|
ok: false,
|
|
1231
1199
|
code: SIGNING_CODES.noProfile,
|
|
1232
|
-
reason: "`
|
|
1200
|
+
reason: "`openssl smime` could not decode the app bundle's embedded.mobileprovision.",
|
|
1233
1201
|
remedy: `The profile inside the app is corrupt. Delete the build cache entry with \`stim gc --delete\`, then ${XCODE_STEP}`
|
|
1234
1202
|
};
|
|
1235
1203
|
const profile = input.profile;
|
|
@@ -1335,10 +1303,13 @@ function readEmbeddedProfile(appPath, { exec = null } = {}) {
|
|
|
1335
1303
|
try {
|
|
1336
1304
|
return {
|
|
1337
1305
|
present: true,
|
|
1338
|
-
profile: parseProvisioningProfilePlist(executor.runFile("
|
|
1339
|
-
"
|
|
1340
|
-
"-
|
|
1341
|
-
"-
|
|
1306
|
+
profile: parseProvisioningProfilePlist(executor.runFile("/usr/bin/openssl", [
|
|
1307
|
+
"smime",
|
|
1308
|
+
"-verify",
|
|
1309
|
+
"-noverify",
|
|
1310
|
+
"-inform",
|
|
1311
|
+
"DER",
|
|
1312
|
+
"-in",
|
|
1342
1313
|
path
|
|
1343
1314
|
], { timeoutMs: SIGNING_TIMEOUT_MS }))
|
|
1344
1315
|
};
|
|
@@ -1624,8 +1595,8 @@ const DEFAULT_DEPS = {
|
|
|
1624
1595
|
devClientScheme,
|
|
1625
1596
|
getProject,
|
|
1626
1597
|
upsertProject,
|
|
1627
|
-
projectShortcut,
|
|
1628
1598
|
checkDeviceCapacity,
|
|
1599
|
+
budgetGate,
|
|
1629
1600
|
ensureOwnedDevice,
|
|
1630
1601
|
listIosRuntimes,
|
|
1631
1602
|
ensureBooted,
|
|
@@ -1635,7 +1606,7 @@ const DEFAULT_DEPS = {
|
|
|
1635
1606
|
ensureRemoteBootOwned,
|
|
1636
1607
|
detectProviders,
|
|
1637
1608
|
resolveProjectMetro,
|
|
1638
|
-
|
|
1609
|
+
startDevServer,
|
|
1639
1610
|
warmMetro,
|
|
1640
1611
|
readWorkspaceState,
|
|
1641
1612
|
pidExists,
|
|
@@ -1656,7 +1627,7 @@ const DEFAULT_DEPS = {
|
|
|
1656
1627
|
resolveEasCliBin,
|
|
1657
1628
|
resolveRemote,
|
|
1658
1629
|
uploadRemote,
|
|
1659
|
-
|
|
1630
|
+
planPrebuild,
|
|
1660
1631
|
runPrebuild,
|
|
1661
1632
|
readPodState,
|
|
1662
1633
|
podsAreStale,
|
|
@@ -1838,6 +1809,12 @@ function reportLaunchErrors(errors, note, root) {
|
|
|
1838
1809
|
for (const line of report.lines) note(chalk.yellow(phaseLine("launch", line)));
|
|
1839
1810
|
return report.lines.length > 0;
|
|
1840
1811
|
}
|
|
1812
|
+
function installsOverWifi(d, udid, selectedWireless, note) {
|
|
1813
|
+
const current = d.listIosDevices().find((entry) => entry.udid === udid);
|
|
1814
|
+
const wireless = current ? isWirelessIosDevice(current) : selectedWireless;
|
|
1815
|
+
if (wireless) note(phaseLine("device", `${current?.name ?? udid} is paired over Wi-Fi, so the install and launch go over the network and take longer than over a cable`));
|
|
1816
|
+
return wireless;
|
|
1817
|
+
}
|
|
1841
1818
|
function cleanAdoptedIosApps({ d, root, slot, udid, bundleId, phase, note }) {
|
|
1842
1819
|
const swept = d.clearOtherUserApps({
|
|
1843
1820
|
udid,
|
|
@@ -1875,10 +1852,14 @@ function recordIosReloadTarget({ d, root, physical, remoteDevice, bundleId, udid
|
|
|
1875
1852
|
note(chalk.yellow(phaseLine("state", `could not record iOS launch: ${error?.message || error}`)));
|
|
1876
1853
|
}
|
|
1877
1854
|
}
|
|
1878
|
-
function
|
|
1879
|
-
return
|
|
1855
|
+
function installFailureRemedy(remoteDevice) {
|
|
1856
|
+
return remoteDevice?.failureRemedy() ?? "Check that the simulator is booted and that the app was built for the simulator SDK.";
|
|
1857
|
+
}
|
|
1858
|
+
function launchFailureRemedy(remoteDevice, udid, bundleId, logFile) {
|
|
1859
|
+
if (remoteDevice) return remoteDevice.failureRemedy();
|
|
1860
|
+
return `If the simulator timed out, run \`stim doctor --platform ios\` and resolve any reported host memory pressure before retrying. Otherwise run \`xcrun simctl launch --terminate-running-process --console ${udid} ${bundleId}\` to see what the app reports, and check ${logFile}.`;
|
|
1880
1861
|
}
|
|
1881
|
-
async function finishIosRun({ artifact, d, root, slot, json, release, configuration, buildScheme, isExpo, metroCheck, metroPort, logsDir, logFile, device, udid, physical, lanAddress, lanOriginUrl, remoteDevice, bootPromise, bootDuration, fail, phase, note, logWriter, elapsed, startedAt, closeWriter, lease, releaseLease, recordRun }) {
|
|
1862
|
+
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 }) {
|
|
1882
1863
|
const { path: appPath, bundleId: initialBundleId, failureFields: buildFailure, cache } = artifact;
|
|
1883
1864
|
const { hit: cacheHit, providerName, readEnabled: useBuildCache, waitedForBuild, compilation: compilationCache } = cache;
|
|
1884
1865
|
const storeHash = cache.identity?.fingerprint ?? null;
|
|
@@ -1918,6 +1899,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1918
1899
|
}
|
|
1919
1900
|
});
|
|
1920
1901
|
if (bundleId) d.upsertProject(root, { bundleId });
|
|
1902
|
+
enterPhase("install");
|
|
1921
1903
|
const booted = await bootPromise;
|
|
1922
1904
|
if (!booted?.ok) return fail({
|
|
1923
1905
|
code: booted?.code || "STIM_NO_DEVICE",
|
|
@@ -1934,7 +1916,9 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1934
1916
|
let launched = null;
|
|
1935
1917
|
let launchedAt = d.now();
|
|
1936
1918
|
if (physical) {
|
|
1937
|
-
const
|
|
1919
|
+
const overWifi = installsOverWifi(d, udid, wireless, note);
|
|
1920
|
+
const bounds = iosDeviceBounds(overWifi);
|
|
1921
|
+
const lostBeforeInstall = raiseLeaseFor(bounds.installMs, true);
|
|
1938
1922
|
if (lostBeforeInstall) return fail(lostBeforeInstall);
|
|
1939
1923
|
await d.stopPreviousCollector({
|
|
1940
1924
|
root,
|
|
@@ -1944,8 +1928,9 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1944
1928
|
const installed = d.installIosDeviceApp({
|
|
1945
1929
|
udid,
|
|
1946
1930
|
appPath,
|
|
1947
|
-
bundleId
|
|
1948
|
-
|
|
1931
|
+
bundleId,
|
|
1932
|
+
wireless: overWifi
|
|
1933
|
+
}, { beforeStep: () => raiseLeaseFor(bounds.installMs, false) });
|
|
1949
1934
|
if (installed?.failed) {
|
|
1950
1935
|
dropSwapDir();
|
|
1951
1936
|
return fail({
|
|
@@ -1970,8 +1955,9 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1970
1955
|
});
|
|
1971
1956
|
}
|
|
1972
1957
|
dropSwapDir();
|
|
1973
|
-
raiseLeaseFor(COLLECTOR_EXIT_WAIT_MS +
|
|
1958
|
+
raiseLeaseFor(COLLECTOR_EXIT_WAIT_MS + bounds.launchMs, false);
|
|
1974
1959
|
const payloadUrl = scheme && metroPort !== null && lanAddress ? devClientUrl(scheme, metroPort, lanAddress) : null;
|
|
1960
|
+
enterPhase("launch");
|
|
1975
1961
|
const launchTimer = stepTimer(d.now);
|
|
1976
1962
|
launchedAt = d.now();
|
|
1977
1963
|
logWriter().write({
|
|
@@ -2012,10 +1998,11 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2012
1998
|
bundleId,
|
|
2013
1999
|
appName: appName ?? bundleId,
|
|
2014
2000
|
collectorPid: collector.pid,
|
|
2001
|
+
wireless: overWifi,
|
|
2015
2002
|
readRecords: () => readCollectorRecords(logsDir).filter((entry) => Number(entry.ts) >= launchedAt && (entry.slot ?? "default") === (slot ?? "default"))
|
|
2016
2003
|
});
|
|
2017
2004
|
if (started.failed || !started.pid) return fail({
|
|
2018
|
-
code: "STIM_LAUNCH_FAILED",
|
|
2005
|
+
code: started.code ?? "STIM_LAUNCH_FAILED",
|
|
2019
2006
|
message: started.reason ?? `${bundleId} did not start on ${udid}.`,
|
|
2020
2007
|
remedy: started.remedy ?? null,
|
|
2021
2008
|
lines: started.lines ?? [],
|
|
@@ -2067,7 +2054,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2067
2054
|
if (installed?.failed) return fail({
|
|
2068
2055
|
code: installed.code || "STIM_INSTALL_FAILED",
|
|
2069
2056
|
message: installed.reason,
|
|
2070
|
-
remedy:
|
|
2057
|
+
remedy: installFailureRemedy(remoteDevice),
|
|
2071
2058
|
build: {
|
|
2072
2059
|
...buildFailure,
|
|
2073
2060
|
appPath,
|
|
@@ -2088,6 +2075,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2088
2075
|
appExecutable,
|
|
2089
2076
|
note
|
|
2090
2077
|
});
|
|
2078
|
+
enterPhase("launch");
|
|
2091
2079
|
const launchTimer = stepTimer(d.now);
|
|
2092
2080
|
launchedAt = d.now();
|
|
2093
2081
|
logWriter().write({
|
|
@@ -2127,7 +2115,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2127
2115
|
return fail({
|
|
2128
2116
|
code: launched.code || "STIM_LAUNCH_FAILED",
|
|
2129
2117
|
message: launched.reason,
|
|
2130
|
-
remedy:
|
|
2118
|
+
remedy: launchFailureRemedy(remoteDevice, udid, bundleId, logFile),
|
|
2131
2119
|
build: {
|
|
2132
2120
|
...buildFailure,
|
|
2133
2121
|
appPath,
|
|
@@ -2240,7 +2228,9 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2240
2228
|
closeWriter,
|
|
2241
2229
|
webPreviewUrl: remoteDevice?.webPreviewUrl() ?? null,
|
|
2242
2230
|
lease: physical ? leaseFacts : void 0,
|
|
2243
|
-
recordRun
|
|
2231
|
+
recordRun,
|
|
2232
|
+
reclaimed,
|
|
2233
|
+
devServer
|
|
2244
2234
|
}),
|
|
2245
2235
|
uploadsAbandoned
|
|
2246
2236
|
};
|
|
@@ -2257,18 +2247,33 @@ function iosCommand(program) {
|
|
|
2257
2247
|
registerIos(program);
|
|
2258
2248
|
}
|
|
2259
2249
|
function registerIos(program, deps = {}) {
|
|
2260
|
-
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.
|
|
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) => {
|
|
2261
2251
|
if (REMOTE_DEVICE_BACKENDS.includes(value)) return value;
|
|
2262
2252
|
throw new InvalidArgumentError(`expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}`);
|
|
2263
2253
|
}).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) => {
|
|
2264
2254
|
const root = (deps.findProjectRoot ?? DEFAULT_DEPS.findProjectRoot)(process.cwd());
|
|
2265
|
-
const run = () => runIos({
|
|
2255
|
+
const run = (progress) => runIos({
|
|
2266
2256
|
...opts,
|
|
2267
2257
|
waitConflict: waitFlagConflict(process.argv)
|
|
2268
|
-
}, deps);
|
|
2269
|
-
const completion = root ? await withWorkspaceProcessLock(workspaceDir(root), "native-run",
|
|
2258
|
+
}, deps, progress);
|
|
2259
|
+
const completion = root ? await withWorkspaceProcessLock(workspaceDir(root), "native-run", async (claim) => {
|
|
2260
|
+
recordWorkspaceUse(root);
|
|
2261
|
+
const progress = startBuildProgress({
|
|
2262
|
+
root,
|
|
2263
|
+
platform: "ios",
|
|
2264
|
+
slot: opts.slot ?? "default",
|
|
2265
|
+
claim,
|
|
2266
|
+
note: (line) => writeNote(chalk.dim(line))
|
|
2267
|
+
});
|
|
2268
|
+
try {
|
|
2269
|
+
return await run(progress);
|
|
2270
|
+
} finally {
|
|
2271
|
+
progress.clear();
|
|
2272
|
+
}
|
|
2273
|
+
}, {
|
|
2270
2274
|
external: true,
|
|
2271
|
-
waitMs: 18e5
|
|
2275
|
+
waitMs: 18e5,
|
|
2276
|
+
declareSpawns: true
|
|
2272
2277
|
}) : await run();
|
|
2273
2278
|
if (!completion) process.exit(1);
|
|
2274
2279
|
else if (completion.uploadsAbandoned) exitAfterFlush(0);
|
|
@@ -2281,7 +2286,7 @@ function explicitSchemeRefusal(root, scheme, isExpo, d) {
|
|
|
2281
2286
|
message: "--scheme must name a non-empty shared Xcode app scheme.",
|
|
2282
2287
|
remedy: "Pass the exact scheme name shown by xcodebuild -list."
|
|
2283
2288
|
};
|
|
2284
|
-
if (
|
|
2289
|
+
if (isExpo) return null;
|
|
2285
2290
|
const project = d.discoverXcodeProject(root);
|
|
2286
2291
|
if (project.error) return project.error;
|
|
2287
2292
|
return d.resolveScheme(project, { scheme }).error ?? null;
|
|
@@ -2332,7 +2337,7 @@ function iosSlotDeps(d, slot) {
|
|
|
2332
2337
|
}
|
|
2333
2338
|
return d;
|
|
2334
2339
|
}
|
|
2335
|
-
async function runIos(opts = {}, overrides = {}) {
|
|
2340
|
+
async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
2336
2341
|
const slot = validateDeviceSlot(opts.slot);
|
|
2337
2342
|
let d = iosSlotDeps({
|
|
2338
2343
|
...DEFAULT_DEPS,
|
|
@@ -2346,16 +2351,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2346
2351
|
const started = d.now();
|
|
2347
2352
|
const startedAt = new Date(started).toISOString();
|
|
2348
2353
|
const elapsed = () => d.now() - started;
|
|
2349
|
-
const
|
|
2350
|
-
if (!foundRoot) {
|
|
2351
|
-
note(chalk.red("Not in a React Native project (no package.json found)."));
|
|
2352
|
-
process.exitCode = 1;
|
|
2353
|
-
return null;
|
|
2354
|
-
}
|
|
2355
|
-
const root = foundRoot;
|
|
2356
|
-
const projectProblem = appProjectProblem(root);
|
|
2357
|
-
if (projectProblem) {
|
|
2358
|
-
const { message, remedy } = projectProblem;
|
|
2354
|
+
const refuseProject = ({ message, remedy }) => {
|
|
2359
2355
|
note(chalk.red(phaseLine("error", message)));
|
|
2360
2356
|
note(chalk.dim(phaseLine("remedy", remedy)));
|
|
2361
2357
|
note(chalk.red(phaseLine("failed", "STIM_NO_PROJECT")));
|
|
@@ -2366,7 +2362,12 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2366
2362
|
}));
|
|
2367
2363
|
process.exitCode = 1;
|
|
2368
2364
|
return null;
|
|
2369
|
-
}
|
|
2365
|
+
};
|
|
2366
|
+
const foundRoot = d.findProjectRoot(process.cwd());
|
|
2367
|
+
if (!foundRoot) return refuseProject(NO_PROJECT_REFUSAL);
|
|
2368
|
+
const root = foundRoot;
|
|
2369
|
+
const projectProblem = appProjectProblem(root);
|
|
2370
|
+
if (projectProblem) return refuseProject(projectProblem);
|
|
2370
2371
|
try {
|
|
2371
2372
|
await d.ensureWorkspaceStorage(root, { note });
|
|
2372
2373
|
} catch (error) {
|
|
@@ -2404,10 +2405,12 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2404
2405
|
platform: "ios",
|
|
2405
2406
|
write: (statsRun, at) => d.recordStats(statsRun, at),
|
|
2406
2407
|
now: () => d.now(),
|
|
2407
|
-
note: (line) => note(chalk.dim(line))
|
|
2408
|
+
note: (line) => note(chalk.dim(line)),
|
|
2409
|
+
phases: () => progress.durations()
|
|
2408
2410
|
});
|
|
2409
2411
|
const recordRun = stats.record;
|
|
2410
2412
|
let compilationCache = COMPILATION_CACHE_NOT_RUN;
|
|
2413
|
+
let reclaimed = [];
|
|
2411
2414
|
const fail = ({ code, message, remedy = null, lines = [], logPath = null, build = null, lease }) => {
|
|
2412
2415
|
releaseLease();
|
|
2413
2416
|
if (message) note(chalk.red(phaseLine("error", message)));
|
|
@@ -2431,7 +2434,8 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2431
2434
|
message: message ?? null,
|
|
2432
2435
|
remedy: remedy ?? null,
|
|
2433
2436
|
...compilationCache.status === "not-run" ? {} : { compilationCache },
|
|
2434
|
-
...lease === void 0 ? {} : { lease }
|
|
2437
|
+
...lease === void 0 ? {} : { lease },
|
|
2438
|
+
...reclaimed.length ? { reclaimed } : {}
|
|
2435
2439
|
}));
|
|
2436
2440
|
writer?.close?.();
|
|
2437
2441
|
process.exitCode = 1;
|
|
@@ -2477,12 +2481,6 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2477
2481
|
for (const key of unknownSettingKeys(settings)) note(phaseLine("setting", chalk.yellow(`Warning: setting "${key}" is not read by Stim and will be ignored.`)));
|
|
2478
2482
|
const cacheProviderError = cacheProviderSettingError(settings);
|
|
2479
2483
|
if (cacheProviderError) note(chalk.yellow(phaseLine("cache", `${cacheProviderError} Using the local cache.`)));
|
|
2480
|
-
const remoteSettingError = remoteDeviceSettingError(settings);
|
|
2481
|
-
if (remoteSettingError) return fail({
|
|
2482
|
-
code: "STIM_BAD_ARG",
|
|
2483
|
-
message: remoteSettingError,
|
|
2484
|
-
remedy: `Set ios.remote and android.remote to one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}.`
|
|
2485
|
-
});
|
|
2486
2484
|
const poolError = parkedMaxSetting("ios").error;
|
|
2487
2485
|
if (poolError) return fail({
|
|
2488
2486
|
code: "STIM_BAD_ARG",
|
|
@@ -2514,7 +2512,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2514
2512
|
});
|
|
2515
2513
|
if (physical && opts.remote) return fail({
|
|
2516
2514
|
code: "STIM_BAD_ARG",
|
|
2517
|
-
message: "--device builds for a phone
|
|
2515
|
+
message: "--device builds for a phone connected to this machine, and --remote installs on a remote one.",
|
|
2518
2516
|
remedy: "Pass only one of --device and --remote."
|
|
2519
2517
|
});
|
|
2520
2518
|
const noWait = opts.wait === false;
|
|
@@ -2554,29 +2552,16 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2554
2552
|
listRuntimes: d.listIosRuntimes
|
|
2555
2553
|
});
|
|
2556
2554
|
if (modelRefusal) return fail(modelRefusal);
|
|
2557
|
-
const
|
|
2555
|
+
const budget = await d.budgetGate({
|
|
2558
2556
|
root,
|
|
2559
|
-
|
|
2560
|
-
profile: opts.easProfile,
|
|
2561
|
-
note,
|
|
2562
|
-
isExpo,
|
|
2563
|
-
physical,
|
|
2564
|
-
selectors: [opts.scheme, opts.configuration],
|
|
2565
|
-
buildCache: opts.buildCache
|
|
2566
|
-
});
|
|
2567
|
-
if (isEasBuildFailure(easBuild)) return fail(easBuild);
|
|
2568
|
-
const registerProject = () => d.upsertProject(root, {
|
|
2569
|
-
bundleId: d.detectBundleId(root) ?? void 0,
|
|
2570
|
-
isExpo
|
|
2557
|
+
note
|
|
2571
2558
|
});
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
const label = d.projectShortcut(root, proj);
|
|
2559
|
+
reclaimed = budget.reclaimed;
|
|
2560
|
+
if (budget.refusal) return fail(budget.refusal);
|
|
2575
2561
|
let remoteDevice = null;
|
|
2576
2562
|
if (remoteBackend) {
|
|
2577
2563
|
const resolved = await d.resolveRemoteContext({
|
|
2578
2564
|
root,
|
|
2579
|
-
label,
|
|
2580
2565
|
backend: remoteBackend,
|
|
2581
2566
|
easBin: d.resolveEasCliBin(root)?.file ?? null
|
|
2582
2567
|
});
|
|
@@ -2595,8 +2580,26 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2595
2580
|
launchIosApp: remoteDevice.launchIosApp
|
|
2596
2581
|
};
|
|
2597
2582
|
}
|
|
2583
|
+
const easBuild = await d.resolveEasDevelopmentBuild({
|
|
2584
|
+
root,
|
|
2585
|
+
platform: "ios",
|
|
2586
|
+
profile: opts.easProfile,
|
|
2587
|
+
note,
|
|
2588
|
+
isExpo,
|
|
2589
|
+
physical,
|
|
2590
|
+
selectors: [opts.scheme, opts.configuration],
|
|
2591
|
+
buildCache: opts.buildCache
|
|
2592
|
+
});
|
|
2593
|
+
if (isEasBuildFailure(easBuild)) return fail(easBuild);
|
|
2594
|
+
const registerProject = () => d.upsertProject(root, {
|
|
2595
|
+
bundleId: d.detectBundleId(root) ?? void 0,
|
|
2596
|
+
isExpo
|
|
2597
|
+
});
|
|
2598
|
+
if (remoteBackend !== "eas") registerProject();
|
|
2599
|
+
const proj = d.getProject(root);
|
|
2598
2600
|
const limits = d.getConcurrencyLimits();
|
|
2599
2601
|
let physicalDevice = null;
|
|
2602
|
+
let wireless = false;
|
|
2600
2603
|
if (physical && typeof deviceFlag !== "string") {
|
|
2601
2604
|
const pooled = await d.selectFromPool({
|
|
2602
2605
|
root,
|
|
@@ -2604,7 +2607,8 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2604
2607
|
idLabel: "udid",
|
|
2605
2608
|
list: () => iosPoolCandidates(d.listIosDevices()).map((entry) => ({
|
|
2606
2609
|
id: entry.udid,
|
|
2607
|
-
name: entry.name
|
|
2610
|
+
name: entry.name,
|
|
2611
|
+
fallback: isWirelessIosDevice(entry)
|
|
2608
2612
|
})),
|
|
2609
2613
|
noCandidates: () => {
|
|
2610
2614
|
const resolved = iosPoolNoCandidatesRefusal(d.listIosDevices());
|
|
@@ -2628,6 +2632,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2628
2632
|
udid: pooled.candidate.id,
|
|
2629
2633
|
name: pooled.candidate.name ?? pooled.candidate.id
|
|
2630
2634
|
};
|
|
2635
|
+
wireless = pooled.candidate.fallback === true;
|
|
2631
2636
|
} else if (physical) {
|
|
2632
2637
|
const resolved = resolveIosPhysicalDevice(typeof deviceFlag === "string" ? deviceFlag : null, d.listIosDevices());
|
|
2633
2638
|
if (!resolved.udid) return fail({
|
|
@@ -2639,6 +2644,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2639
2644
|
udid: resolved.udid,
|
|
2640
2645
|
name: resolved.name ?? resolved.udid
|
|
2641
2646
|
};
|
|
2647
|
+
wireless = resolved.wireless === true;
|
|
2642
2648
|
}
|
|
2643
2649
|
if (!physical) {
|
|
2644
2650
|
const capacity = d.checkDeviceCapacity({
|
|
@@ -2651,6 +2657,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2651
2657
|
let metroPort = proj?.metroPort ?? null;
|
|
2652
2658
|
let lanAddress = null;
|
|
2653
2659
|
let lanOriginUrl = null;
|
|
2660
|
+
let devServer = null;
|
|
2654
2661
|
if (!await resolveMetroPort()) return null;
|
|
2655
2662
|
let device;
|
|
2656
2663
|
if (physicalDevice) device = {
|
|
@@ -2693,34 +2700,28 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2693
2700
|
metroPort = null;
|
|
2694
2701
|
phase("metro", `skipped (${configuration}: the JS bundle is embedded, no dev server is used)`);
|
|
2695
2702
|
} else if (metroCheck) {
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2703
|
+
const gate = await ensureDevServer({
|
|
2704
|
+
root,
|
|
2705
|
+
port: metroPort,
|
|
2706
|
+
settings,
|
|
2707
|
+
remote: Boolean(remoteDevice),
|
|
2708
|
+
note,
|
|
2709
|
+
resolve: d.resolveProjectMetro,
|
|
2710
|
+
start: d.startDevServer,
|
|
2711
|
+
readState: d.readWorkspaceState
|
|
2712
|
+
});
|
|
2713
|
+
reclaimed = [...reclaimed, ...gate.reclaimed];
|
|
2714
|
+
if (!gate.ok) {
|
|
2708
2715
|
fail({
|
|
2709
|
-
code:
|
|
2710
|
-
message:
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
supervisor,
|
|
2714
|
-
supervisorAlive
|
|
2715
|
-
}),
|
|
2716
|
-
remedy: noMetroRemedy({
|
|
2717
|
-
port: metroPort,
|
|
2718
|
-
supervisor,
|
|
2719
|
-
supervisorAlive
|
|
2720
|
-
})
|
|
2716
|
+
code: gate.code,
|
|
2717
|
+
message: gate.message,
|
|
2718
|
+
remedy: gate.remedy,
|
|
2719
|
+
lines: gate.lines
|
|
2721
2720
|
});
|
|
2722
2721
|
return false;
|
|
2723
2722
|
}
|
|
2723
|
+
metroPort = gate.port;
|
|
2724
|
+
devServer = gate.devServer;
|
|
2724
2725
|
} else if (!metroPort) {
|
|
2725
2726
|
metroPort = DEFAULT_METRO_PORT;
|
|
2726
2727
|
note(chalk.yellow(`No Metro port is reserved for this workspace; wiring the app to ${metroPort}.`));
|
|
@@ -2814,6 +2815,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2814
2815
|
boot,
|
|
2815
2816
|
createdSessionId: remoteDevice.createdSessionId,
|
|
2816
2817
|
abandonCreatedSession: remoteDevice.abandonCreatedSession,
|
|
2818
|
+
webPreviewUrl: remoteDevice.webPreviewUrl,
|
|
2817
2819
|
writeState: d.writeWorkspaceState,
|
|
2818
2820
|
register: registerProject
|
|
2819
2821
|
}) : boot()).then((result) => {
|
|
@@ -2850,7 +2852,8 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2850
2852
|
note,
|
|
2851
2853
|
logWriter,
|
|
2852
2854
|
estimates,
|
|
2853
|
-
stats
|
|
2855
|
+
stats,
|
|
2856
|
+
step: progress.step
|
|
2854
2857
|
}
|
|
2855
2858
|
}, d);
|
|
2856
2859
|
if (!acquiredArtifact.ok) {
|
|
@@ -2868,7 +2871,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2868
2871
|
idLabel: "udid",
|
|
2869
2872
|
waitSeconds,
|
|
2870
2873
|
noWait,
|
|
2871
|
-
installBoundMs:
|
|
2874
|
+
installBoundMs: iosDeviceBounds(wireless).installMs,
|
|
2872
2875
|
appId: artifact.bundleId ?? proj?.bundleId ?? null,
|
|
2873
2876
|
holderAppId: (holder) => d.getProject(holder)?.bundleId ?? null,
|
|
2874
2877
|
now: d.now,
|
|
@@ -2908,6 +2911,7 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2908
2911
|
device,
|
|
2909
2912
|
udid,
|
|
2910
2913
|
physical,
|
|
2914
|
+
wireless,
|
|
2911
2915
|
lanAddress,
|
|
2912
2916
|
lanOriginUrl,
|
|
2913
2917
|
remoteDevice,
|
|
@@ -2923,7 +2927,10 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2923
2927
|
closeWriter: () => writer?.close?.(),
|
|
2924
2928
|
lease: leaseHandle,
|
|
2925
2929
|
releaseLease,
|
|
2926
|
-
recordRun
|
|
2930
|
+
recordRun,
|
|
2931
|
+
reclaimed,
|
|
2932
|
+
devServer,
|
|
2933
|
+
enterPhase: progress.step
|
|
2927
2934
|
});
|
|
2928
2935
|
} finally {
|
|
2929
2936
|
releaseLease();
|
|
@@ -2939,4 +2946,4 @@ async function runIos(opts = {}, overrides = {}) {
|
|
|
2939
2946
|
}
|
|
2940
2947
|
}
|
|
2941
2948
|
//#endregion
|
|
2942
|
-
export { appNameFromPath, buildLogFile, cacheDescription, collectorEntry, iosCommand as default, devClientScheme, deviceLabel, ensureWorkspaceStorageSafely, formatDuration,
|
|
2949
|
+
export { appNameFromPath, buildLogFile, cacheDescription, collectorEntry, iosCommand as default, devClientScheme, deviceLabel, ensureWorkspaceStorageSafely, formatDuration, iosConfigurationSetting, iosFacts, isReleaseConfiguration, lastBuildRecord, phaseLine, pickDevClientScheme, podAction, registerIos, replaceCollector, resolveConfiguration, resolveDeviceType, resolveRuntime, schemesFromInfoPlist, shortHash, shortUdid, writeLastBuild };
|