stim 1.16.0 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activity-BxwdD81S.mjs → activity-IRvJY_ru.mjs} +23 -3
- package/dist/{agent-device-usage-output-Dpih1Tfa.mjs → agent-device-usage-output-BK41vnzN.mjs} +3 -3
- package/dist/{android-Ift4kVvt.mjs → android-B6rDWrTm.mjs} +681 -319
- package/dist/{android-B_NumVyQ.mjs → android-B_YNZy61.mjs} +7 -43
- package/dist/{android-r2rBL8kV.mjs → android-DE4v59Mb.mjs} +12 -3
- package/dist/{android-cas-8U4DPqeR.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
- package/dist/{app-install-CKWdbXIX.mjs → app-install-VPkI5WEg.mjs} +6 -5
- package/dist/{budget-DjrURfQn.mjs → budget-CUDz870h.mjs} +62 -25
- package/dist/{build-plan-DjeSb2Xl.mjs → build-plan-BJSXzsCL.mjs} +345 -86
- package/dist/{idle-DYVymG92.mjs → build-progress-D0WkjCPd.mjs} +170 -233
- package/dist/{build-slots-rUk77xqh.mjs → build-slots-41v_d2x9.mjs} +35 -25
- package/dist/{cli-BkYZ_6hy.mjs → cli-BLQqDGlX.mjs} +17 -17
- package/dist/cli.mjs +1 -1
- package/dist/{client-BTY686R6.mjs → client-CxNotugx.mjs} +313 -44
- package/dist/collector-run.mjs +3 -3
- package/dist/{command-output-DnJMdEY-.mjs → command-output-CDAIFD-8.mjs} +3 -3
- package/dist/{created-devices-D5owjN4C.mjs → created-devices-CpvzBL25.mjs} +1 -1
- package/dist/{dependency-state-B6cMXZab.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
- package/dist/{deps-urbmfXig.mjs → deps-CVxlsRFn.mjs} +1 -1
- package/dist/{dev-client-CroAIjjj.mjs → dev-client-B-XC4uRH.mjs} +2 -2
- package/dist/{device-DZQjF7H5.mjs → device-C8IOoJPv.mjs} +7 -7
- package/dist/device-capacity-ZC4XSZ4R.mjs +580 -0
- package/dist/device-host-worker.mjs +436 -154
- package/dist/{device-ios-BadmeL2V.mjs → device-ios-C2Um-XUR.mjs} +75 -44
- package/dist/{device-lease-D-hLqx1b.mjs → device-lease-DpoS36_u.mjs} +2 -2
- package/dist/{device-lease-run-CqjShqWW.mjs → device-lease-run-B8YltIH_.mjs} +3 -3
- package/dist/{device-pool-CUaEWMMm.mjs → device-pool-3o7s5lo4.mjs} +2 -2
- package/dist/{device-remote-D5WVWqOq.mjs → device-remote-hFSkpfQu.mjs} +12 -12
- package/dist/{doctor-Cimf-gGB.mjs → doctor-BF_435OC.mjs} +40 -58
- package/dist/{error-diagnostics-B9L4Ae0x.mjs → error-diagnostics-C-NMnhrk.mjs} +7 -7
- package/dist/{gc-Bqy4bjEu.mjs → gc-BsWKa_-d.mjs} +313 -30
- package/dist/{gradle-BsO1MdsH.mjs → gradle-bsBRy6i9.mjs} +3 -3
- package/dist/{guide-B_uyKTxW.mjs → guide-DC3n6-NH.mjs} +1776 -655
- package/dist/{guide-status-CjEZMAD4.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
- package/dist/hosted-android-DgU31wY3.mjs +32 -0
- package/dist/{hosted-client-a-WmqE2L.mjs → hosted-client-CdSoH-G6.mjs} +5 -6
- package/dist/hosted-ios-BTaVj4Jb.mjs +15 -0
- package/dist/{hosted-logs-D5g041Q3.mjs → hosted-logs-SxfBvSvc.mjs} +16 -16
- package/dist/{hosted-macos-BSZyIb3y.mjs → hosted-macos-CT9E3meL.mjs} +4 -4
- package/dist/{hosted-ios-CIWelIqf.mjs → hosted-native-CZLOrMrN.mjs} +77 -42
- package/dist/idle-BXG__1BA.mjs +176 -0
- package/dist/{idle-shutdown-CTsDnAde.mjs → idle-shutdown-IGyNV8Cr.mjs} +25 -17
- package/dist/{in-use-DvBw0Kxo.mjs → in-use-CvGOUn-x.mjs} +11 -11
- package/dist/{ios-aq3QoGI3.mjs → ios-C7JuT1bI.mjs} +173 -91
- package/dist/{ios-BaInn3sW.mjs → ios-DSfnPfse.mjs} +4 -4
- package/dist/{ios-device-FfCN_C8p.mjs → ios-device-pAN4t54-.mjs} +1 -1
- package/dist/ios-state-8L3lgum6.mjs +89 -0
- package/dist/{launch-verify-2DBRizjo.mjs → launch-verify-lTnWZikR.mjs} +2 -2
- package/dist/{logs-CHEVK8zD.mjs → logs-DNxKcok9.mjs} +36 -23
- package/dist/{macos-CSYEAFmF.mjs → macos-BEs8cwKx.mjs} +75 -34
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +2 -2
- package/dist/{metro-BeK1ZPz1.mjs → metro-g8NqiJp-.mjs} +1 -1
- package/dist/{metro-gateway-BJ-rxQAB.mjs → metro-gateway-CHqK0p-a.mjs} +22 -3
- package/dist/{named-ports-Bk_YXEmE.mjs → named-ports-C8m8EQs2.mjs} +2 -2
- package/dist/{native-run-NaBrRFtQ.mjs → native-run-D1Q56rAD.mjs} +17 -6
- package/dist/{native-runtime-DBzRnEKS.mjs → native-runtime-YhaSxP4v.mjs} +6 -6
- package/dist/offload-worker.mjs +9 -9
- package/dist/{teardown-CL6vDs2Y.mjs → ownership-BMLqyBgJ.mjs} +603 -26
- package/dist/{ownership-DiA16AsN.mjs → ownership-DyRQru0q.mjs} +2 -2
- package/dist/{ports-R2k4Knz3.mjs → ports-4nYqxPWC.mjs} +2 -2
- package/dist/{prebuild-D2fsca_Z.mjs → prebuild-D7RUMkwN.mjs} +3 -3
- package/dist/{preview-DhVbvPAZ.mjs → preview-C_JjkEy4.mjs} +7 -7
- package/dist/{project-Du91Ilvc.mjs → project-D47Rh0ly.mjs} +7 -2
- package/dist/{recordings-BIXOzVnr.mjs → recordings-BNgsD1Tr.mjs} +1 -1
- package/dist/{reload-rM9jV1fz.mjs → reload-byOjE3P4.mjs} +62 -35
- package/dist/{remote-cache-C8-V13XN.mjs → remote-cache-Ci4DQYYj.mjs} +3 -3
- package/dist/{run-f4vI6EnK.mjs → run-CkE9y0nc.mjs} +1 -1
- package/dist/{server-bare-CpPGmnmO.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
- package/dist/{server-expo-MC0rHlOC.mjs → server-expo-CHTyXD0G.mjs} +2 -2
- package/dist/server-expo-CeakhI8P.mjs +2 -0
- package/dist/{settings-oTSkkNrM.mjs → settings-Cfd-0r2d.mjs} +10 -9
- package/dist/{settings-ZkDzkzvB.mjs → settings-SR9OmW9h.mjs} +3 -3
- package/dist/settings.schema.json +123 -76
- package/dist/{simslim-B8-7AoTI.mjs → simslim-BWNrc3M3.mjs} +3 -3
- package/dist/{slot-launch-B8VrHxn1.mjs → slot-launch-DmjBmpQV.mjs} +8 -8
- package/dist/{start-CX8Ig-U2.mjs → start-BEP-XmEA.mjs} +1 -1
- package/dist/{start-ClDfwXa4.mjs → start-BHIersSm.mjs} +11 -11
- package/dist/{state-DcW6vOd_.mjs → state-BKa8wNN5.mjs} +1 -1
- package/dist/{state-3DwSQIBK.mjs → state-DyaNTgfR.mjs} +1 -1
- package/dist/{state-C1jB7Q8q.mjs → state-PeQiJuIu.mjs} +2 -2
- package/dist/{stats-CEZ_i5je.mjs → stats-Bq4fJOdB.mjs} +7 -4
- package/dist/{status-Cs7VLg9D.mjs → status-CqeWbIWW.mjs} +128 -38
- package/dist/{status-BuvBFeII.mjs → status-CzS4bPO9.mjs} +4 -4
- package/dist/{stop-Bffozsac.mjs → stop-Cj01je8D.mjs} +48 -27
- package/dist/{stop-B0Yxtmiy.mjs → stop-D03prQnW.mjs} +4 -4
- package/dist/{stop-Dt_dM16A.mjs → stop-DOxwkH4j.mjs} +2 -2
- package/dist/{stop-cause-CidxIqup.mjs → stop-cause-rhmGfwvt.mjs} +1 -1
- package/dist/supervisor-run.d.mts +7 -4
- package/dist/supervisor-run.mjs +26 -28
- package/dist/{support-D4aYJniO.mjs → support-BE-tbOP9.mjs} +45 -20
- package/dist/{support-CAP8qDUF.mjs → support-WvD__tSV.mjs} +7 -7
- package/dist/{toolchain-DkUflduf.mjs → toolchain-CdrxgUeA.mjs} +8 -8
- package/dist/{warm-progress-CpGv3Wb6.mjs → warm-progress-DF4JRvYI.mjs} +3 -3
- package/dist/watchman-APYjXSQa.mjs +48 -0
- package/dist/{web-DWUaMp8P.mjs → web-DddUdJzr.mjs} +12 -13
- package/dist/web-run.mjs +4 -4
- package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
- package/dist/{workspace-state-B8-aJ1_5.mjs → workspace-state-DqcCbpE7.mjs} +2 -2
- package/dist/{workspaces-BV4pdHFz.mjs → workspaces-Bcib97-6.mjs} +3 -3
- package/dist/{worktree-K-xj9Db0.mjs → worktree-AK_m-d_m.mjs} +141 -40
- package/dist/{worktree-jnG8Iph5.mjs → worktree-CsAjSmEo.mjs} +1 -1
- package/package.json +5 -5
- package/dist/device-capacity-BHwxNBlu.mjs +0 -136
- package/dist/ios-state-DS5UpYTH.mjs +0 -48
- package/dist/machines-BIBUdhpj.mjs +0 -265
- package/dist/ownership-hCkPzGmr.mjs +0 -571
- package/dist/server-expo-CVqO2c35.mjs +0 -2
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
-
import { D as withConfigLock$1, H as projectDeviceSlots, _ as loadConfig$1, a as clearDevice, b as releaseAndroidConsolePort, i as clearAndroidBootPending, k as acquireAvdClaim, t as allConsolePortsAndSerials, w as setDevice, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { D as withConfigLock$1, H as projectDeviceSlots, _ as loadConfig$1, a as clearDevice, b as releaseAndroidConsolePort, i as clearAndroidBootPending, k as acquireAvdClaim, p as getProject, t as allConsolePortsAndSerials, w as setDevice, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
|
|
3
|
+
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
4
|
import { r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
4
|
-
import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-
|
|
5
|
-
import { Tt as removeTemporaryEntry,
|
|
6
|
-
import {
|
|
7
|
-
import { o as pidExists } from "./metro-
|
|
8
|
-
import { d as sharedBuildCache } from "./workspace-state-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { A as listAvds, B as ownedAvdSystemImage, E as getAvdNameForSerial, F as ownedAvdDeviceProfile, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, O as listAdbDevices, P as nextConsolePort, R as ownedAvdName, W as pickDefaultSystemImage, b as createOwnedAvd, f as assertOwnedAvdStopped, ft as parkedMaxSetting, g as avdPoolConfiguration, j as listInstalledSystemImages, n as OWNED_AVD_CONFIG_DEFAULTS, pt as readParked, st as adoptParked, t as DEFAULT_AVD_DEVICE_PROFILE, tt as waitForBoot, ut as isLegacyDeletionClaim, v as bootAndroidEmulator, y as configureNewOwnedAvd } from "./android-
|
|
12
|
-
import { j as readHostMemoryPressure, u as listAllIosSims } from "./ios-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { t as
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
5
|
+
import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-CDAIFD-8.mjs";
|
|
6
|
+
import { Tt as removeTemporaryEntry, a as androidAvdConfigSetting, at as gitCommonDirOnDisk, c as androidDataPartitionSizeGbSetting, wt as makeTemporaryDirectory } from "./settings-Cfd-0r2d.mjs";
|
|
7
|
+
import { u as ownedDeviceLabel } from "./project-D47Rh0ly.mjs";
|
|
8
|
+
import { o as pidExists } from "./metro-g8NqiJp-.mjs";
|
|
9
|
+
import { d as sharedBuildCache } from "./workspace-state-DqcCbpE7.mjs";
|
|
10
|
+
import { o as peekBudget } from "./budget-CUDz870h.mjs";
|
|
11
|
+
import { C as diffFingerprintSources, I as storedSources, w as entryDir, y as artifactIn } from "./device-lease-DpoS36_u.mjs";
|
|
12
|
+
import { A as listAvds, B as ownedAvdSystemImage, E as getAvdNameForSerial, F as ownedAvdDeviceProfile, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, O as listAdbDevices, P as nextConsolePort, R as ownedAvdName, W as pickDefaultSystemImage, b as createOwnedAvd, f as assertOwnedAvdStopped, ft as parkedMaxSetting, g as avdPoolConfiguration, j as listInstalledSystemImages, n as OWNED_AVD_CONFIG_DEFAULTS, pt as readParked, st as adoptParked, t as DEFAULT_AVD_DEVICE_PROFILE, tt as waitForBoot, ut as isLegacyDeletionClaim, v as bootAndroidEmulator, y as configureNewOwnedAvd } from "./android-B_YNZy61.mjs";
|
|
13
|
+
import { j as readHostMemoryPressure, u as listAllIosSims } from "./ios-DSfnPfse.mjs";
|
|
14
|
+
import { _ as teardownParkedAvd, m as teardownOwnedAvd } from "./ownership-BMLqyBgJ.mjs";
|
|
15
|
+
import { o as estimateBuild, p as readStats$1 } from "./build-progress-D0WkjCPd.mjs";
|
|
16
|
+
import { b as tailLines, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-CdrxgUeA.mjs";
|
|
17
|
+
import { t as cleanLine } from "./server-expo-CHTyXD0G.mjs";
|
|
18
|
+
import { f as namedBuildMachine, m as resolveBuildMachine, v as hostingMachines } from "./client-CxNotugx.mjs";
|
|
19
|
+
import { a as call, o as connectHost } from "./hosted-client-CdSoH-G6.mjs";
|
|
20
|
+
import { t as clearDeviceIdleShutdown } from "./idle-shutdown-IGyNV8Cr.mjs";
|
|
21
|
+
import { i as countLiveOwnedDevices, n as DeviceAdmissionRefusal, p as withDeviceBootAdmission, s as peekDeviceSlots } from "./device-capacity-ZC4XSZ4R.mjs";
|
|
22
|
+
import { i as staleNativeDirRefusal } from "./prebuild-D7RUMkwN.mjs";
|
|
23
|
+
import { i as ensureOwnedIosDevice, r as ensureIosBooted } from "./device-ios-C2Um-XUR.mjs";
|
|
24
|
+
import { r as readHostedNative, s as writeHostedNative } from "./ios-state-8L3lgum6.mjs";
|
|
25
|
+
import { n as prepareHostedNative } from "./hosted-native-CZLOrMrN.mjs";
|
|
26
|
+
import { a as easAuthNote } from "./remote-cache-Ci4DQYYj.mjs";
|
|
27
|
+
import { t as reconcileSimSlim } from "./simslim-BWNrc3M3.mjs";
|
|
22
28
|
import { randomUUID } from "node:crypto";
|
|
23
29
|
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
24
30
|
import { basename, dirname, join, relative } from "node:path";
|
|
25
|
-
import { LAST_BUILD_KEYS, loadConfig, readWorkspaceState } from "@stim-cli/core/state";
|
|
31
|
+
import { LAST_BUILD_KEYS, isJsonObject, loadConfig, machineCapacity, parseHostedChoice, parseHostedNativeOffer, readWorkspaceState } from "@stim-cli/core/state";
|
|
26
32
|
import { claimRemoveCommand, clearClaimChild, markClaimChildPending, processGroupAlive, releaseClaim, setClaimChild } from "@stim-cli/core/ownership-claim";
|
|
27
33
|
import { captureProcessIdentity } from "@stim-cli/core/process-identity";
|
|
28
34
|
import chalk from "chalk";
|
|
@@ -30,6 +36,219 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
30
36
|
import * as expoFingerprint from "@expo/fingerprint";
|
|
31
37
|
import { resolveTieredBuild } from "@stim-cli/cache";
|
|
32
38
|
import { request } from "node:http";
|
|
39
|
+
//#region src/device-host/placement.ts
|
|
40
|
+
function local$1(reason, skipped = []) {
|
|
41
|
+
return {
|
|
42
|
+
kind: "local",
|
|
43
|
+
reason,
|
|
44
|
+
skipped
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function decideDevicePlacement(inputs) {
|
|
48
|
+
if ("sticky" in inputs) {
|
|
49
|
+
if ("machine" in inputs.sticky) {
|
|
50
|
+
const reason = `recorded session on ${inputs.sticky.machine}`;
|
|
51
|
+
return {
|
|
52
|
+
kind: "host",
|
|
53
|
+
reason,
|
|
54
|
+
machines: [{
|
|
55
|
+
machine: inputs.sticky.machine,
|
|
56
|
+
reason
|
|
57
|
+
}],
|
|
58
|
+
skipped: []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
kind: "local",
|
|
63
|
+
reason: "this workspace's device runs here",
|
|
64
|
+
skipped: []
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const { platform, here, offers, buildMachine, noWait } = inputs;
|
|
68
|
+
const { count, max, queued } = here.devices;
|
|
69
|
+
const cannotTake = !(max === 0 || count !== null && count < max) || queued > 0;
|
|
70
|
+
const usage = max > 0 ? `${count} of ${max} devices in use` : `${count} devices in use, no device cap`;
|
|
71
|
+
const localReason = count === null ? "cannot tell how many devices run here; local boot admission decides" : cannotTake ? `${usage}${queued ? `, ${queued} runs queued ahead` : ""}` : here.budgetRefusal ?? (here.memoryPressure !== "normal" ? `host memory pressure ${here.memoryPressure ?? "unknown"} here` : `load ${here.loadPerCore.toFixed(1)}/core here, ${usage}`);
|
|
72
|
+
if (!offers.length) return local$1("no remote Macs configured; " + localReason);
|
|
73
|
+
if (count === null) return local$1(localReason);
|
|
74
|
+
if (!cannotTake && here.memoryPressure === "normal" && !here.budgetRefusal && here.loadPerCore < here.maxLoadPerCore) return local$1(localReason);
|
|
75
|
+
const skipped = [];
|
|
76
|
+
const admitted = [];
|
|
77
|
+
offers.forEach((probe, index) => {
|
|
78
|
+
let reason = null;
|
|
79
|
+
if ("failure" in probe) reason = probe.failure;
|
|
80
|
+
else {
|
|
81
|
+
const { offer } = probe;
|
|
82
|
+
if (offer.declined !== null) reason = `declined: ${offer.declined}`;
|
|
83
|
+
else if (offer.platform !== platform || !offer.choice) reason = `no matching ${platform} device choice`;
|
|
84
|
+
else if (offer.resources.memoryPressure !== "normal") reason = "host memory pressure unknown or elevated";
|
|
85
|
+
else if (offer.capacity.available === 0) reason = "no hosted device capacity available";
|
|
86
|
+
else if (!cannotTake && (offer.resources.loadPerCore === null || offer.resources.loadPerCore >= here.loadPerCore)) reason = offer.resources.loadPerCore === null ? "host load unknown while this Mac has room" : "host is not less loaded than this Mac";
|
|
87
|
+
else admitted.push({
|
|
88
|
+
machine: probe.machine,
|
|
89
|
+
offer,
|
|
90
|
+
index
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (reason) skipped.push({
|
|
94
|
+
machine: probe.machine,
|
|
95
|
+
reason
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
admitted.sort((a, b) => Number(b.machine === buildMachine) - Number(a.machine === buildMachine) || (a.offer.resources.loadPerCore ?? Infinity) - (b.offer.resources.loadPerCore ?? Infinity) || b.offer.resources.memoryFreeBytes - a.offer.resources.memoryFreeBytes || a.index - b.index);
|
|
99
|
+
if (!admitted.length) return local$1(`${localReason}; no host admits${cannotTake && !noWait ? "; waiting locally if needed" : ""}`, skipped);
|
|
100
|
+
const machines = admitted.map(({ machine, offer }) => ({
|
|
101
|
+
machine,
|
|
102
|
+
reason: `${localReason}; ${machine}${machine === buildMachine ? " is the explicit remote Mac," : ""} load ${offer.resources.loadPerCore === null ? "unknown" : offer.resources.loadPerCore.toFixed(1) + "/core"}`
|
|
103
|
+
}));
|
|
104
|
+
return {
|
|
105
|
+
kind: "host",
|
|
106
|
+
machines,
|
|
107
|
+
reason: machines[0].reason,
|
|
108
|
+
skipped
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/device-host/auto-placement.ts
|
|
113
|
+
async function probeHost(machine, platform, selectors) {
|
|
114
|
+
let host;
|
|
115
|
+
const deadline = Date.now() + 3e3;
|
|
116
|
+
try {
|
|
117
|
+
host = await connectHost(machine, 3e3, true);
|
|
118
|
+
const offer = await call(host, "device-host.offer", {
|
|
119
|
+
platform,
|
|
120
|
+
...selectors
|
|
121
|
+
}, Math.max(1, deadline - Date.now()));
|
|
122
|
+
const resources = isJsonObject(offer.resources) ? offer.resources : {};
|
|
123
|
+
const parsed = parseHostedNativeOffer({
|
|
124
|
+
...offer,
|
|
125
|
+
resources: {
|
|
126
|
+
...resources,
|
|
127
|
+
loadPerCore: resources.loadPerCore ?? 0
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
let choice = platform === "ios" ? offer.platform === "ios" ? parseHostedChoice(offer.choice) : null : parsed?.platform === "android" ? parsed.choice : null;
|
|
131
|
+
if (choice && ("runtime" in choice ? selectors.deviceType && selectors.deviceType !== choice.deviceType || selectors.runtime && selectors.runtime.replace(/^iOS /, "") !== choice.runtime.replace(/^iOS /, "") : selectors.systemImage && selectors.systemImage !== choice.systemImage || selectors.deviceProfile && selectors.deviceProfile !== choice.deviceProfile)) choice = null;
|
|
132
|
+
if (!isJsonObject(offer.capacity) || offer.declined !== null && typeof offer.declined !== "string") throw new Error("unreadable device offer");
|
|
133
|
+
return {
|
|
134
|
+
probe: {
|
|
135
|
+
machine,
|
|
136
|
+
offer: {
|
|
137
|
+
platform,
|
|
138
|
+
choice,
|
|
139
|
+
declined: offer.declined,
|
|
140
|
+
capacity: { available: typeof offer.capacity.available === "number" ? offer.capacity.available : null },
|
|
141
|
+
resources: {
|
|
142
|
+
loadPerCore: typeof resources.loadPerCore === "number" && Number.isFinite(resources.loadPerCore) && resources.loadPerCore >= 0 ? resources.loadPerCore : null,
|
|
143
|
+
memoryFreeBytes: typeof resources.memoryFreeBytes === "number" ? resources.memoryFreeBytes : 0,
|
|
144
|
+
memoryPressure: typeof resources.memoryPressure === "string" ? resources.memoryPressure : null
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
...choice ? { target: {
|
|
149
|
+
host,
|
|
150
|
+
choice,
|
|
151
|
+
session: null
|
|
152
|
+
} } : {}
|
|
153
|
+
};
|
|
154
|
+
} catch (error) {
|
|
155
|
+
return { probe: {
|
|
156
|
+
machine,
|
|
157
|
+
failure: error instanceof Error ? error.message : String(error)
|
|
158
|
+
} };
|
|
159
|
+
} finally {
|
|
160
|
+
host?.connection.close();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function hosted(target, reason, skipped = []) {
|
|
164
|
+
target.selection = {
|
|
165
|
+
selected: "auto",
|
|
166
|
+
reason
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
target,
|
|
170
|
+
placement: {
|
|
171
|
+
decision: "hosted",
|
|
172
|
+
machine: target.host.machine,
|
|
173
|
+
reason
|
|
174
|
+
},
|
|
175
|
+
skipped
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function local(reason, skipped = []) {
|
|
179
|
+
return {
|
|
180
|
+
target: null,
|
|
181
|
+
placement: {
|
|
182
|
+
decision: "local",
|
|
183
|
+
reason
|
|
184
|
+
},
|
|
185
|
+
skipped
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
async function automaticDevicePlacement({ root, slot, platform, selectors, buildMachine, noWait }, { machines = hostingMachines, read = readHostedNative, write = writeHostedNative, resume = prepareHostedNative, peek = () => peekDeviceSlots({
|
|
189
|
+
platform,
|
|
190
|
+
project: getProject(root),
|
|
191
|
+
slot
|
|
192
|
+
}), capacity = machineCapacity, memory = readHostMemoryPressure, probe = probeHost, budget = peekBudget } = {}) {
|
|
193
|
+
const recorded = read(root, platform, slot)[slot];
|
|
194
|
+
if (recorded) {
|
|
195
|
+
const target = await resume(recorded.machine, selectors, recorded, platform, true);
|
|
196
|
+
if (target) return {
|
|
197
|
+
target,
|
|
198
|
+
placement: {
|
|
199
|
+
decision: "hosted",
|
|
200
|
+
machine: recorded.machine,
|
|
201
|
+
reason: recorded.reason ?? decideDevicePlacement({ sticky: { machine: recorded.machine } }).reason
|
|
202
|
+
},
|
|
203
|
+
skipped: [],
|
|
204
|
+
sticky: true
|
|
205
|
+
};
|
|
206
|
+
write(root, slot, null, platform);
|
|
207
|
+
}
|
|
208
|
+
const devices = peek();
|
|
209
|
+
if (devices.localLive) return {
|
|
210
|
+
...local(decideDevicePlacement({ sticky: { local: true } }).reason),
|
|
211
|
+
sticky: true
|
|
212
|
+
};
|
|
213
|
+
const entries = machines();
|
|
214
|
+
if (entries === null) throw Object.assign(/* @__PURE__ */ new Error("remote.machines is invalid. Run stim guide settings and correct it."), { code: "STIM_HOSTING_REFUSED" });
|
|
215
|
+
const preference = resolveBuildMachine(buildMachine, process.env.STIM_REMOTE_BUILD, loadConfig$1()?.remote?.build);
|
|
216
|
+
buildMachine = namedBuildMachine(preference) ? preference : void 0;
|
|
217
|
+
const load = capacity();
|
|
218
|
+
const here = {
|
|
219
|
+
loadPerCore: load.loadPerCore,
|
|
220
|
+
maxLoadPerCore: load.maxLoadPerCore,
|
|
221
|
+
memoryPressure: memory(),
|
|
222
|
+
devices,
|
|
223
|
+
budgetRefusal: await budget(root)
|
|
224
|
+
};
|
|
225
|
+
const early = decideDevicePlacement({
|
|
226
|
+
platform,
|
|
227
|
+
here,
|
|
228
|
+
offers: entries.map((machine) => ({
|
|
229
|
+
machine,
|
|
230
|
+
failure: "not probed"
|
|
231
|
+
})),
|
|
232
|
+
buildMachine,
|
|
233
|
+
noWait
|
|
234
|
+
});
|
|
235
|
+
if (early.kind === "local" && early.skipped.length === 0) return local(early.reason);
|
|
236
|
+
const probes = await Promise.all(entries.map((machine) => probe(machine, platform, selectors)));
|
|
237
|
+
const decision = decideDevicePlacement({
|
|
238
|
+
platform,
|
|
239
|
+
here,
|
|
240
|
+
offers: probes.map((each) => each.probe),
|
|
241
|
+
buildMachine,
|
|
242
|
+
noWait
|
|
243
|
+
});
|
|
244
|
+
if (decision.kind === "local") return local(decision.reason, decision.skipped);
|
|
245
|
+
const target = probes.find((each) => each.probe.machine === decision.machines[0].machine).target;
|
|
246
|
+
return hosted(target, decision.reason, decision.skipped);
|
|
247
|
+
}
|
|
248
|
+
function devicePlacementLine(placement, skipped) {
|
|
249
|
+
return `${placement.machine ?? "local"}, ${placement.reason}${placement.decision !== "hosted" && skipped.length ? "; " + skipped.map((each) => `${each.machine}: ${each.reason}`).join("; ") : ""}`;
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
33
252
|
//#region src/engine/metro-warmup.ts
|
|
34
253
|
const WARMUP_TIMEOUT_MS = 6e4;
|
|
35
254
|
async function requestLocal(url, platform, prefetch) {
|
|
@@ -325,6 +544,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
|
|
|
325
544
|
out(chalk.dim(`Recorded port for owned AVD ${record.avdName} is not currently ours; booting it on a freshly allocated port...`));
|
|
326
545
|
return {
|
|
327
546
|
...await bootOwnedAvdOnFreshPort({
|
|
547
|
+
deviceSlotWait: flags.deviceSlotWait,
|
|
328
548
|
avdName: record.avdName,
|
|
329
549
|
metadata: record,
|
|
330
550
|
projectPath,
|
|
@@ -397,6 +617,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
|
|
|
397
617
|
}
|
|
398
618
|
return {
|
|
399
619
|
...await bootOwnedAvdOnFreshPort({
|
|
620
|
+
deviceSlotWait: flags.deviceSlotWait,
|
|
400
621
|
avdName: parked.name,
|
|
401
622
|
projectPath,
|
|
402
623
|
slot,
|
|
@@ -435,6 +656,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
|
|
|
435
656
|
}
|
|
436
657
|
return {
|
|
437
658
|
...await bootOwnedAvdOnFreshPort({
|
|
659
|
+
deviceSlotWait: flags.deviceSlotWait,
|
|
438
660
|
avdName: created.avdName,
|
|
439
661
|
metadata: created.created ? {
|
|
440
662
|
poolConfiguration: configuration,
|
|
@@ -472,41 +694,50 @@ function liveAndroidConsolePorts() {
|
|
|
472
694
|
const adbLive = listAdbDevices();
|
|
473
695
|
return [...adbLive.emulators.map((e) => e.consolePort), ...adbLive.unhealthy.map((u) => u.consolePort).filter((p) => p != null)];
|
|
474
696
|
}
|
|
475
|
-
async function bootOwnedAvdOnFreshPort({ avdName, metadata, projectPath, slot, deviceName, out, logFile = null, alive = pidExists }) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const pid = bootAndroidEmulator(avdName, claim.consolePort, { logFile });
|
|
488
|
-
out(chalk.dim(phaseLine("device", `waiting for ${serial} to finish booting`)));
|
|
489
|
-
const result = await waitForAndroidBoot({
|
|
490
|
-
serial,
|
|
491
|
-
timeoutMs: ANDROID_FRESH_BOOT_TIMEOUT_MS,
|
|
492
|
-
pid,
|
|
493
|
-
alive,
|
|
494
|
-
out
|
|
697
|
+
async function bootOwnedAvdOnFreshPort({ avdName, deviceSlotWait, metadata, projectPath, slot, deviceName, out, logFile = null, alive = pidExists }) {
|
|
698
|
+
return withDeviceBootAdmission({
|
|
699
|
+
platform: "android",
|
|
700
|
+
key: avdName
|
|
701
|
+
}, async () => {
|
|
702
|
+
const claim = claimAndroidConsolePort({
|
|
703
|
+
projectPath,
|
|
704
|
+
slot,
|
|
705
|
+
avdName,
|
|
706
|
+
deviceName,
|
|
707
|
+
livePorts: liveAndroidConsolePorts(),
|
|
708
|
+
metadata
|
|
495
709
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
710
|
+
const serial = `emulator-${claim.consolePort}`;
|
|
711
|
+
try {
|
|
712
|
+
reportAndroidMemoryPressure(out);
|
|
713
|
+
const pid = bootAndroidEmulator(avdName, claim.consolePort, { logFile });
|
|
714
|
+
out(chalk.dim(phaseLine("device", `waiting for ${serial} to finish booting`)));
|
|
715
|
+
const result = await waitForAndroidBoot({
|
|
716
|
+
serial,
|
|
717
|
+
timeoutMs: ANDROID_FRESH_BOOT_TIMEOUT_MS,
|
|
718
|
+
pid,
|
|
719
|
+
alive,
|
|
720
|
+
out
|
|
721
|
+
});
|
|
722
|
+
if (result.failed) throw new AvdBootError(result.reason, result.remedy);
|
|
723
|
+
const running = getAvdNameForSerial(serial);
|
|
724
|
+
if (running && running !== avdName) throw new Error(`${serial} is running AVD ${running}, not this workspace's owned AVD ${avdName}; refusing to use it.`);
|
|
725
|
+
clearAndroidBootPending(projectPath, avdName, slot);
|
|
726
|
+
const { bootPending: _booted, ...booted } = claim;
|
|
727
|
+
return {
|
|
728
|
+
...booted,
|
|
729
|
+
serial,
|
|
730
|
+
setup: true
|
|
731
|
+
};
|
|
732
|
+
} catch (error) {
|
|
733
|
+
releaseAndroidConsolePort(projectPath, claim.consolePort, slot);
|
|
734
|
+
throw error;
|
|
735
|
+
}
|
|
736
|
+
}, {
|
|
737
|
+
...deviceSlotWait,
|
|
738
|
+
root: projectPath,
|
|
739
|
+
out
|
|
740
|
+
});
|
|
510
741
|
}
|
|
511
742
|
function reportAndroidMemoryPressure(out) {
|
|
512
743
|
const pressure = readHostMemoryPressure();
|
|
@@ -515,11 +746,15 @@ function reportAndroidMemoryPressure(out) {
|
|
|
515
746
|
function androidBootRemedy(pressure) {
|
|
516
747
|
let count = null;
|
|
517
748
|
try {
|
|
518
|
-
|
|
519
|
-
sims: process.platform === "darwin" ? listAllIosSims({ timeoutMs: 2e3 }) : [],
|
|
520
|
-
|
|
521
|
-
|
|
749
|
+
const live = countLiveOwnedDevices({
|
|
750
|
+
sims: () => process.platform === "darwin" ? listAllIosSims({ timeoutMs: 2e3 }) : [],
|
|
751
|
+
adb: () => ({
|
|
752
|
+
...listAdbDevices({ timeoutMs: 2e3 }),
|
|
753
|
+
unhealthy: []
|
|
754
|
+
}),
|
|
755
|
+
booting: []
|
|
522
756
|
});
|
|
757
|
+
count = typeof live === "number" ? live : null;
|
|
523
758
|
} catch {}
|
|
524
759
|
const observation = pressure === "warning" || pressure === "critical" ? `macOS reports ${pressure} host memory pressure. ` : "";
|
|
525
760
|
const devices = count ? `${count} Stim-owned ${count === 1 ? "device is" : "devices are"} running. ` : "";
|
|
@@ -557,7 +792,7 @@ async function waitForAndroidBoot({ serial, timeoutMs, pid = null, alive = pidEx
|
|
|
557
792
|
remedy: exited ? "Inspect the emulator log for the process exit, fix what it reports, then run `stim android` again." : androidBootRemedy(pressure)
|
|
558
793
|
};
|
|
559
794
|
}
|
|
560
|
-
async function ensureAndroidBooted({ device, projectPath, slot, timeoutMs, out, logFile = null, alive = pidExists }) {
|
|
795
|
+
async function ensureAndroidBooted({ device, deviceSlotWait, projectPath, slot, timeoutMs, out, logFile = null, alive = pidExists }) {
|
|
561
796
|
if (!device?.avdName || !projectPath) return {
|
|
562
797
|
failed: true,
|
|
563
798
|
reason: "No owned Android emulator is recorded for this project."
|
|
@@ -595,36 +830,57 @@ async function ensureAndroidBooted({ device, projectPath, slot, timeoutMs, out,
|
|
|
595
830
|
timeoutMs,
|
|
596
831
|
out
|
|
597
832
|
}));
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
833
|
+
const boot = async () => {
|
|
834
|
+
const claim = claimAndroidConsolePort({
|
|
835
|
+
projectPath,
|
|
836
|
+
slot,
|
|
837
|
+
avdName,
|
|
838
|
+
deviceName: device.deviceName,
|
|
839
|
+
livePorts: liveAndroidConsolePorts(),
|
|
840
|
+
metadata: device
|
|
841
|
+
});
|
|
842
|
+
const serial = `emulator-${claim.consolePort}`;
|
|
843
|
+
reportAndroidMemoryPressure(out);
|
|
844
|
+
out(chalk.dim(phaseLine("device", `booting ${avdName} as ${serial}`)));
|
|
845
|
+
let pid = null;
|
|
846
|
+
try {
|
|
847
|
+
pid = bootAndroidEmulator(avdName, claim.consolePort, { logFile });
|
|
848
|
+
} catch (e) {
|
|
849
|
+
releaseAndroidConsolePort(projectPath, claim.consolePort, slot);
|
|
850
|
+
return {
|
|
851
|
+
failed: true,
|
|
852
|
+
reason: `Could not start emulator for AVD ${avdName}: ${e?.message || e}`
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
const result = await waitForAndroidBoot({
|
|
856
|
+
serial,
|
|
857
|
+
timeoutMs,
|
|
858
|
+
pid,
|
|
859
|
+
alive,
|
|
860
|
+
out
|
|
861
|
+
});
|
|
862
|
+
if (result.failed) releaseAndroidConsolePort(projectPath, claim.consolePort, slot);
|
|
863
|
+
return booted(result);
|
|
864
|
+
};
|
|
610
865
|
try {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
866
|
+
return await withDeviceBootAdmission({
|
|
867
|
+
platform: "android",
|
|
868
|
+
key: avdName
|
|
869
|
+
}, boot, {
|
|
870
|
+
...deviceSlotWait,
|
|
871
|
+
root: projectPath,
|
|
872
|
+
out
|
|
873
|
+
});
|
|
874
|
+
} catch (error) {
|
|
875
|
+
const refusal = error instanceof DeviceAdmissionRefusal ? error : (0, ownership_claim_exports.claimFailure)(error, "stim android");
|
|
876
|
+
if (!refusal) throw error;
|
|
614
877
|
return {
|
|
615
878
|
failed: true,
|
|
616
|
-
|
|
879
|
+
code: refusal.code,
|
|
880
|
+
reason: refusal.message,
|
|
881
|
+
remedy: refusal.remedy
|
|
617
882
|
};
|
|
618
883
|
}
|
|
619
|
-
const result = await waitForAndroidBoot({
|
|
620
|
-
serial,
|
|
621
|
-
timeoutMs,
|
|
622
|
-
pid,
|
|
623
|
-
alive,
|
|
624
|
-
out
|
|
625
|
-
});
|
|
626
|
-
if (result.failed) releaseAndroidConsolePort(projectPath, claim.consolePort, slot);
|
|
627
|
-
return booted(result);
|
|
628
884
|
}
|
|
629
885
|
//#endregion
|
|
630
886
|
//#region src/engine/device.ts
|
|
@@ -668,9 +924,11 @@ async function ensureOwnedDevice({ platform, project, projectPath, slot, setting
|
|
|
668
924
|
});
|
|
669
925
|
}
|
|
670
926
|
const BOOT_POLL_MS = 500;
|
|
671
|
-
async function ensureBooted({ platform, device, simulatorApp, timeoutMs, pollMs = BOOT_POLL_MS, out = () => {}, logFile = null, alive = pidExists, projectPath, slot
|
|
927
|
+
async function ensureBooted({ platform, device, simulatorApp, timeoutMs, pollMs = BOOT_POLL_MS, out = () => {}, logFile = null, alive = pidExists, projectPath, slot, deviceSlotWait }) {
|
|
672
928
|
if (platform === "ios") return ensureIosBooted({
|
|
673
929
|
device,
|
|
930
|
+
projectPath,
|
|
931
|
+
deviceSlotWait,
|
|
674
932
|
simulatorApp,
|
|
675
933
|
timeoutMs: timeoutMs ?? 6e5,
|
|
676
934
|
pollMs,
|
|
@@ -678,6 +936,7 @@ async function ensureBooted({ platform, device, simulatorApp, timeoutMs, pollMs
|
|
|
678
936
|
});
|
|
679
937
|
if (platform === "android") return ensureAndroidBooted({
|
|
680
938
|
device,
|
|
939
|
+
deviceSlotWait,
|
|
681
940
|
projectPath,
|
|
682
941
|
slot,
|
|
683
942
|
timeoutMs: timeoutMs ?? ANDROID_BOOT_TIMEOUT_MS,
|
|
@@ -1523,4 +1782,4 @@ function planFlagRefusal(flag) {
|
|
|
1523
1782
|
};
|
|
1524
1783
|
}
|
|
1525
1784
|
//#endregion
|
|
1526
|
-
export { AvdRecoveryError as _, refusePlan as a, skippedMissReason as c, refreshUpdatesManifestFile as d, swapJsBundle as f, AvdBootError as g, ensureOwnedDevice as h, printPlan as i, UPDATES_MANIFEST_NAME as l, ensureBooted as m, planFlagRefusal as n, explainBuildMiss as o, didSetUpDevice as p, planPayload as r, fingerprintErrorMissReason as s, planCachedBuild as t, detectEntryFile as u, warmMetro as v };
|
|
1785
|
+
export { AvdRecoveryError as _, refusePlan as a, devicePlacementLine as b, skippedMissReason as c, refreshUpdatesManifestFile as d, swapJsBundle as f, AvdBootError as g, ensureOwnedDevice as h, printPlan as i, UPDATES_MANIFEST_NAME as l, ensureBooted as m, planFlagRefusal as n, explainBuildMiss as o, didSetUpDevice as p, planPayload as r, fingerprintErrorMissReason as s, planCachedBuild as t, detectEntryFile as u, warmMetro as v, automaticDevicePlacement as y };
|