stim 1.14.0 → 1.16.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 +2 -0
- package/dist/activity-BxwdD81S.mjs +609 -0
- package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
- package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
- package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
- package/dist/android-cas-8U4DPqeR.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
- package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
- package/dist/attempt-Bk2ouQVL.mjs +39 -0
- package/dist/budget-DjrURfQn.mjs +2700 -0
- package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
- package/dist/build-slots-rUk77xqh.mjs +132 -0
- package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
- package/dist/cli-BkYZ_6hy.mjs +51 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-BTY686R6.mjs +1368 -0
- package/dist/collector-run.mjs +9 -195
- package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
- package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
- package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
- package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
- package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CroAIjjj.mjs +43 -0
- package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
- package/dist/device-capacity-BHwxNBlu.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +964 -0
- package/dist/device-ios-BadmeL2V.mjs +381 -0
- package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
- package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
- package/dist/device-pool-CUaEWMMm.mjs +125 -0
- package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
- package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
- package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
- package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
- package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
- package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
- package/dist/hosted-client-a-WmqE2L.mjs +197 -0
- package/dist/hosted-ios-CIWelIqf.mjs +220 -0
- package/dist/hosted-logs-D5g041Q3.mjs +187 -0
- package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
- package/dist/idle-DYVymG92.mjs +1099 -0
- package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
- package/dist/in-use-DvBw0Kxo.mjs +130 -0
- package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
- package/dist/ios-Cr1h5gnO.mjs +189 -0
- package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
- package/dist/ios-state-DS5UpYTH.mjs +48 -0
- package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
- package/dist/logs-CHEVK8zD.mjs +371 -0
- package/dist/machines-BIBUdhpj.mjs +265 -0
- package/dist/macos-CSYEAFmF.mjs +473 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/maintenance-run.d.mts +4 -0
- package/dist/maintenance-run.mjs +254 -0
- package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
- package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
- package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
- package/dist/native-run-NaBrRFtQ.mjs +147 -0
- package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
- package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
- package/dist/offload-worker.d.mts +122 -0
- package/dist/offload-worker.mjs +606 -0
- package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
- package/dist/ownership-hCkPzGmr.mjs +571 -0
- package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
- package/dist/prebuild-D2fsca_Z.mjs +213 -0
- package/dist/preview-DhVbvPAZ.mjs +318 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-BIXOzVnr.mjs +37 -0
- package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
- package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
- package/dist/run-f4vI6EnK.mjs +119 -0
- package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
- package/dist/server-expo-CVqO2c35.mjs +2 -0
- package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
- package/dist/settings-BBpMcDbD.mjs +25 -0
- package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
- package/dist/settings-oTSkkNrM.mjs +1439 -0
- package/dist/settings.schema.json +845 -97
- package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
- package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
- package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CX8Ig-U2.mjs +2 -0
- package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
- package/dist/state-3DwSQIBK.mjs +41 -0
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
- package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
- package/dist/stats-CEZ_i5je.mjs +77 -0
- package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
- package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
- package/dist/status-DlKvVJBE.mjs +49 -0
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/stop-B0Yxtmiy.mjs +48 -0
- package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
- package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
- package/dist/stop-cause-CidxIqup.mjs +97 -0
- package/dist/supervisor-run.d.mts +43 -11
- package/dist/supervisor-run.mjs +363 -24
- package/dist/support-CAP8qDUF.mjs +316 -0
- package/dist/support-D4aYJniO.mjs +201 -0
- package/dist/teardown-CL6vDs2Y.mjs +727 -0
- package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
- package/dist/trigger-Bemu8ytw.mjs +65 -0
- package/dist/trigger-CXts6qt1.mjs +2 -0
- package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
- package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
- package/dist/web-run.mjs +310 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
- package/dist/workspaces-BV4pdHFz.mjs +306 -0
- package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
- package/dist/worktree-jnG8Iph5.mjs +2 -0
- package/package.json +10 -5
- package/shim/bundle-response.cjs +28 -12
- package/dist/activity-CYVDcrt3.mjs +0 -356
- package/dist/budget-CGDkhvv_.mjs +0 -1745
- package/dist/build-progress-DxKpwnaS.mjs +0 -247
- package/dist/idle-DXtx3RbX.mjs +0 -191
- package/dist/in-use-DlqBDKqY.mjs +0 -249
- package/dist/logs-Civ4gbBH.mjs +0 -486
- package/dist/merge-state-ytFQCeh4.mjs +0 -262
- package/dist/server-expo-DIHDhvGg.mjs +0 -2
- package/dist/settings-D61iNOsB.mjs +0 -629
- package/dist/start-Cetfvy8l.mjs +0 -2
- package/dist/stats-CFpFGlJV.mjs +0 -62
- package/dist/stats-CX1Z8Tca.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
- package/dist/worktree-BVrHsYZG.mjs +0 -752
- package/dist/worktree-CHWWvm5v.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { R as deviceSlotKey, _ as loadConfig$1 } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { o as formatLongDuration } from "./command-output-DnJMdEY-.mjs";
|
|
3
|
+
import { a as updateWorkspaceState, r as readWorkspaceState$1 } from "./workspace-state-B8-aJ1_5.mjs";
|
|
4
|
+
import { o as canonicalPath } from "./in-use-DvBw0Kxo.mjs";
|
|
5
|
+
import { n as collectOwnedDeviceActivity, s as workspaceBuildInProgress } from "./idle-DYVymG92.mjs";
|
|
6
|
+
import { u as listAllIosSims } from "./ios-BaInn3sW.mjs";
|
|
7
|
+
import { i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-CL6vDs2Y.mjs";
|
|
8
|
+
import { DEVICE_IDLE_SHUTDOWN_KEY, readDeviceIdleShutdowns } from "@stim-cli/core/state";
|
|
9
|
+
//#region src/devices/idle-shutdown.ts
|
|
10
|
+
const SIM_LIST_TIMEOUT_MS = 1e4;
|
|
11
|
+
const MINUTE_MS = 6e4;
|
|
12
|
+
/**
|
|
13
|
+
* How long a booted owned device has been idle, when that is at least `idleMs` and nothing keeps it in use: no
|
|
14
|
+
* driver, Stim or agent-device lock, or unreadable activity evidence, no build in the workspace, and no activity
|
|
15
|
+
* (including an open stim-server viewer) for `idleMs`. Null keeps the device running.
|
|
16
|
+
*/
|
|
17
|
+
function idleShutdownDueMs(activity, { idleMs, now, buildInProgress, platform = process.platform }) {
|
|
18
|
+
if (buildInProgress || activity.state === "driven") return null;
|
|
19
|
+
const unknown = platform === "win32" ? activity.basis.filter((basis) => basis !== "driver-process") : activity.basis;
|
|
20
|
+
if (activity.state === "unknown" && unknown.length > 0) return null;
|
|
21
|
+
const last = Date.parse(activity.lastActivityAt ?? "");
|
|
22
|
+
if (!Number.isFinite(last)) return null;
|
|
23
|
+
const idle = now - last;
|
|
24
|
+
return idle >= idleMs ? idle : null;
|
|
25
|
+
}
|
|
26
|
+
function listSims() {
|
|
27
|
+
try {
|
|
28
|
+
return listAllIosSims({ timeoutMs: SIM_LIST_TIMEOUT_MS });
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The workspace's booted owned simulators and emulators that have been idle for `idleMs` or more. */
|
|
34
|
+
function dueIdleDevices(root, idleMs, now = Date.now()) {
|
|
35
|
+
const config = loadConfig$1();
|
|
36
|
+
const self = canonicalPath(root);
|
|
37
|
+
const entry = Object.entries(config?.projects ?? {}).find(([path]) => canonicalPath(path) === self);
|
|
38
|
+
if (!config || !entry) return [];
|
|
39
|
+
const buildInProgress = workspaceBuildInProgress(entry[0]);
|
|
40
|
+
return collectOwnedDeviceActivity({
|
|
41
|
+
...config,
|
|
42
|
+
projects: { [entry[0]]: entry[1] }
|
|
43
|
+
}, listSims(), now).flatMap((device) => {
|
|
44
|
+
const idleForMs = idleShutdownDueMs(device.activity, {
|
|
45
|
+
idleMs,
|
|
46
|
+
now,
|
|
47
|
+
buildInProgress
|
|
48
|
+
});
|
|
49
|
+
return idleForMs === null ? [] : [{
|
|
50
|
+
device,
|
|
51
|
+
idleForMs
|
|
52
|
+
}];
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Shuts down, through centralized teardown, each of the workspace's owned devices that is still idle for `idleMs`,
|
|
57
|
+
* and records why. The caller holds the workspace's native-run lock, so no `ios` or `android` run is booting or
|
|
58
|
+
* installing on them.
|
|
59
|
+
*/
|
|
60
|
+
function shutDownIdleDevices(root, idleMs, log, now = Date.now()) {
|
|
61
|
+
let shutDown = 0;
|
|
62
|
+
for (const { device, idleForMs } of dueIdleDevices(root, idleMs, now)) {
|
|
63
|
+
const what = `${device.kind === "ios" ? "simulator" : "emulator"} ${device.name}`;
|
|
64
|
+
const outcome = device.kind === "ios" ? teardownOwnedIosSim(device.id, {
|
|
65
|
+
label: device.name,
|
|
66
|
+
workspace: root
|
|
67
|
+
}) : teardownOwnedAvd(device.id, {
|
|
68
|
+
owner: {
|
|
69
|
+
projectPath: device.project,
|
|
70
|
+
slot: device.slot
|
|
71
|
+
},
|
|
72
|
+
workspace: root
|
|
73
|
+
});
|
|
74
|
+
if (outcome.status === "torn-down") {
|
|
75
|
+
shutDown++;
|
|
76
|
+
const idleMinutes = Math.floor(idleForMs / MINUTE_MS);
|
|
77
|
+
try {
|
|
78
|
+
updateWorkspaceState(root, (state) => ({
|
|
79
|
+
...state,
|
|
80
|
+
[DEVICE_IDLE_SHUTDOWN_KEY]: {
|
|
81
|
+
...readDeviceIdleShutdowns(state),
|
|
82
|
+
[deviceSlotKey(device.kind, device.slot)]: {
|
|
83
|
+
at: new Date(now).toISOString(),
|
|
84
|
+
idleMinutes
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
} catch (error) {
|
|
89
|
+
log({
|
|
90
|
+
level: "warn",
|
|
91
|
+
event: "device_idle_shutdown_failed",
|
|
92
|
+
msg: `shut down idle ${what} but could not record it: ${error?.message || error}`
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
log({
|
|
96
|
+
level: "info",
|
|
97
|
+
event: "device_idle_shutdown",
|
|
98
|
+
msg: `shut down ${what}, idle ${formatLongDuration(idleForMs)}`
|
|
99
|
+
});
|
|
100
|
+
} else if (outcome.status !== "missing") log({
|
|
101
|
+
level: "warn",
|
|
102
|
+
event: "device_idle_shutdown_failed",
|
|
103
|
+
msg: `could not shut down idle ${what}: ${outcome.reason}`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return shutDown;
|
|
107
|
+
}
|
|
108
|
+
/** Forgets the slot's idle shutdown once a run boots its device again. */
|
|
109
|
+
function clearDeviceIdleShutdown(root, platform, slot = "default") {
|
|
110
|
+
const key = deviceSlotKey(platform, slot);
|
|
111
|
+
if (!(key in readDeviceIdleShutdowns(readWorkspaceState$1(root)))) return;
|
|
112
|
+
updateWorkspaceState(root, (state) => {
|
|
113
|
+
const { [key]: _cleared, ...rest } = readDeviceIdleShutdowns(state);
|
|
114
|
+
const { [DEVICE_IDLE_SHUTDOWN_KEY]: _all, ...others } = state;
|
|
115
|
+
return Object.keys(rest).length ? {
|
|
116
|
+
...others,
|
|
117
|
+
[DEVICE_IDLE_SHUTDOWN_KEY]: rest
|
|
118
|
+
} : others;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { dueIdleDevices as n, shutDownIdleDevices as r, clearDeviceIdleShutdown as t };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { p as getProject } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
|
+
import { r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-B8-aJ1_5.mjs";
|
|
4
|
+
import { o as readWebRecord, u as webFacts } from "./state-C1jB7Q8q.mjs";
|
|
5
|
+
import { h as listBuildLocks } from "./device-lease-D-hLqx1b.mjs";
|
|
6
|
+
import { n as listBuildSlots } from "./build-slots-rUk77xqh.mjs";
|
|
7
|
+
import { n as workspaceProcessLockError, r as workspaceProcessLockPath, t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
|
|
8
|
+
import { i as macosRuntimeClaim } from "./state-3DwSQIBK.mjs";
|
|
9
|
+
import { n as managedLockHolders, t as resolveSupervisorTarget } from "./ownership-hCkPzGmr.mjs";
|
|
10
|
+
import { lstatSync, readdirSync, rmSync, rmdirSync, unlinkSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { realpathSync as realpathSync$1 } from "fs";
|
|
13
|
+
import { resolve as resolve$1 } from "path";
|
|
14
|
+
import { hostedIosRecords, macosAppState, parseHostedIosPlacement, readMacosRecord, unreadableHostedIos } from "@stim-cli/core/state";
|
|
15
|
+
//#region src/commands/gc/paths.ts
|
|
16
|
+
function canonicalPath(p) {
|
|
17
|
+
try {
|
|
18
|
+
return realpathSync$1(p);
|
|
19
|
+
} catch {
|
|
20
|
+
return resolve$1(p);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/commands/gc/results.ts
|
|
25
|
+
const results = [];
|
|
26
|
+
function recordGcResult(kind, status, label, { id = null, bytes = null, detail = null } = {}) {
|
|
27
|
+
results.push({
|
|
28
|
+
kind,
|
|
29
|
+
status,
|
|
30
|
+
label,
|
|
31
|
+
id,
|
|
32
|
+
bytes,
|
|
33
|
+
detail
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function takeGcResults() {
|
|
37
|
+
return results.splice(0);
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/workspace/in-use.ts
|
|
41
|
+
const NATIVE_RUN = "native-run";
|
|
42
|
+
const NATIVE_RUN_HELD = "a stim ios, android or stop run holds its native-run.lock";
|
|
43
|
+
function workspaceInUse(root, { supervisor = true, managedLocks = true, hosted = true, nativeRun = true } = {}) {
|
|
44
|
+
const reasons = [];
|
|
45
|
+
if (supervisor) {
|
|
46
|
+
const project = getProject(root);
|
|
47
|
+
const target = resolveSupervisorTarget({
|
|
48
|
+
state: readWorkspaceState$1(root)?.supervisor,
|
|
49
|
+
record: project?.supervisor,
|
|
50
|
+
reservedPort: project?.metroPort
|
|
51
|
+
});
|
|
52
|
+
if (target.status === "ours") reasons.push(`its dev server supervisor (pid ${target.pid}) is running`);
|
|
53
|
+
else if (target.status === "unverified") reasons.push(`its dev server supervisor cannot be verified: ${target.reason ?? "unknown identity"}`);
|
|
54
|
+
const macos = macosAppState(readMacosRecord(root));
|
|
55
|
+
if (macos?.host) reasons.push(`its macOS app runs on ${macos.host.machine}`);
|
|
56
|
+
else if (macos?.state === "running" || macos?.state === "orphaned" || macos?.build.state === "running") reasons.push("its macOS app or build is running");
|
|
57
|
+
else if (macos?.state === "unverified" || !macos && readWorkspaceState$1(root)?.macos !== void 0) reasons.push("its macOS process owner cannot be verified");
|
|
58
|
+
const runtime = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
|
|
59
|
+
if (runtime.live.length) reasons.push("its macOS runtime claim is held");
|
|
60
|
+
else if (runtime.unresolved[0]) reasons.push(`its macOS runtime cannot be verified: ${runtime.unresolved[0].reason}`);
|
|
61
|
+
const browser = webFacts(readWebRecord(root));
|
|
62
|
+
if (browser?.status === "running" || browser?.status === "orphaned") reasons.push(`its owned Chrome (pid ${browser.record.chromeProcess?.pid}) is running`);
|
|
63
|
+
else if (browser?.status === "unverified") reasons.push("its owned Chrome cannot be verified");
|
|
64
|
+
}
|
|
65
|
+
if (nativeRun) {
|
|
66
|
+
const claims = (0, ownership_claim_exports.readClaimSet)(workspaceProcessLockPath(workspaceDir(root), NATIVE_RUN, true));
|
|
67
|
+
if (claims.live.length) reasons.push(NATIVE_RUN_HELD);
|
|
68
|
+
else if (claims.unresolved[0]) reasons.push(`its native-run.lock cannot be resolved: ${claims.unresolved[0].reason}`);
|
|
69
|
+
}
|
|
70
|
+
for (const [slot, record] of Object.entries(hosted ? hostedIosRecords(readWorkspaceState$1(root)) : {})) {
|
|
71
|
+
const placement = parseHostedIosPlacement(record);
|
|
72
|
+
reasons.push(placement ? `its iOS simulator runs on ${placement.machine}` : unreadableHostedIos(slot));
|
|
73
|
+
}
|
|
74
|
+
const self = canonicalPath(root);
|
|
75
|
+
for (const [kind, entries] of [["build lock", listBuildLocks()], ["build slot", listBuildSlots()]]) for (const entry of entries) {
|
|
76
|
+
if (!entry.alive && !entry.unresolved) continue;
|
|
77
|
+
if (entry.projectRoot !== null && canonicalPath(entry.projectRoot) === self) reasons.push(`a ${entry.alive ? "live" : "unresolvable"} ${kind} at ${entry.path} names it`);
|
|
78
|
+
}
|
|
79
|
+
if (managedLocks) reasons.push(...managedLockHolders(root));
|
|
80
|
+
return reasons;
|
|
81
|
+
}
|
|
82
|
+
function emptyWorkspaceDir(dir) {
|
|
83
|
+
if (lstatSync(dir).isSymbolicLink()) {
|
|
84
|
+
unlinkSync(dir);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
for (const name of readdirSync(dir)) if (name !== `${NATIVE_RUN}.lock`) rmSync(join(dir, name), {
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function withIdleWorkspace(root, fn, { purpose, ...checks }) {
|
|
93
|
+
try {
|
|
94
|
+
return await withWorkspaceProcessLock(workspaceDir(root), NATIVE_RUN, async () => {
|
|
95
|
+
const reasons = workspaceInUse(root, {
|
|
96
|
+
...checks,
|
|
97
|
+
nativeRun: false
|
|
98
|
+
});
|
|
99
|
+
if (reasons.length) return {
|
|
100
|
+
ran: false,
|
|
101
|
+
reasons
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
ran: true,
|
|
105
|
+
value: await fn()
|
|
106
|
+
};
|
|
107
|
+
}, {
|
|
108
|
+
external: true,
|
|
109
|
+
waitMs: 0,
|
|
110
|
+
ownerPurpose: purpose
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (workspaceProcessLockError(error)) return {
|
|
114
|
+
ran: false,
|
|
115
|
+
reasons: [NATIVE_RUN_HELD]
|
|
116
|
+
};
|
|
117
|
+
if ((0, ownership_claim_exports.isClaimRefusal)(error) || (0, ownership_claim_exports.isClaimUnavailable)(error)) return {
|
|
118
|
+
ran: false,
|
|
119
|
+
reasons: [`its native-run.lock cannot be taken: ${error.reason}`]
|
|
120
|
+
};
|
|
121
|
+
throw error;
|
|
122
|
+
} finally {
|
|
123
|
+
try {
|
|
124
|
+
const dir = workspaceDir(root);
|
|
125
|
+
if (!lstatSync(dir).isSymbolicLink()) rmdirSync(dir);
|
|
126
|
+
} catch {}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { takeGcResults as a, recordGcResult as i, withIdleWorkspace as n, canonicalPath as o, workspaceInUse as r, emptyWorkspaceDir as t };
|
|
@@ -1,13 +1,144 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { _ as loadConfig$1 } from "./config-D0DbpZtM.mjs";
|
|
3
3
|
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-D5owjN4C.mjs";
|
|
5
|
+
import { at as isStimOwnedSim } from "./android-B_NumVyQ.mjs";
|
|
6
|
+
import { n as settingDefault, t as STIM_DESKTOP_OPEN_OPTIONS } from "./stim-desktop-Cnz8CPnl.mjs";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { closeSync, existsSync, lstatSync, mkdtempSync, openSync, readSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
8
10
|
import { IOS_SIMULATOR_APPS, settingDefinition } from "@stim-cli/core/state";
|
|
9
|
-
import { dirname, join, resolve } from "node:path";
|
|
10
11
|
import { tmpdir } from "node:os";
|
|
12
|
+
//#region src/engine/installed-artifact.ts
|
|
13
|
+
const READ_CHUNK_BYTES = 1048576;
|
|
14
|
+
const DEVICE_PATH_TIMEOUT_MS = 3e4;
|
|
15
|
+
const DEVICE_HASH_TIMEOUT_MS = 12e4;
|
|
16
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
17
|
+
function parseInstalledApkPath(text) {
|
|
18
|
+
if (typeof text !== "string") return null;
|
|
19
|
+
const paths = [];
|
|
20
|
+
for (const raw of text.split("\n")) {
|
|
21
|
+
const line = raw.trim();
|
|
22
|
+
if (!line.startsWith("package:")) continue;
|
|
23
|
+
const path = line.slice(8);
|
|
24
|
+
if (path.startsWith("/")) paths.push(path);
|
|
25
|
+
}
|
|
26
|
+
return paths.length === 1 ? paths[0] : null;
|
|
27
|
+
}
|
|
28
|
+
function parseDeviceSha256(text) {
|
|
29
|
+
if (typeof text !== "string") return null;
|
|
30
|
+
const first = text.trim().split(/\s+/)[0] ?? "";
|
|
31
|
+
return SHA256_HEX.test(first) ? first : null;
|
|
32
|
+
}
|
|
33
|
+
function parseAppContainerPath(text) {
|
|
34
|
+
if (typeof text !== "string") return null;
|
|
35
|
+
const lines = text.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
36
|
+
return lines.length === 1 && isAbsolute(lines[0]) ? lines[0] : null;
|
|
37
|
+
}
|
|
38
|
+
function artifactsMatch(local, installed) {
|
|
39
|
+
return Boolean(local) && local === installed;
|
|
40
|
+
}
|
|
41
|
+
function hashFile(file) {
|
|
42
|
+
let fd = null;
|
|
43
|
+
try {
|
|
44
|
+
fd = openSync(file, "r");
|
|
45
|
+
const digest = createHash("sha256");
|
|
46
|
+
const buffer = Buffer.allocUnsafe(READ_CHUNK_BYTES);
|
|
47
|
+
for (;;) {
|
|
48
|
+
const read = readSync(fd, buffer, 0, READ_CHUNK_BYTES, null);
|
|
49
|
+
if (read <= 0) break;
|
|
50
|
+
digest.update(buffer.subarray(0, read));
|
|
51
|
+
}
|
|
52
|
+
return digest.digest("hex");
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
} finally {
|
|
56
|
+
if (fd !== null) try {
|
|
57
|
+
closeSync(fd);
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function hashBundle(dir) {
|
|
62
|
+
const digest = createHash("sha256");
|
|
63
|
+
const walk = (abs, rel) => {
|
|
64
|
+
let names;
|
|
65
|
+
try {
|
|
66
|
+
names = readdirSync(abs);
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
for (const name of names.toSorted()) {
|
|
71
|
+
const child = join(abs, name);
|
|
72
|
+
const path = rel === "" ? name : `${rel}/${name}`;
|
|
73
|
+
let stat;
|
|
74
|
+
try {
|
|
75
|
+
stat = lstatSync(child);
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (stat.isDirectory()) {
|
|
80
|
+
if (!walk(child, path)) return false;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!stat.isFile()) return false;
|
|
84
|
+
const file = hashFile(child);
|
|
85
|
+
if (file === null) return false;
|
|
86
|
+
digest.update(`${path}\0${file}\n`);
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
90
|
+
return walk(dir, "") ? digest.digest("hex") : null;
|
|
91
|
+
}
|
|
92
|
+
function deviceHoldsApk({ serial, packageName, apkPath }, { exec = null } = {}) {
|
|
93
|
+
const e = exec || getExecutor();
|
|
94
|
+
let path;
|
|
95
|
+
try {
|
|
96
|
+
path = parseInstalledApkPath(e.runFile("adb", [
|
|
97
|
+
"-s",
|
|
98
|
+
serial,
|
|
99
|
+
"shell",
|
|
100
|
+
"pm",
|
|
101
|
+
"path",
|
|
102
|
+
packageName
|
|
103
|
+
], { timeoutMs: DEVICE_PATH_TIMEOUT_MS }));
|
|
104
|
+
} catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
if (!path) return false;
|
|
108
|
+
let installed;
|
|
109
|
+
try {
|
|
110
|
+
installed = parseDeviceSha256(e.runFile("adb", [
|
|
111
|
+
"-s",
|
|
112
|
+
serial,
|
|
113
|
+
"shell",
|
|
114
|
+
"sha256sum",
|
|
115
|
+
path
|
|
116
|
+
], { timeoutMs: DEVICE_HASH_TIMEOUT_MS }));
|
|
117
|
+
} catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (!installed) return false;
|
|
121
|
+
return artifactsMatch(hashFile(apkPath), installed);
|
|
122
|
+
}
|
|
123
|
+
function deviceHoldsBundle({ udid, bundleId, appPath }, { exec = null } = {}) {
|
|
124
|
+
const e = exec || getExecutor();
|
|
125
|
+
let container;
|
|
126
|
+
try {
|
|
127
|
+
container = parseAppContainerPath(e.runFile("xcrun", [
|
|
128
|
+
"simctl",
|
|
129
|
+
"get_app_container",
|
|
130
|
+
udid,
|
|
131
|
+
bundleId
|
|
132
|
+
], { timeoutMs: DEVICE_PATH_TIMEOUT_MS }));
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (!container) return false;
|
|
137
|
+
const installed = hashBundle(container);
|
|
138
|
+
if (!installed) return false;
|
|
139
|
+
return artifactsMatch(hashBundle(appPath), installed);
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
11
142
|
//#region src/host-memory.ts
|
|
12
143
|
function readHostMemoryPressure(exec = getExecutor(), platform = process.platform) {
|
|
13
144
|
if (platform !== "darwin") return null;
|
|
@@ -201,7 +332,7 @@ async function awaitBootCommand(args, attemptMs, onLine) {
|
|
|
201
332
|
const detail = lines.length ? `: ${lines.join(" | ")}` : "";
|
|
202
333
|
throw new Error(`${command} failed with exit code ${result.code ?? "unknown"}${detail}`);
|
|
203
334
|
}
|
|
204
|
-
async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = BOOTSTATUS_ATTEMPT_MS, simulatorApp, label = udid, out = () => {} } = {}) {
|
|
335
|
+
async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = BOOTSTATUS_ATTEMPT_MS, simulatorApp, openViewer = true, label = udid, out = () => {} } = {}) {
|
|
205
336
|
const exec = getExecutor();
|
|
206
337
|
const viewer = configuredIosSimulatorViewer(simulatorApp);
|
|
207
338
|
const started = Date.now();
|
|
@@ -280,7 +411,7 @@ async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = B
|
|
|
280
411
|
} finally {
|
|
281
412
|
clearInterval(monitor);
|
|
282
413
|
}
|
|
283
|
-
viewer.open(udid);
|
|
414
|
+
if (openViewer) viewer.open(udid);
|
|
284
415
|
}
|
|
285
416
|
function shutdownIosSim(udid) {
|
|
286
417
|
getExecutor().runQuiet(`xcrun simctl shutdown ${udid}`, SIMCTL_OPTIONS);
|
|
@@ -432,6 +563,66 @@ function resetIosKeychain(udid) {
|
|
|
432
563
|
"reset"
|
|
433
564
|
], SIMCTL_OPTIONS);
|
|
434
565
|
}
|
|
566
|
+
const CLEARED_CONTAINER_DIRS = [
|
|
567
|
+
"Documents",
|
|
568
|
+
"Library",
|
|
569
|
+
"tmp",
|
|
570
|
+
"SystemData"
|
|
571
|
+
];
|
|
572
|
+
function clearIosAppData(udid, bundleId, { defaultsPlist = null } = {}) {
|
|
573
|
+
const exec = getExecutor();
|
|
574
|
+
if (defaultsPlist) exec.runFile("xcrun", [
|
|
575
|
+
"simctl",
|
|
576
|
+
"spawn",
|
|
577
|
+
udid,
|
|
578
|
+
"defaults",
|
|
579
|
+
"import",
|
|
580
|
+
bundleId,
|
|
581
|
+
"-"
|
|
582
|
+
], {
|
|
583
|
+
...SIMCTL_OPTIONS,
|
|
584
|
+
input: defaultsPlist
|
|
585
|
+
});
|
|
586
|
+
else try {
|
|
587
|
+
exec.runFile("xcrun", [
|
|
588
|
+
"simctl",
|
|
589
|
+
"spawn",
|
|
590
|
+
udid,
|
|
591
|
+
"defaults",
|
|
592
|
+
"delete",
|
|
593
|
+
bundleId
|
|
594
|
+
], SIMCTL_OPTIONS);
|
|
595
|
+
} catch (error) {
|
|
596
|
+
if (!/Domain .* not found/.test(String(error?.message))) throw error;
|
|
597
|
+
}
|
|
598
|
+
const output = exec.runFile("xcrun", [
|
|
599
|
+
"simctl",
|
|
600
|
+
"get_app_container",
|
|
601
|
+
udid,
|
|
602
|
+
bundleId,
|
|
603
|
+
"data"
|
|
604
|
+
], SIMCTL_OPTIONS);
|
|
605
|
+
const container = parseAppContainerPath(output);
|
|
606
|
+
if (!container) throw new Error(`simctl get_app_container returned no data container for ${bundleId}: ${JSON.stringify(output)}`);
|
|
607
|
+
for (const name of CLEARED_CONTAINER_DIRS) {
|
|
608
|
+
const dir = join(container, name);
|
|
609
|
+
let stat;
|
|
610
|
+
try {
|
|
611
|
+
stat = lstatSync(dir);
|
|
612
|
+
} catch (error) {
|
|
613
|
+
if (error?.code === "ENOENT") continue;
|
|
614
|
+
throw error;
|
|
615
|
+
}
|
|
616
|
+
if (!stat.isDirectory()) {
|
|
617
|
+
rmSync(dir, { force: true });
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
for (const child of readdirSync(dir)) rmSync(join(dir, child), {
|
|
621
|
+
recursive: true,
|
|
622
|
+
force: true
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
435
626
|
function uninstallIosApp(udid, bundleId) {
|
|
436
627
|
getExecutor().runFile("xcrun", [
|
|
437
628
|
"simctl",
|
|
@@ -526,4 +717,4 @@ function listIosRuntimes() {
|
|
|
526
717
|
}));
|
|
527
718
|
}
|
|
528
719
|
//#endregion
|
|
529
|
-
export {
|
|
720
|
+
export { hostMemoryPressureAdvice as A, resolveIosCreation as C, uninstallIosApp as D, shutdownIosSim as E, deviceHoldsApk as M, deviceHoldsBundle as N, configuredIosSimulatorViewer as O, resetIosPrivacy as S, sanitizeDeviceLabel as T, parseRuntimeVersion as _, deleteIosSim as a, renameIosSim as b, iosRuntimeMatches as c, listAllIosSimsAsync as d, listIosDeviceTypes as f, parkedSimName as g, ownedSimName as h, createOwnedIosSim as i, readHostMemoryPressure as j, parseIosSimulatorApp as k, iosSimulatorFailureAdvice as l, listUserApps as m, bootIosSim as n, deleteParkedIosSim as o, listIosRuntimes as p, clearIosAppData as r, eraseIosSim as s, IOS_BOOT_TIMEOUT_MS as t, listAllIosSims as u, parseSimctlList as v, resolveOwnedIosSim as w, resetIosKeychain as x, pickDefaultIosCreation as y };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
//#region src/collector/ios.ts
|
|
3
|
+
const MESSAGE_TYPE_LEVEL = {
|
|
4
|
+
Debug: "debug",
|
|
5
|
+
Info: "info",
|
|
6
|
+
Default: "info",
|
|
7
|
+
Error: "error",
|
|
8
|
+
Fault: "fatal"
|
|
9
|
+
};
|
|
10
|
+
function levelFromMessageType(messageType) {
|
|
11
|
+
return MESSAGE_TYPE_LEVEL[messageType] ?? "info";
|
|
12
|
+
}
|
|
13
|
+
const NOISE_RULES = [
|
|
14
|
+
{
|
|
15
|
+
id: "network",
|
|
16
|
+
subsystem: "com.apple.network"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "network-default-subsystem",
|
|
20
|
+
messagePrefix: [
|
|
21
|
+
"nw_socket",
|
|
22
|
+
"nw_connection",
|
|
23
|
+
"nw_protocol",
|
|
24
|
+
"nw_endpoint",
|
|
25
|
+
"nw_path",
|
|
26
|
+
"nw_resolver",
|
|
27
|
+
"nw_flow",
|
|
28
|
+
"nw_read_request",
|
|
29
|
+
"nw_write_request",
|
|
30
|
+
"tcp_input"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "sectrust",
|
|
35
|
+
subsystem: "com.apple.securityd"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "sectrust-default-subsystem",
|
|
39
|
+
messagePrefix: [
|
|
40
|
+
"SecTrust",
|
|
41
|
+
"SecOSStatus",
|
|
42
|
+
"TrustResultType"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "webkit",
|
|
47
|
+
subsystem: "com.apple.WebKit"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "webkit-default-subsystem",
|
|
51
|
+
messagePrefix: [
|
|
52
|
+
"WebPrivacy",
|
|
53
|
+
"GPUProcessProxy",
|
|
54
|
+
"WebProcessProxy"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "audio-factory",
|
|
59
|
+
messageIncludes: ["AddInstanceForFactory"]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "coreui",
|
|
63
|
+
subsystem: "com.apple.coreui"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "coreui-default-subsystem",
|
|
67
|
+
messagePrefix: [
|
|
68
|
+
"CUICatalog:",
|
|
69
|
+
"CoreUI:",
|
|
70
|
+
"CoreThemeDefinition"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "uiscene-deprecation",
|
|
75
|
+
messageIncludes: [
|
|
76
|
+
"UIScene lifecycle will soon be required",
|
|
77
|
+
"`UIScene` lifecycle will soon be required",
|
|
78
|
+
"must migrate to UIScene",
|
|
79
|
+
"migrate to UIScene lifecycle"
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "react-native-focus-cache",
|
|
84
|
+
exactSubsystem: "com.apple.UIKit",
|
|
85
|
+
category: "UIFocus",
|
|
86
|
+
messageEquals: "RCTScrollViewComponentView implements focusItemsInRect: - caching for linear focus movement is limited as long as this view is on screen."
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "cfnetwork-performance-diagnostic",
|
|
90
|
+
exactSubsystem: "com.apple.runtime-issues",
|
|
91
|
+
category: "CFNetwork Performance Diagnostic",
|
|
92
|
+
level: "warn"
|
|
93
|
+
}
|
|
94
|
+
];
|
|
95
|
+
function ruleMatches(rule, { subsystem, category, message }) {
|
|
96
|
+
if (rule.subsystem && subsystem !== rule.subsystem && !subsystem.startsWith(`${rule.subsystem}.`)) return false;
|
|
97
|
+
if (rule.exactSubsystem && subsystem !== rule.exactSubsystem) return false;
|
|
98
|
+
if (rule.category && category !== rule.category) return false;
|
|
99
|
+
if (rule.messageEquals && message !== rule.messageEquals) return false;
|
|
100
|
+
if (rule.messagePrefix && !rule.messagePrefix.some((p) => message.startsWith(p))) return false;
|
|
101
|
+
if (rule.messageIncludes && !rule.messageIncludes.some((p) => message.includes(p))) return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function matchingNoiseRule(event) {
|
|
105
|
+
const subsystem = typeof event?.subsystem === "string" ? event.subsystem : "";
|
|
106
|
+
const category = typeof event?.category === "string" ? event.category : "";
|
|
107
|
+
const message = typeof event?.eventMessage === "string" ? event.eventMessage : "";
|
|
108
|
+
return NOISE_RULES.find((rule) => ruleMatches(rule, {
|
|
109
|
+
subsystem,
|
|
110
|
+
category,
|
|
111
|
+
message
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
function levelForEvent(event) {
|
|
115
|
+
const level = levelFromMessageType(event?.messageType);
|
|
116
|
+
if (level !== "error" && level !== "fatal") return level;
|
|
117
|
+
const rule = matchingNoiseRule(event);
|
|
118
|
+
return rule ? rule.level ?? "info" : level;
|
|
119
|
+
}
|
|
120
|
+
function procFromImagePath(path) {
|
|
121
|
+
if (typeof path !== "string" || !path) return null;
|
|
122
|
+
const parts = path.split("/");
|
|
123
|
+
return parts[parts.length - 1] || null;
|
|
124
|
+
}
|
|
125
|
+
function tsFromEvent(event, now = Date.now) {
|
|
126
|
+
const parsed = Date.parse(event?.timestamp);
|
|
127
|
+
return Number.isFinite(parsed) ? parsed : now();
|
|
128
|
+
}
|
|
129
|
+
function recordFromLogEvent(event, { now = Date.now } = {}) {
|
|
130
|
+
if (!event || typeof event !== "object") return null;
|
|
131
|
+
const eventType = event.eventType;
|
|
132
|
+
if (eventType && eventType !== "logEvent") return null;
|
|
133
|
+
const msg = typeof event.eventMessage === "string" ? event.eventMessage : "";
|
|
134
|
+
if (!msg.trim()) return null;
|
|
135
|
+
const record = {
|
|
136
|
+
ts: tsFromEvent(event, now),
|
|
137
|
+
src: "device",
|
|
138
|
+
level: levelForEvent(event),
|
|
139
|
+
msg
|
|
140
|
+
};
|
|
141
|
+
const proc = procFromImagePath(event.processImagePath);
|
|
142
|
+
if (proc) record.proc = proc;
|
|
143
|
+
if (typeof event.subsystem === "string") record.subsystem = event.subsystem;
|
|
144
|
+
if (typeof event.category === "string") record.category = event.category;
|
|
145
|
+
return record;
|
|
146
|
+
}
|
|
147
|
+
function parseLogStreamLine(line, { now = Date.now } = {}) {
|
|
148
|
+
if (typeof line !== "string") return null;
|
|
149
|
+
const trimmed = line.trim();
|
|
150
|
+
if (!trimmed || trimmed[0] !== "{") return null;
|
|
151
|
+
let event;
|
|
152
|
+
try {
|
|
153
|
+
event = JSON.parse(trimmed);
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return recordFromLogEvent(event, { now });
|
|
158
|
+
}
|
|
159
|
+
function logStreamArgs(udid, appName, executableName) {
|
|
160
|
+
return [
|
|
161
|
+
"simctl",
|
|
162
|
+
"spawn",
|
|
163
|
+
udid,
|
|
164
|
+
"log",
|
|
165
|
+
"stream",
|
|
166
|
+
"--style",
|
|
167
|
+
"ndjson",
|
|
168
|
+
"--predicate",
|
|
169
|
+
`processImagePath ENDSWITH "/${appName}.app/${executableName && executableName.trim() !== "" ? executableName.trim() : appName}"`,
|
|
170
|
+
"--level",
|
|
171
|
+
"info"
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
function appNameFromBundleId(bundleId) {
|
|
175
|
+
const parts = String(bundleId || "").split(".");
|
|
176
|
+
return parts[parts.length - 1] || String(bundleId || "");
|
|
177
|
+
}
|
|
178
|
+
function startIosLogStream({ udid, appName, executableName = null, spawnFn = null }) {
|
|
179
|
+
return (spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts)))("xcrun", logStreamArgs(udid, appName, executableName), {
|
|
180
|
+
stdio: [
|
|
181
|
+
"ignore",
|
|
182
|
+
"pipe",
|
|
183
|
+
"pipe"
|
|
184
|
+
],
|
|
185
|
+
detached: false
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { parseLogStreamLine as n, startIosLogStream as r, appNameFromBundleId as t };
|