stim 1.34.0 → 1.36.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/{acquire-artifact-B0SWoVNt.mjs → acquire-artifact-DGTHCd0Q.mjs} +19 -3
- package/dist/{act-7f7wIvCQ.mjs → act-CvN9xyV6.mjs} +18 -19
- package/dist/{activity-DkS-Ir6V.mjs → activity-BpdDvA8Q.mjs} +4 -4
- package/dist/{agent-device-usage-output-BVdgKbfz.mjs → agent-device-usage-output-pbhaW7_k.mjs} +4 -4
- package/dist/{android-B2DSKg-A.mjs → android-5wkcMFDG.mjs} +1 -1
- package/dist/{android-BU4uBX8I.mjs → android-B0qTdwnt.mjs} +5 -5
- package/dist/{android-Iq0M2t2d.mjs → android-SJx1V3R3.mjs} +5 -5
- package/dist/{android-cas-Dhcjkys1.mjs → android-cas-BS9_55U5.mjs} +4 -4
- package/dist/{android-D7qjT2fq.mjs → android-e9WP10cE.mjs} +47 -41
- package/dist/{android-image-DFk26aY6.mjs → android-image-BZ57YL6R.mjs} +2 -2
- package/dist/{android-project-DhO6el8N.d.mts → android-project-v_1nej_x.d.mts} +3 -1
- package/dist/api.d.mts +20 -6
- package/dist/api.mjs +31 -26
- package/dist/{apk-signed-tail-CPpA-3vu.mjs → apk-signed-tail-eZyXIrnc.mjs} +2 -2
- package/dist/{artifact-DmRtKFXW.mjs → artifact-C3srrGVU.mjs} +36 -14
- package/dist/{artifact-CNnTZs3R.mjs → artifact-ubNdxo_K.mjs} +52 -19
- package/dist/{auto-placement-DA65VQH7.mjs → auto-placement-CKFpFCuq.mjs} +7 -8
- package/dist/{browser-web-Dn_hgKZC.mjs → browser-web-B63vLrj6.mjs} +11 -11
- package/dist/{build-D7SuVoRX.mjs → build-B_Dx9SKJ.mjs} +72 -25
- package/dist/{build-cache-Cqj4FGnX.mjs → build-cache-BW8T4oD2.mjs} +10 -5
- package/dist/{build-plan-Ct1FiA3E.mjs → build-plan-CeIooJqn.mjs} +6 -6
- package/dist/{cache-manifest-8JX9S1QJ.mjs → cache-manifest-CxWkZmUr.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{cli-DjdvQG5U.mjs → cli-COdXswmc.mjs} +19 -18
- package/dist/cli.mjs +1 -1
- package/dist/{client-kU37gURU.mjs → client-KSWIeQLA.mjs} +9 -8
- package/dist/collector-run.mjs +4 -4
- package/dist/{command-output-DjExb_tZ.mjs → command-output-T3cDctRE.mjs} +1 -1
- package/dist/{config-BW0fAtoK.mjs → config-BA3TgoIP.mjs} +59 -10
- package/dist/{dependencies-CZ7c8XX_.mjs → dependencies-LH-7k1Vr.mjs} +35 -38
- package/dist/{dependency-state-mL5g4H6K.mjs → dependency-state-Blfp3AkG.mjs} +1 -1
- package/dist/{dev-client-D3wOllNd.mjs → dev-client-MO_DjTZr.mjs} +2 -2
- package/dist/{device-DH5yf6TU.mjs → device-BZWt_aPJ.mjs} +11 -11
- package/dist/{device-CWPFAqs0.mjs → device-DNTWFFB1.mjs} +12 -12
- package/dist/{device-android-ChfF5I9A.mjs → device-android-BB9Lugr8.mjs} +8 -8
- package/dist/{ccache-ChBMXlBq.mjs → device-capacity-CpAVcKgq.mjs} +1006 -23
- package/dist/device-host-worker.mjs +13 -14
- package/dist/{device-pool-EZziQ0uS.mjs → device-pool-BJToGG-q.mjs} +3 -3
- package/dist/{device-provision-CfpEy-Vm.mjs → device-provision-CxQDCtrc.mjs} +9 -9
- package/dist/{doctor-CGBsS_68.mjs → doctor-C-46SkBe.mjs} +1 -1
- package/dist/{doctor-dwRboaXx.mjs → doctor-CYZ45LnX.mjs} +20 -21
- package/dist/{doctor-B5uEZiKp.mjs → doctor-DV639Iw_.mjs} +15 -16
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-watchman-r7M9UPi0.mjs → doctor-watchman-TZxYt_98.mjs} +4 -4
- package/dist/{eas-build-BpHIt_M3.mjs → eas-build-Xf5Jd6LR.mjs} +2 -2
- package/dist/{eas-fallback-CNPcjq3K.mjs → eas-fallback-DNYPNinw.mjs} +4 -4
- package/dist/{eas-session-ledger-CXwagcQ7.mjs → eas-session-ledger-CXZ4aix0.mjs} +5 -5
- package/dist/{error-diagnostics-Ym2mjmJ0.mjs → error-diagnostics-CvB5bpPU.mjs} +8 -8
- package/dist/{gc-B464w_a5.mjs → gc-8Qm_K1iy.mjs} +2 -2
- package/dist/{gc-C7YxKNci.mjs → gc-DiUhrVFo.mjs} +17 -17
- package/dist/{guide-BFW-cB7R.mjs → guide-CuvHRP53.mjs} +130 -65
- package/dist/{hosted-android-B7yfqXEy.mjs → hosted-android-D__HGVIO.mjs} +3 -3
- package/dist/{hosted-client-CQuzZwAu.mjs → hosted-client-DMOOu8vD.mjs} +6 -6
- package/dist/{hosted-logs-DfYCqrrR.mjs → hosted-logs-CClIktQM.mjs} +6 -6
- package/dist/{hosted-logs-sync-Dlpa2mQF.mjs → hosted-logs-sync-B7XCeqVm.mjs} +5 -5
- package/dist/{hosted-macos-JKefapEm.mjs → hosted-macos-D4sDJIbB.mjs} +5 -5
- package/dist/{hosted-native-B7OFt5gB.mjs → hosted-native-BiiUG_Q6.mjs} +7 -7
- package/dist/{ios-sUPbWqEh.mjs → ios-BZuhvLGr.mjs} +8 -8
- package/dist/{ios-BdZdNsAj.mjs → ios-BhfpRfNf.mjs} +4 -4
- package/dist/{ios-DSBs9c6d.mjs → ios-BhpUWyN7.mjs} +39 -32
- package/dist/{ios-device-Drplrgzo.mjs → ios-device-vhYL1N--.mjs} +1 -1
- package/dist/{ios-project-DoTQYghg.mjs → ios-project-Cz0S1Sz-.mjs} +7 -7
- package/dist/{ios-signing-R34vbrNU.mjs → ios-signing-BcH88ecn.mjs} +1 -1
- package/dist/{ios-state-CWsBysyN.mjs → ios-state-Avwz2cbZ.mjs} +1 -1
- package/dist/{js-swap-DrokhOfo.mjs → js-swap-Desu2iII.mjs} +4 -4
- package/dist/{launch-Cy-MWEZc.mjs → launch-6ckG9UrC.mjs} +19 -19
- package/dist/{lightened-ALwQcQtV.mjs → lightened-B6TnpHMX.mjs} +4 -4
- package/dist/{logs-DuED-01Z.mjs → logs-B-DMy1K0.mjs} +7 -7
- package/dist/{logs-DWT7jGpF.mjs → logs-CO0CJRiC.mjs} +5 -5
- package/dist/{macos-CtBtA_hW.mjs → macos-B1aCXhem.mjs} +19 -19
- package/dist/{macos-kWGcfLzx.mjs → macos-CduEmWAK.mjs} +1 -1
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +5 -5
- package/dist/{metro-B5PVz0Wv.mjs → metro-DM3yJL1M.mjs} +2 -2
- package/dist/{metro-request-2LmFpC1z.mjs → metro-request-O8Q-JvBg.mjs} +1 -1
- package/dist/{named-ports-CA0nB9Yw.mjs → named-ports-BvB_CO9B.mjs} +2 -2
- package/dist/{native-android-tISP2EVp.mjs → native-android-28NOG2-y.mjs} +17 -17
- package/dist/{native-gradle-artifact-inputs-DVoeZkrw.mjs → native-gradle-artifact-inputs-DxVEtS6_.mjs} +3 -3
- package/dist/{native-runtime-CNgxeOCG.mjs → native-runtime-C3_NkUlW.mjs} +6 -6
- package/dist/{native-xcode-inputs-DGzkhpu4.mjs → native-xcode-inputs-BWFTw5cJ.mjs} +2 -2
- package/dist/{native-xcode-ios-B9nsfId2.mjs → native-xcode-ios-B4Qoc7-U.mjs} +16 -16
- package/dist/offload-worker.d.mts +1 -1
- package/dist/offload-worker.mjs +19 -19
- package/dist/{ownership-hC7xvvxF.mjs → ownership-C3y8wLSl.mjs} +2 -2
- package/dist/{phone-reverses-Bo0EzJ-P.mjs → phone-reverses-BhSxbqom.mjs} +4 -4
- package/dist/{placement-log-BsGvKLtU.mjs → placement-log-B8RCSzOm.mjs} +1 -1
- package/dist/{plan-placement-Am0IjuxB.mjs → plan-placement-BI4r55aP.mjs} +6 -6
- package/dist/{ports-CNzg1LYD.mjs → ports-DhOSyWm9.mjs} +3 -3
- package/dist/{prebuild-BfJII57G.mjs → prebuild-Di2IhUue.mjs} +9 -9
- package/dist/{project-DU3jjnBE.mjs → project-Clk1JAWL.mjs} +15 -15
- package/dist/{react-native-android-3dZiJv-4.mjs → react-native-android-bdHBMrnf.mjs} +23 -23
- package/dist/{react-native-build-CuvNPt-q.mjs → react-native-build-CJega_NM.mjs} +7 -7
- package/dist/{react-native-doctor-a35BwMUO.mjs → react-native-doctor-CY7BGITE.mjs} +5 -5
- package/dist/{react-native-ios-CqnReM1t.mjs → react-native-ios-Bo5EDVel.mjs} +25 -20
- package/dist/recorded-build-BuGL_fnm.mjs +58 -0
- package/dist/{recordings-AKZfsW2W.mjs → recordings-6i2-x8LU.mjs} +1 -1
- package/dist/{reload-CC3sNo10.mjs → reload-A_axEbeS.mjs} +14 -14
- package/dist/{reload-YPnvXGlB.mjs → reload-BvDuvygc.mjs} +1 -1
- package/dist/remote-PD6CM0xp.mjs +158 -0
- package/dist/{remote-BfaIHnhM.mjs → remote-WK_swZEw.mjs} +8 -8
- package/dist/{result-H-AxY7Ud.mjs → result-BkDpN5Mz.mjs} +23 -18
- package/dist/{run-N-BbRxnC.mjs → run-CTFi4Nq2.mjs} +1 -1
- package/dist/{server-bare-BTlICuaX.mjs → server-bare-W0aPsRZE.mjs} +1 -1
- package/dist/{server-command-Bn_gOObU.mjs → server-command-S00-ddjK.mjs} +4 -4
- package/dist/server-expo-BWJDa7Qb.mjs +2 -0
- package/dist/{server-expo-CUJ2fuv1.mjs → server-expo-cc-cmfsl.mjs} +2 -2
- package/dist/{settings-B5IBDfTx.mjs → settings-Bap-qjnp.mjs} +1 -1
- package/dist/{settings-DoWHJopy.mjs → settings-C_Xu4RNZ.mjs} +2 -2
- package/dist/{settings-payload-Bxw3hid5.mjs → settings-payload-D5jjhmrw.mjs} +4 -4
- package/dist/{settings-write-C6d7EC54.mjs → settings-write-C5huI-iS.mjs} +5 -5
- package/dist/settings.schema.json +1 -1
- package/dist/{simslim-DKdJx0LL.mjs → simslim-DlBvwgeF.mjs} +1 -1
- package/dist/{slot-launch-kq0-7w9C.mjs → slot-launch-qEQVTth7.mjs} +6 -6
- package/dist/{stage-CBfMTUK3.mjs → stage-CxVI_MlP.mjs} +1 -1
- package/dist/{start-Diu8q6_U.mjs → start-CVzivp35.mjs} +1 -1
- package/dist/{start-WTMumMHi.mjs → start-YpT_JpQQ.mjs} +10 -10
- package/dist/{state-DSOUqO-o.mjs → state-B4B5P4LU.mjs} +1 -1
- package/dist/{state-CtmYTRWm.mjs → state-B9VFI6r0.mjs} +2 -2
- package/dist/{stats-D4cW247z.mjs → stats-COoePEri.mjs} +4 -4
- package/dist/{status-CEwxo-PS.mjs → status-CIg0k7Qb.mjs} +21 -22
- package/dist/{status-B-oeWS0Z.mjs → status-CIvU5-TF.mjs} +1 -1
- package/dist/{status-DTFhDnd1.mjs → status-CQWmNl1f.mjs} +1 -1
- package/dist/{status-watch-D63R5nSI.mjs → status-watch--rfZynD_.mjs} +4 -4
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-_WTria-r.mjs → stim-desktop-D0P_bzmd.mjs} +1 -1
- package/dist/{stop-HL2RvhrE.mjs → stop-BEBBruvD.mjs} +4 -4
- package/dist/{stop-Dm9ON6Os.mjs → stop-BiI4_VFG.mjs} +2 -2
- package/dist/{stop-vX4w3_8V.mjs → stop-C3d5qG7C.mjs} +15 -15
- package/dist/supervisor-run.mjs +12 -13
- package/dist/support-BJbXovoO.mjs +2089 -0
- package/dist/{support-BNe1_Hg7.mjs → support-Vckdzrmk.mjs} +5 -5
- package/dist/{swiftpm-artifact-inputs-uq5oV7xR.mjs → swiftpm-artifact-inputs-DbuF-Yrr.mjs} +1 -1
- package/dist/{swiftpm-macos-ClF203_2.mjs → swiftpm-macos-Bu8xeBfM.mjs} +8 -8
- package/dist/{toolchain-CECahBDa.mjs → toolchain-CIRdNl-c.mjs} +1 -1
- package/dist/{toolchain-CYonNjd_.mjs → toolchain-DCnWAxQL.mjs} +71 -7
- package/dist/{warm-progress-q11Vdvhh.mjs → warm-progress-DwsGBpph.mjs} +3 -3
- package/dist/{web-BdaMBr2O.mjs → web-D2En0Wa5.mjs} +8 -8
- package/dist/web-Dpj70t4p.mjs +2 -0
- package/dist/web-run.mjs +4 -4
- package/dist/{workspace-state-BdZ-QgmB.mjs → workspace-state-BhwAJBgA.mjs} +2 -2
- package/dist/{workspaces-B9v5V7Es.mjs → workspaces-Dh5N70qW.mjs} +11 -11
- package/dist/{worktree-C4MBOMz7.mjs → worktree-DLm4s2Ib.mjs} +1 -1
- package/dist/{worktree-C3N86KpI.mjs → worktree-Yw3EW77B.mjs} +24 -24
- package/package.json +7 -7
- package/dist/device-capacity-CHC3dKWg.mjs +0 -867
- package/dist/device-ios-B3-Ah--R.mjs +0 -716
- package/dist/device-lease-run-i3FNX4OE.mjs +0 -282
- package/dist/idle-shutdown-DPD8oV36.mjs +0 -142
- package/dist/selection-CH-MUVGD.mjs +0 -791
- package/dist/server-expo-B59N16uT.mjs +0 -2
- package/dist/support-ivsfDj0v.mjs +0 -287
- package/dist/web-CIpHpGp8.mjs +0 -2
|
@@ -1,716 +0,0 @@
|
|
|
1
|
-
import { D as ownership_claim_exports, l as cancellableSleep, n as isTimeoutError, p as withWorkspaceProcessLock, t as getExecutor } from "./exec-CGuDzt40.mjs";
|
|
2
|
-
import { D as workspaceId$1, k as workspaceLogsDir$1 } from "./workspace-state-BdZ-QgmB.mjs";
|
|
3
|
-
import { l as phaseLine } from "./command-output-DjExb_tZ.mjs";
|
|
4
|
-
import { T as setDevice, a as clearDevice, d as getConfigDir, ft as deviceSlotPlatforms, ht as projectDeviceSlots, k as withConfigLockAsync$1, v as loadConfig$1, w as saveConfig } from "./config-BW0fAtoK.mjs";
|
|
5
|
-
import { D as iosSimSlimProfileSetting, E as iosSimSlimDefaultSetting } from "./settings-B5IBDfTx.mjs";
|
|
6
|
-
import { Ct as selectParked, bt as parkedMaxSetting, gt as dropParked, ht as adoptParked, xt as readParked } from "./android-Iq0M2t2d.mjs";
|
|
7
|
-
import { i as createNdjsonWriter } from "./ndjson-CrjIsGzw.mjs";
|
|
8
|
-
import { _t as teardownParkedIosSim, ht as teardownOwnedIosSim } from "./workspaces-B9v5V7Es.mjs";
|
|
9
|
-
import { A as springBoardRunning, B as reportMemoryCulprits, C as renameIosSim, D as resolveOwnedIosSim, E as resolveIosCreation, F as hostMemoryPressureAdvice, M as waitForSpringBoard, N as configuredIosSimulatorViewer, R as readHostMemoryPressure, S as readSpringBoardPid, T as resetIosPrivacy, _ as ownedSimName, a as createOwnedIosSim, d as listAllIosSims, f as listAllIosSimsAsync, h as listIosRuntimesAsync, n as bootIosSim, p as listIosDeviceTypesAsync, u as iosSimulatorFailureAdvice, w as resetIosKeychain, y as parseRuntimeVersion } from "./ios-BdZdNsAj.mjs";
|
|
10
|
-
import { _ as withDeviceBootAdmission, f as runtimeMismatch, l as deviceTypeMismatch, n as DeviceAdmissionRefusal } from "./device-capacity-CHC3dKWg.mjs";
|
|
11
|
-
import { createHash } from "node:crypto";
|
|
12
|
-
import { readFileSync } from "node:fs";
|
|
13
|
-
import { homedir } from "node:os";
|
|
14
|
-
import { join } from "node:path";
|
|
15
|
-
import { LOG_ROTATE_BYTES, ambientContext } from "@stim-cli/core";
|
|
16
|
-
import { isJsonObject } from "@stim-cli/core/state";
|
|
17
|
-
import chalk from "chalk";
|
|
18
|
-
import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
19
|
-
//#region src/devices/springboard-crash-reports.ts
|
|
20
|
-
const REPORT_WINDOW_MS = 6e5;
|
|
21
|
-
const MAX_CANDIDATES = 100;
|
|
22
|
-
const MAX_STORED = 40;
|
|
23
|
-
const MAX_REPORT_BYTES = 1048576;
|
|
24
|
-
const MAX_COPIED_BYTES = 8388608;
|
|
25
|
-
function selectSpringBoardReports(entries, udid, sinceMs) {
|
|
26
|
-
const owner = `.${udid}`.toLowerCase();
|
|
27
|
-
return entries.flatMap(({ name, text }) => {
|
|
28
|
-
if (!/^SpringBoard-.+\.ips$/.test(name)) return [];
|
|
29
|
-
try {
|
|
30
|
-
const report = JSON.parse(text.slice(text.indexOf("\n") + 1));
|
|
31
|
-
if (!isJsonObject(report)) return [];
|
|
32
|
-
const { coalitionName, captureTime } = report;
|
|
33
|
-
const capturedAt = Date.parse(typeof captureTime === "string" ? captureTime : "");
|
|
34
|
-
return typeof coalitionName === "string" && coalitionName.toLowerCase().endsWith(owner) && capturedAt >= sinceMs ? [name] : [];
|
|
35
|
-
} catch {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Copies this simulator's recent SpringBoard crash reports from DiagnosticReports and its Retired folder into
|
|
42
|
-
* `destDir`, which keeps at most 40 of them. The source folders are only read; macOS deletes their reports after
|
|
43
|
-
* about two days. Returns the matching reports now in `destDir`, how many matched but did not fit its limits, and
|
|
44
|
-
* the message of a write that failed.
|
|
45
|
-
*/
|
|
46
|
-
async function copySpringBoardCrashReports({ udid, destDir, now = Date.now(), home = homedir() }) {
|
|
47
|
-
const since = now - REPORT_WINDOW_MS;
|
|
48
|
-
const reportsDir = join(home, "Library/Logs/DiagnosticReports");
|
|
49
|
-
const candidates = /* @__PURE__ */ new Map();
|
|
50
|
-
for (const directory of [reportsDir, join(reportsDir, "Retired")]) {
|
|
51
|
-
let names;
|
|
52
|
-
try {
|
|
53
|
-
names = await readdir(directory);
|
|
54
|
-
} catch (error) {
|
|
55
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") continue;
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
for (const name of names) {
|
|
59
|
-
if (!/^SpringBoard-.+\.ips$/.test(name) || candidates.has(name)) continue;
|
|
60
|
-
try {
|
|
61
|
-
const path = join(directory, name);
|
|
62
|
-
const { mtimeMs, size } = await stat(path);
|
|
63
|
-
if (mtimeMs >= since && size <= MAX_REPORT_BYTES) candidates.set(name, {
|
|
64
|
-
path,
|
|
65
|
-
mtimeMs
|
|
66
|
-
});
|
|
67
|
-
} catch {}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const newest = [...candidates].toSorted((a, b) => b[1].mtimeMs - a[1].mtimeMs).slice(0, MAX_CANDIDATES);
|
|
71
|
-
const entries = [];
|
|
72
|
-
for (const [name, { path }] of newest) try {
|
|
73
|
-
entries.push({
|
|
74
|
-
name,
|
|
75
|
-
text: await readFile(path, "utf8")
|
|
76
|
-
});
|
|
77
|
-
} catch {}
|
|
78
|
-
const matching = selectSpringBoardReports(entries, udid, since);
|
|
79
|
-
if (matching.length === 0) return {
|
|
80
|
-
files: [],
|
|
81
|
-
dropped: 0
|
|
82
|
-
};
|
|
83
|
-
await mkdir(destDir, {
|
|
84
|
-
recursive: true,
|
|
85
|
-
mode: 448
|
|
86
|
-
});
|
|
87
|
-
const present = new Set(await readdir(destDir));
|
|
88
|
-
let stored = [...present].filter((name) => /^SpringBoard-.+\.ips$/.test(name)).length;
|
|
89
|
-
let copiedBytes = 0;
|
|
90
|
-
const files = [];
|
|
91
|
-
for (const { name, text } of entries) {
|
|
92
|
-
if (!matching.includes(name)) continue;
|
|
93
|
-
if (present.has(name)) {
|
|
94
|
-
files.push(name);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const bytes = Buffer.byteLength(text);
|
|
98
|
-
if (stored >= MAX_STORED || copiedBytes + bytes > MAX_COPIED_BYTES) continue;
|
|
99
|
-
try {
|
|
100
|
-
await writeFile(join(destDir, name), text, {
|
|
101
|
-
flag: "wx",
|
|
102
|
-
mode: 384
|
|
103
|
-
});
|
|
104
|
-
} catch (error) {
|
|
105
|
-
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
106
|
-
files.push(name);
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
await rm(join(destDir, name), { force: true }).catch(() => {});
|
|
110
|
-
return {
|
|
111
|
-
files,
|
|
112
|
-
dropped: 0,
|
|
113
|
-
failure: error instanceof Error ? error.message : String(error)
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
stored++;
|
|
117
|
-
copiedBytes += bytes;
|
|
118
|
-
files.push(name);
|
|
119
|
-
}
|
|
120
|
-
return {
|
|
121
|
-
files,
|
|
122
|
-
dropped: matching.length - files.length
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/engine/ios-boot-log.ts
|
|
127
|
-
function iosBootRecorder(root, slot, udid) {
|
|
128
|
-
return (event, { level = "info", ...fields }) => {
|
|
129
|
-
try {
|
|
130
|
-
const writer = createNdjsonWriter(join(workspaceLogsDir$1(root), "device.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
131
|
-
writer.write({
|
|
132
|
-
src: "device",
|
|
133
|
-
platform: "ios",
|
|
134
|
-
level,
|
|
135
|
-
event,
|
|
136
|
-
deviceId: udid,
|
|
137
|
-
...slot && slot !== "default" ? { slot } : {},
|
|
138
|
-
...fields
|
|
139
|
-
});
|
|
140
|
-
writer.close();
|
|
141
|
-
} catch {}
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
//#region src/engine/device-ios.ts
|
|
146
|
-
function recordBootPhase(record, udid, origin) {
|
|
147
|
-
return (event) => {
|
|
148
|
-
const pid = "pid" in event ? event.pid : void 0;
|
|
149
|
-
const boot = event.phase === "boot_requested" ? origin : void 0;
|
|
150
|
-
record("ios_boot", {
|
|
151
|
-
phase: event.phase,
|
|
152
|
-
...pid === void 0 ? {} : { pid },
|
|
153
|
-
...boot === void 0 ? {} : { boot },
|
|
154
|
-
msg: `ios boot ${udid}: ${event.phase}${pid === void 0 ? "" : ` pid ${pid}`}${boot === void 0 ? "" : ` (${boot})`}`
|
|
155
|
-
});
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function startIosBoot(udid, configure, label, out, simulatorApp, root, slot, origin, deviceSlotWait) {
|
|
159
|
-
const done = withDeviceBootAdmission({
|
|
160
|
-
platform: "ios",
|
|
161
|
-
key: udid
|
|
162
|
-
}, async () => {
|
|
163
|
-
out(chalk.dim(phaseLine("device", `booting ${label} (${udid})`)));
|
|
164
|
-
await bootIosSim(udid, {
|
|
165
|
-
label,
|
|
166
|
-
out,
|
|
167
|
-
simulatorApp,
|
|
168
|
-
env: ambientContext()?.env,
|
|
169
|
-
onPhase: recordBootPhase(iosBootRecorder(root, slot, udid), udid, origin)
|
|
170
|
-
});
|
|
171
|
-
await configure();
|
|
172
|
-
await muteBootedSimulator(udid, out);
|
|
173
|
-
}, {
|
|
174
|
-
...deviceSlotWait,
|
|
175
|
-
root,
|
|
176
|
-
out
|
|
177
|
-
});
|
|
178
|
-
done.catch(() => {});
|
|
179
|
-
return {
|
|
180
|
-
udid,
|
|
181
|
-
done
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
const SPRINGBOARD_MUTE_WAIT_MS = 6e4;
|
|
185
|
-
async function muteBootedSimulator(udid, out) {
|
|
186
|
-
try {
|
|
187
|
-
const springBoard = await waitForSpringBoard(udid, Date.now() + SPRINGBOARD_MUTE_WAIT_MS);
|
|
188
|
-
if (springBoard.state === "unreadable") throw new Error(springBoard.reason);
|
|
189
|
-
if (springBoard.state === "timed-out") throw new Error(`SpringBoard did not finish starting within ${SPRINGBOARD_MUTE_WAIT_MS / 1e3}s.`);
|
|
190
|
-
const response = JSON.parse(await getExecutor().runFileAsync("xcrun", [
|
|
191
|
-
"devicectl",
|
|
192
|
-
"device",
|
|
193
|
-
"settings",
|
|
194
|
-
"audio",
|
|
195
|
-
"--device",
|
|
196
|
-
udid,
|
|
197
|
-
"--volume",
|
|
198
|
-
"0",
|
|
199
|
-
"--json-output",
|
|
200
|
-
"-"
|
|
201
|
-
], { timeoutMs: 3e4 }));
|
|
202
|
-
if (!isJsonObject(response) || !isJsonObject(response.info) || response.info.outcome !== "success" || !isJsonObject(response.result) || typeof response.result.deviceIdentifier !== "string" || response.result.deviceIdentifier.toUpperCase() !== udid.toUpperCase() || response.result.volume !== 0) throw new Error("Xcode did not confirm volume zero for this simulator.");
|
|
203
|
-
out(chalk.dim(phaseLine("device", "simulator muted; turn on Sound in its Stim Desktop options")));
|
|
204
|
-
} catch (error) {
|
|
205
|
-
out(chalk.yellow(phaseLine("device", `Could not mute this simulator: ${error instanceof Error ? error.message : String(error)}`)));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
var IosDeviceMismatchError = class extends Error {
|
|
209
|
-
remedy = "Run `stim worktree remove` (or `stim gc --delete`) to reap the current sim, then `stim ios` again to create the requested one, or pass `--slot <name>` to create it beside the current one.";
|
|
210
|
-
};
|
|
211
|
-
async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, label, settings, flags, note, out, reconcileIosSimulator, simSnapshot }) {
|
|
212
|
-
const pressure = readHostMemoryPressure();
|
|
213
|
-
const memoryAdvice = hostMemoryPressureAdvice(pressure);
|
|
214
|
-
if (memoryAdvice) out(chalk.yellow(phaseLine("memory", memoryAdvice)));
|
|
215
|
-
reportMemoryCulprits(pressure, (named) => out(chalk.yellow(phaseLine("memory", named))));
|
|
216
|
-
const simslimProfile = iosSimSlimProfileSetting(settings, settingsRoot);
|
|
217
|
-
const simslimDefault = iosSimSlimDefaultSetting(settings);
|
|
218
|
-
if (record?.deviceUdid) {
|
|
219
|
-
if (record.owned) {
|
|
220
|
-
const listed = simSnapshot ? simSnapshot.read() : listAllIosSims({ includeUnavailable: true });
|
|
221
|
-
const resolved = resolveOwnedIosSim(record.deviceUdid, listed);
|
|
222
|
-
if (resolved.notOwned) note(chalk.yellow(`Note: recorded sim is now named "${resolved.notOwned}", not Stim-owned -- creating a fresh owned sim instead of booting it.`));
|
|
223
|
-
else if (resolved.missing) {} else {
|
|
224
|
-
const sim = resolved.sim;
|
|
225
|
-
const wantedType = flags.deviceType || settings?.ios?.deviceType;
|
|
226
|
-
const deviceTypes = await listIosDeviceTypesAsync({ snapshot: simSnapshot });
|
|
227
|
-
const mismatch = deviceTypeMismatch(sim.deviceTypeIdentifier, wantedType, deviceTypes);
|
|
228
|
-
if (mismatch) throw new IosDeviceMismatchError(`${mismatch}. Stim will not silently boot a different model.`);
|
|
229
|
-
const versionMismatch = flags.runtimeFlag ? runtimeMismatch(sim.runtime, flags.runtimeFlag, await listIosRuntimesAsync({ snapshot: simSnapshot })) : null;
|
|
230
|
-
if (versionMismatch) throw new IosDeviceMismatchError(`${versionMismatch}. Stim will not silently boot a different iOS version.`);
|
|
231
|
-
const model = {
|
|
232
|
-
model: deviceTypes.find((d) => d.identifier === sim.deviceTypeIdentifier)?.name ?? null,
|
|
233
|
-
runtime: parseRuntimeVersion(sim.runtime)
|
|
234
|
-
};
|
|
235
|
-
const name = ownedIosName(sim, label, model, projectPath, listed) === sim.name ? sim.name : await withIosDeviceNameLock(() => renameToOwnedName(sim, label, model, projectPath));
|
|
236
|
-
const updated = {
|
|
237
|
-
deviceUdid: sim.udid,
|
|
238
|
-
owned: true,
|
|
239
|
-
deviceName: name,
|
|
240
|
-
...record.simslimManaged ? { simslimManaged: true } : {},
|
|
241
|
-
...record.simslimApplied ? { simslimApplied: record.simslimApplied } : {},
|
|
242
|
-
...record.adopted ? { adopted: true } : {},
|
|
243
|
-
...record.adoptionPending ? { adoptionPending: true } : {},
|
|
244
|
-
...record.parkedCacheKey ? { parkedCacheKey: record.parkedCacheKey } : {},
|
|
245
|
-
...record.schemeApprovals ? { schemeApprovals: record.schemeApprovals } : {}
|
|
246
|
-
};
|
|
247
|
-
const configure = async (freshBoot) => {
|
|
248
|
-
if (record.adoptionPending) await resetAdoptedSim(sim.udid, out);
|
|
249
|
-
return configureOwnedIosSim({
|
|
250
|
-
record: updated,
|
|
251
|
-
projectPath,
|
|
252
|
-
slot,
|
|
253
|
-
profile: simslimProfile,
|
|
254
|
-
slimByDefault: simslimDefault,
|
|
255
|
-
freshBoot,
|
|
256
|
-
out,
|
|
257
|
-
reconcileIosSimulator
|
|
258
|
-
});
|
|
259
|
-
};
|
|
260
|
-
const facts = {
|
|
261
|
-
deviceType: model.model,
|
|
262
|
-
runtime: model.runtime
|
|
263
|
-
};
|
|
264
|
-
if (sim.state !== "Booted") return {
|
|
265
|
-
...updated,
|
|
266
|
-
booting: startIosBoot(sim.udid, () => configure(true), name, out, flags.simulatorApp, projectPath, slot, record.adoptionPending ? "adopted" : "existing", flags.deviceSlotWait),
|
|
267
|
-
...facts
|
|
268
|
-
};
|
|
269
|
-
const { record: configured, rebooted } = await configure(false);
|
|
270
|
-
if (rebooted) await muteBootedSimulator(sim.udid, out);
|
|
271
|
-
return {
|
|
272
|
-
...configured,
|
|
273
|
-
...facts,
|
|
274
|
-
booted: sim.udid
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
} else {
|
|
278
|
-
const sim = (await listAllIosSimsAsync()).find((s) => s.udid === record.deviceUdid);
|
|
279
|
-
if (sim) {
|
|
280
|
-
if (sim.state !== "Booted") {
|
|
281
|
-
note(chalk.yellow(`Note: assigned sim ${sim.name} (${sim.udid}) is shut down and is not owned by Stim, so it will not be booted automatically.`));
|
|
282
|
-
note(chalk.dim("Boot it yourself, or run `stim gc --delete` to clear the assignment so Stim can create an owned sim."));
|
|
283
|
-
}
|
|
284
|
-
return record;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
await withConfigLockAsync$1(() => {
|
|
288
|
-
const current = deviceSlotPlatforms(loadConfig$1()?.projects?.[projectPath], slot)?.ios;
|
|
289
|
-
if (!current) return;
|
|
290
|
-
if (current.deviceUdid !== record.deviceUdid || current.owned !== record.owned) throw new Error("The simulator assignment changed during recovery. Run `stim ios` again.");
|
|
291
|
-
clearDevice(projectPath, "ios", slot);
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
const choice = await resolveIosCreation({
|
|
295
|
-
deviceType: flags.deviceType || settings.ios?.deviceType,
|
|
296
|
-
runtime: flags.runtime || settings.ios?.runtime
|
|
297
|
-
});
|
|
298
|
-
const adopted = parkedMaxSetting("ios").max > 0 ? await withIosDeviceNameLock(() => takeParkedIosSim({
|
|
299
|
-
projectPath,
|
|
300
|
-
slot,
|
|
301
|
-
label,
|
|
302
|
-
choice,
|
|
303
|
-
out
|
|
304
|
-
})) : null;
|
|
305
|
-
if (adopted) {
|
|
306
|
-
const booting = startIosBoot(adopted.deviceUdid, async () => {
|
|
307
|
-
await resetAdoptedSim(adopted.deviceUdid, out);
|
|
308
|
-
await configureOwnedIosSim({
|
|
309
|
-
record: adopted,
|
|
310
|
-
projectPath,
|
|
311
|
-
slot,
|
|
312
|
-
profile: simslimProfile,
|
|
313
|
-
slimByDefault: simslimDefault,
|
|
314
|
-
freshBoot: true,
|
|
315
|
-
out,
|
|
316
|
-
reconcileIosSimulator
|
|
317
|
-
});
|
|
318
|
-
}, adopted.deviceName, out, flags.simulatorApp, projectPath, slot, "adopted", flags.deviceSlotWait);
|
|
319
|
-
return {
|
|
320
|
-
...adopted,
|
|
321
|
-
booting,
|
|
322
|
-
deviceType: choice.deviceType,
|
|
323
|
-
runtime: choice.runtime
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
const created = await withIosDeviceNameLock(async () => {
|
|
327
|
-
const suffix = ownedIosNameSuffix(label, {
|
|
328
|
-
model: choice.deviceType,
|
|
329
|
-
runtime: choice.runtime
|
|
330
|
-
}, projectPath, void 0, await listAllIosSimsAsync({ includeUnavailable: true }));
|
|
331
|
-
const result = await createOwnedIosSim(label, { suffix }, choice);
|
|
332
|
-
await withConfigLockAsync$1(() => setDevice(projectPath, "ios", {
|
|
333
|
-
deviceUdid: result.udid,
|
|
334
|
-
owned: true,
|
|
335
|
-
deviceName: result.name
|
|
336
|
-
}, slot));
|
|
337
|
-
return result;
|
|
338
|
-
});
|
|
339
|
-
const newRecord = {
|
|
340
|
-
deviceUdid: created.udid,
|
|
341
|
-
owned: true,
|
|
342
|
-
deviceName: created.name
|
|
343
|
-
};
|
|
344
|
-
const booting = startIosBoot(created.udid, () => configureOwnedIosSim({
|
|
345
|
-
record: newRecord,
|
|
346
|
-
projectPath,
|
|
347
|
-
slot,
|
|
348
|
-
profile: simslimProfile,
|
|
349
|
-
slimByDefault: simslimDefault,
|
|
350
|
-
freshBoot: true,
|
|
351
|
-
out,
|
|
352
|
-
reconcileIosSimulator
|
|
353
|
-
}), created.name, out, flags.simulatorApp, projectPath, slot, "created", flags.deviceSlotWait);
|
|
354
|
-
return {
|
|
355
|
-
...newRecord,
|
|
356
|
-
created: true,
|
|
357
|
-
booting,
|
|
358
|
-
deviceType: created.deviceType,
|
|
359
|
-
runtime: created.runtime
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function withIosDeviceNameLock(fn) {
|
|
363
|
-
return withWorkspaceProcessLock(getConfigDir(), "ios-device-names", async () => fn(), { external: true });
|
|
364
|
-
}
|
|
365
|
-
function ownedIosNameSuffix(label, model, projectPath, udid, listed) {
|
|
366
|
-
const names = new Set(listed.filter((sim) => sim.udid !== udid).map((sim) => sim.name));
|
|
367
|
-
for (const project of Object.values(loadConfig$1()?.projects ?? {})) for (const { platforms } of projectDeviceSlots(project)) {
|
|
368
|
-
const record = platforms.ios;
|
|
369
|
-
if (record?.deviceUdid !== udid && record?.deviceName) names.add(record.deviceName);
|
|
370
|
-
}
|
|
371
|
-
for (const parked of readParked("ios")) if (parked.udid !== udid) names.add(parked.name);
|
|
372
|
-
let suffix = "";
|
|
373
|
-
for (let attempt = 0; names.has(ownedSimName(label, model, suffix)); attempt++) suffix = ` ${workspaceId$1(projectPath)}${attempt ? `-${attempt}` : ""}`;
|
|
374
|
-
return suffix;
|
|
375
|
-
}
|
|
376
|
-
function ownedIosName(sim, label, model, projectPath, listed) {
|
|
377
|
-
return ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, sim.udid, listed));
|
|
378
|
-
}
|
|
379
|
-
async function renameToOwnedName(sim, label, model, projectPath) {
|
|
380
|
-
const wanted = ownedIosName(sim, label, model, projectPath, await listAllIosSimsAsync({ includeUnavailable: true }));
|
|
381
|
-
if (sim.name === wanted) return wanted;
|
|
382
|
-
try {
|
|
383
|
-
await renameIosSim(sim.udid, wanted);
|
|
384
|
-
return wanted;
|
|
385
|
-
} catch {
|
|
386
|
-
return sim.name;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
async function resetAdoptedSim(udid, out) {
|
|
390
|
-
out(chalk.dim(phaseLine("device", `resetting privacy grants and the keychain on ${udid}`)));
|
|
391
|
-
await resetIosPrivacy(udid);
|
|
392
|
-
await resetIosKeychain(udid);
|
|
393
|
-
}
|
|
394
|
-
async function takeParkedIosSim({ projectPath, slot, label, choice, out }) {
|
|
395
|
-
const candidates = selectParked(readParked("ios"), {
|
|
396
|
-
deviceTypeIdentifier: choice.deviceTypeId,
|
|
397
|
-
runtimeIdentifier: choice.runtimeId
|
|
398
|
-
});
|
|
399
|
-
if (candidates.length === 0) return null;
|
|
400
|
-
const listed = new Map((await listAllIosSimsAsync({ includeUnavailable: true })).map((sim) => [sim.udid, sim]));
|
|
401
|
-
for (const parked of candidates) {
|
|
402
|
-
const sim = listed.get(parked.udid);
|
|
403
|
-
if (!sim || !sim.available) {
|
|
404
|
-
const result = sim ? await teardownParkedIosSim(parked.udid, { label: parked.name }) : null;
|
|
405
|
-
if (sim ? result?.status === "torn-down" : await dropParked("ios", parked.udid)) out(chalk.dim(phaseLine("device", `deleted parked ${parked.name} (${parked.udid}): ${sim ? "unavailable" : "gone"}`)));
|
|
406
|
-
else if (result?.status === "failed") out(chalk.yellow(phaseLine("device", `could not delete unavailable parked ${parked.name} (${parked.udid}): ${result.reason}`)));
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
if (!sim.name.startsWith("stim-")) {
|
|
410
|
-
out(chalk.yellow(phaseLine("device", `kept parked record for ${parked.udid}: simulator is now named ${JSON.stringify(sim.name)} and is not Stim-owned`)));
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
const model = {
|
|
414
|
-
model: choice.deviceType,
|
|
415
|
-
runtime: choice.runtime
|
|
416
|
-
};
|
|
417
|
-
const name = ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, parked.udid, [...listed.values()]));
|
|
418
|
-
const device = {
|
|
419
|
-
deviceUdid: parked.udid,
|
|
420
|
-
owned: true,
|
|
421
|
-
deviceName: name,
|
|
422
|
-
adopted: true,
|
|
423
|
-
adoptionPending: true,
|
|
424
|
-
...parked.simslimManaged ? { simslimManaged: true } : {},
|
|
425
|
-
...parked.cacheKey ? { parkedCacheKey: parked.cacheKey } : {}
|
|
426
|
-
};
|
|
427
|
-
const adopted = await adoptParked({
|
|
428
|
-
platform: "ios",
|
|
429
|
-
projectPath,
|
|
430
|
-
slot,
|
|
431
|
-
udid: parked.udid,
|
|
432
|
-
device
|
|
433
|
-
});
|
|
434
|
-
if (!adopted) continue;
|
|
435
|
-
try {
|
|
436
|
-
await renameIosSim(parked.udid, name);
|
|
437
|
-
} catch {}
|
|
438
|
-
return adopted.schemeApprovals && adopted.schemeApprovals.length > 0 ? {
|
|
439
|
-
...device,
|
|
440
|
-
schemeApprovals: adopted.schemeApprovals
|
|
441
|
-
} : device;
|
|
442
|
-
}
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
function clearIosAdoptionPending(projectPath, slot = "default") {
|
|
446
|
-
return withConfigLockAsync$1(() => {
|
|
447
|
-
const cfg = loadConfig$1();
|
|
448
|
-
const ios = deviceSlotPlatforms(cfg?.projects?.[projectPath], slot)?.ios;
|
|
449
|
-
if (!cfg || !ios?.adoptionPending) return;
|
|
450
|
-
delete ios.adopted;
|
|
451
|
-
delete ios.adoptionPending;
|
|
452
|
-
delete ios.parkedCacheKey;
|
|
453
|
-
saveConfig(cfg);
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
function simslimProfileIdentity(profile, slimByDefault) {
|
|
457
|
-
if (profile) return `profile:${createHash("sha256").update(readFileSync(profile)).digest("hex")}`;
|
|
458
|
-
return slimByDefault ? "default" : null;
|
|
459
|
-
}
|
|
460
|
-
async function startedSpringBoardPid(udid) {
|
|
461
|
-
const springBoard = await waitForSpringBoard(udid, Date.now() + SPRINGBOARD_MUTE_WAIT_MS);
|
|
462
|
-
return springBoard.state === "started" ? springBoard.pid : null;
|
|
463
|
-
}
|
|
464
|
-
async function configureOwnedIosSim({ record, projectPath, slot, profile, slimByDefault, freshBoot, out, reconcileIosSimulator }) {
|
|
465
|
-
const identity = simslimProfileIdentity(profile, slimByDefault);
|
|
466
|
-
const slimConfigured = identity !== null || Boolean(record.simslimManaged);
|
|
467
|
-
const applied = record.simslimApplied;
|
|
468
|
-
const springBoardBefore = slimConfigured ? await readSpringBoardPid(record.deviceUdid) : null;
|
|
469
|
-
if (identity !== null && record.simslimManaged && !freshBoot && applied?.profile === identity && springBoardBefore !== null && springBoardBefore === applied.springBoardPid) {
|
|
470
|
-
await withConfigLockAsync$1(() => setDevice(projectPath, "ios", { ...record }, slot));
|
|
471
|
-
return {
|
|
472
|
-
record,
|
|
473
|
-
rebooted: false
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
if (profile) out(chalk.dim(phaseLine("device", `applying the SimSlim profile to ${record.deviceUdid}`)));
|
|
477
|
-
else if (slimByDefault) out(chalk.dim(phaseLine("device", `applying SimSlim's default services to ${record.deviceUdid}`)));
|
|
478
|
-
else if (record.simslimManaged) out(chalk.dim(phaseLine("device", `restoring stock simulator services on ${record.deviceUdid}`)));
|
|
479
|
-
const previouslyManaged = Boolean(record.simslimManaged);
|
|
480
|
-
if (identity !== null && !record.simslimManaged || applied) {
|
|
481
|
-
const { simslimApplied: _applied, ...rest } = record;
|
|
482
|
-
const pending = identity !== null ? {
|
|
483
|
-
...rest,
|
|
484
|
-
simslimManaged: true
|
|
485
|
-
} : rest;
|
|
486
|
-
await withConfigLockAsync$1(() => setDevice(projectPath, "ios", pending, slot));
|
|
487
|
-
record = pending;
|
|
488
|
-
}
|
|
489
|
-
const result = await reconcileIosSimulator({
|
|
490
|
-
context: ambientContext(),
|
|
491
|
-
udid: record.deviceUdid,
|
|
492
|
-
profile,
|
|
493
|
-
slimByDefault,
|
|
494
|
-
previouslyManaged,
|
|
495
|
-
out
|
|
496
|
-
});
|
|
497
|
-
const updated = { ...record };
|
|
498
|
-
if (result.managed) updated.simslimManaged = true;
|
|
499
|
-
else delete updated.simslimManaged;
|
|
500
|
-
const springBoardAfter = slimConfigured ? await startedSpringBoardPid(record.deviceUdid) : null;
|
|
501
|
-
if (result.managed && !result.notInstalled && identity !== null && springBoardAfter !== null) updated.simslimApplied = {
|
|
502
|
-
profile: identity,
|
|
503
|
-
springBoardPid: springBoardAfter
|
|
504
|
-
};
|
|
505
|
-
await withConfigLockAsync$1(() => setDevice(projectPath, "ios", updated, slot));
|
|
506
|
-
const rebooted = slimConfigured && springBoardAfter !== springBoardBefore;
|
|
507
|
-
if (rebooted && !result.notInstalled) iosBootRecorder(projectPath, slot, record.deviceUdid)("ios_boot", {
|
|
508
|
-
phase: "simslim_reboot",
|
|
509
|
-
pidBefore: springBoardBefore,
|
|
510
|
-
pidAfter: springBoardAfter,
|
|
511
|
-
msg: `ios boot ${record.deviceUdid}: simslim_reboot (SpringBoard pid ${springBoardBefore ?? "unknown"} to ${springBoardAfter ?? "unknown"})`
|
|
512
|
-
});
|
|
513
|
-
return {
|
|
514
|
-
record: updated,
|
|
515
|
-
rebooted
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
const SPRINGBOARD_RESPAWN_POLLS = 20;
|
|
519
|
-
const SPAWN_STALL_TOLERANCE_MS = 18e4;
|
|
520
|
-
async function ensureIosBooted(args) {
|
|
521
|
-
const { springBoardDown, ...first } = await bootOwnedIosSim(args);
|
|
522
|
-
const { device, projectPath, out } = args;
|
|
523
|
-
const udid = device?.deviceUdid;
|
|
524
|
-
if (!springBoardDown || !device || !udid) return first;
|
|
525
|
-
out(chalk.yellow(phaseLine("device", `SpringBoard is not running on ${udid}; restarting the simulator once`)));
|
|
526
|
-
const record = iosBootRecorder(projectPath, args.slot, udid);
|
|
527
|
-
await preserveSpringBoardReports(record, udid, projectPath);
|
|
528
|
-
const stopped = await teardownOwnedIosSim(udid, { workspace: projectPath });
|
|
529
|
-
if (stopped.status !== "torn-down") return {
|
|
530
|
-
...first,
|
|
531
|
-
reason: `${first.reason} The restart did not run: ${stopped.reason ?? stopped.status}.`
|
|
532
|
-
};
|
|
533
|
-
record("ios_boot", {
|
|
534
|
-
phase: "restart",
|
|
535
|
-
level: "warn",
|
|
536
|
-
msg: `ios boot ${udid}: restart (SpringBoard is not running after boot; restarting once)`
|
|
537
|
-
});
|
|
538
|
-
const { booted: _booted, booting: _booting, ...unbooted } = device;
|
|
539
|
-
const { springBoardDown: stillDown, ...second } = await bootOwnedIosSim({
|
|
540
|
-
...args,
|
|
541
|
-
device: unbooted,
|
|
542
|
-
origin: "restart"
|
|
543
|
-
});
|
|
544
|
-
if (stillDown) await preserveSpringBoardReports(record, udid, projectPath);
|
|
545
|
-
return stillDown ? {
|
|
546
|
-
...second,
|
|
547
|
-
reason: `${second.reason} Stim already restarted the simulator once, so it did not restart it again.`
|
|
548
|
-
} : second;
|
|
549
|
-
}
|
|
550
|
-
async function preserveSpringBoardReports(record, udid, root) {
|
|
551
|
-
const dir = workspaceLogsDir$1(root);
|
|
552
|
-
try {
|
|
553
|
-
const { files, dropped, failure } = await copySpringBoardCrashReports({
|
|
554
|
-
udid,
|
|
555
|
-
destDir: dir
|
|
556
|
-
});
|
|
557
|
-
const limit = dropped ? `; ${dropped} more matched but exceeded the copy limits` : "";
|
|
558
|
-
record("springboard_crash_reports", {
|
|
559
|
-
level: files.length || dropped || failure ? "warn" : "info",
|
|
560
|
-
files,
|
|
561
|
-
dropped,
|
|
562
|
-
...failure ? { failure } : {},
|
|
563
|
-
dir,
|
|
564
|
-
msg: failure ? `could not copy a SpringBoard crash report for ${udid} (${files.length} copied before it): ${failure}` : files.length ? `copied ${files.length} SpringBoard crash report(s) for ${udid} to ${dir}: ${files.join(", ")}${limit}` : dropped ? `${dropped} SpringBoard crash report(s) for ${udid} matched but exceeded the copy limits` : `no SpringBoard crash report for ${udid} from the last 10 minutes`
|
|
565
|
-
});
|
|
566
|
-
} catch (error) {
|
|
567
|
-
record("springboard_crash_reports", {
|
|
568
|
-
level: "warn",
|
|
569
|
-
files: [],
|
|
570
|
-
dropped: 0,
|
|
571
|
-
failure: error instanceof Error ? error.message : String(error),
|
|
572
|
-
dir,
|
|
573
|
-
msg: `could not copy SpringBoard crash reports for ${udid}: ${error instanceof Error ? error.message : String(error)}`
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
async function bootOwnedIosSim({ device, projectPath, slot, origin, deviceSlotWait, simulatorApp, timeoutMs, pollMs, out }) {
|
|
578
|
-
const udid = device?.deviceUdid;
|
|
579
|
-
if (!udid) return {
|
|
580
|
-
failed: true,
|
|
581
|
-
reason: "No iOS simulator is recorded for this project."
|
|
582
|
-
};
|
|
583
|
-
const onPhase = recordBootPhase(iosBootRecorder(projectPath, slot, udid), udid, origin ?? (device.adoptionPending ? "adopted" : "existing"));
|
|
584
|
-
const openViewer = async () => {
|
|
585
|
-
await configuredIosSimulatorViewer(simulatorApp, ambientContext()?.env).open(udid);
|
|
586
|
-
onPhase({ phase: "viewer_opened" });
|
|
587
|
-
};
|
|
588
|
-
const ready = async () => {
|
|
589
|
-
try {
|
|
590
|
-
const stallDeadline = Date.now() + SPAWN_STALL_TOLERANCE_MS;
|
|
591
|
-
const listSpringBoard = async () => {
|
|
592
|
-
for (;;) try {
|
|
593
|
-
return await getExecutor().runFileAsync("xcrun", [
|
|
594
|
-
"simctl",
|
|
595
|
-
"spawn",
|
|
596
|
-
udid,
|
|
597
|
-
"launchctl",
|
|
598
|
-
"list"
|
|
599
|
-
], { timeoutMs: 3e4 });
|
|
600
|
-
} catch (error) {
|
|
601
|
-
if (!isTimeoutError(error) || Date.now() >= stallDeadline) throw error;
|
|
602
|
-
const sims = await listAllIosSimsAsync().catch(() => null);
|
|
603
|
-
if (sims && sims.find((s) => s.udid === udid)?.state !== "Booted") throw error;
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
let listing = await listSpringBoard();
|
|
607
|
-
for (let poll = 0; !springBoardRunning(listing) && poll < SPRINGBOARD_RESPAWN_POLLS; poll++) {
|
|
608
|
-
await cancellableSleep(pollMs);
|
|
609
|
-
listing = await listSpringBoard();
|
|
610
|
-
}
|
|
611
|
-
if (!springBoardRunning(listing)) return {
|
|
612
|
-
failed: true,
|
|
613
|
-
springBoardDown: true,
|
|
614
|
-
reason: `Simulator ${udid} reports Booted, but SpringBoard (the system shell) is not running, so apps cannot launch. Run \`stim stop\`, then \`stim ios\` again. If it repeats, look for SpringBoard crash reports in ~/Library/Logs/DiagnosticReports.`
|
|
615
|
-
};
|
|
616
|
-
return {
|
|
617
|
-
ok: true,
|
|
618
|
-
udid
|
|
619
|
-
};
|
|
620
|
-
} catch (error) {
|
|
621
|
-
return {
|
|
622
|
-
failed: true,
|
|
623
|
-
reason: `Simulator ${udid} failed its process-spawn readiness check: ${error?.message || error}. ${await iosSimulatorFailureAdvice()}`
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
};
|
|
627
|
-
const booting = device?.booting;
|
|
628
|
-
if (booting?.udid === udid) {
|
|
629
|
-
try {
|
|
630
|
-
await booting.done;
|
|
631
|
-
} catch (e) {
|
|
632
|
-
return bootFailure(udid, e);
|
|
633
|
-
}
|
|
634
|
-
return ready();
|
|
635
|
-
}
|
|
636
|
-
const readiness = device?.booted === udid ? await ready() : null;
|
|
637
|
-
if (readiness?.ok) {
|
|
638
|
-
if (simulatorApp !== void 0) await openViewer();
|
|
639
|
-
return readiness;
|
|
640
|
-
}
|
|
641
|
-
let resolved;
|
|
642
|
-
try {
|
|
643
|
-
resolved = resolveOwnedIosSim(udid, await listAllIosSimsAsync());
|
|
644
|
-
} catch (e) {
|
|
645
|
-
return {
|
|
646
|
-
failed: true,
|
|
647
|
-
reason: `Could not list simulators: ${e?.message || e}`
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
if (resolved.missing) return {
|
|
651
|
-
failed: true,
|
|
652
|
-
reason: `Simulator ${udid} no longer exists. Run \`stim ios\` again to create a fresh owned sim.`
|
|
653
|
-
};
|
|
654
|
-
if (resolved.notOwned) return {
|
|
655
|
-
failed: true,
|
|
656
|
-
reason: `Simulator ${udid} is now named "${resolved.notOwned}" and is not Stim-owned; refusing to boot it.`
|
|
657
|
-
};
|
|
658
|
-
const sim = resolved.sim;
|
|
659
|
-
if (sim.state === "Booted") {
|
|
660
|
-
const result = readiness ?? await ready();
|
|
661
|
-
if (result.ok && simulatorApp !== void 0) await openViewer();
|
|
662
|
-
return result;
|
|
663
|
-
}
|
|
664
|
-
const bootDeadline = Date.now() + timeoutMs;
|
|
665
|
-
try {
|
|
666
|
-
await withDeviceBootAdmission({
|
|
667
|
-
platform: "ios",
|
|
668
|
-
key: udid
|
|
669
|
-
}, async () => {
|
|
670
|
-
out(chalk.dim(phaseLine("device", `booting ${sim.name} (${udid})`)));
|
|
671
|
-
await bootIosSim(udid, {
|
|
672
|
-
timeoutMs,
|
|
673
|
-
label: sim.name,
|
|
674
|
-
out,
|
|
675
|
-
simulatorApp,
|
|
676
|
-
env: ambientContext()?.env,
|
|
677
|
-
onPhase
|
|
678
|
-
});
|
|
679
|
-
await muteBootedSimulator(udid, out);
|
|
680
|
-
}, {
|
|
681
|
-
...deviceSlotWait,
|
|
682
|
-
root: projectPath,
|
|
683
|
-
out
|
|
684
|
-
});
|
|
685
|
-
} catch (e) {
|
|
686
|
-
return bootFailure(udid, e);
|
|
687
|
-
}
|
|
688
|
-
const deadline = Math.max(bootDeadline, Date.now() + 2 * pollMs);
|
|
689
|
-
while (Date.now() < deadline) {
|
|
690
|
-
await cancellableSleep(pollMs);
|
|
691
|
-
let state = null;
|
|
692
|
-
try {
|
|
693
|
-
state = (await listAllIosSimsAsync({ timeoutMs: 3e4 })).find((s) => s.udid === udid)?.state ?? null;
|
|
694
|
-
} catch {}
|
|
695
|
-
if (state === "Booted") return ready();
|
|
696
|
-
}
|
|
697
|
-
return {
|
|
698
|
-
failed: true,
|
|
699
|
-
reason: `Simulator ${udid} did not reach the Booted state within ${Math.round(timeoutMs / 1e3)}s.`
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
function bootFailure(udid, error) {
|
|
703
|
-
const refusal = error instanceof DeviceAdmissionRefusal ? error : (0, ownership_claim_exports.claimFailure)(error, "stim ios");
|
|
704
|
-
if (refusal) return {
|
|
705
|
-
failed: true,
|
|
706
|
-
code: refusal.code,
|
|
707
|
-
reason: refusal.message,
|
|
708
|
-
remedy: refusal.remedy
|
|
709
|
-
};
|
|
710
|
-
return {
|
|
711
|
-
failed: true,
|
|
712
|
-
reason: `Could not boot simulator ${udid}: ${error?.message || error}`
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
//#endregion
|
|
716
|
-
export { muteBootedSimulator as a, ensureOwnedIosDevice as i, clearIosAdoptionPending as n, ensureIosBooted as r, IosDeviceMismatchError as t };
|