stim 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -155
- package/dist/{android-DWssqHQ8.mjs → android-787HhP5w.mjs} +168 -39
- package/dist/{android-BRgBYzU0.mjs → android-DBkeHwpm.mjs} +250 -200
- package/dist/{android-DeYdjjBP.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-CITmIeWY.mjs} +22 -14
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/app-install-CrJ6t_bv.mjs +819 -0
- package/dist/budget-BP4jZZL4.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Pubfp8wV.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +7 -1
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-D5z2_bcF.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-BEq0Qw_a.mjs} +134 -121
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-DP4eWqea.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-92U593KT.mjs} +1090 -660
- package/dist/{device-RdujjHLB.mjs → device-DhTZe7L4.mjs} +13 -20
- package/dist/{build-lock-CgtsB6TV.mjs → device-lease-CbEaIk7b.mjs} +481 -27
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-Di8Q-9Ro.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-Dy1jGj3U.mjs} +645 -119
- package/dist/{doctor-BMt156qe.mjs → doctor-B-inAJmt.mjs} +137 -113
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-xxWKNO3-.mjs} +22 -17
- package/dist/exec-DK8KaVHK.mjs +133 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-ChPFZMRC.mjs} +836 -813
- package/dist/{guide-BTAlD1_y.mjs → guide-DwmaD_Wa.mjs} +953 -209
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle-DpRLp5lj.mjs +157 -0
- package/dist/{build-slots-C-oAHRT1.mjs → in-use-CjUluqIX.mjs} +102 -8
- package/dist/{ios-BcCiI4TS.mjs → ios-B2Fpqvlb.mjs} +60 -71
- package/dist/{ios-BP04pY5f.mjs → ios-Dd-hYJBh.mjs} +241 -234
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-BiOsSVzd.mjs} +3 -2
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-CtRdEVjx.mjs} +149 -52
- package/dist/launch-verify-CQS_Kg-C.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-MARIy6m9.mjs} +20 -15
- package/dist/metro-BWLOJ_Wr.mjs +409 -0
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-CDY9IkVC.mjs} +23 -43
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/{teardown-BJqEzPo_.mjs → ownership-DZjdx8Gq.mjs} +664 -612
- package/dist/{ports-BIbJaKNW.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-BXZzOABt.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-DoETJ3rl.mjs} +11 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DVbb7kXH.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-BvOCeakp.mjs} +8 -7
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-BXXorVM2.mjs → settings-DOugPlPz.mjs} +59 -159
- package/dist/settings-EWYNwe72.mjs +378 -0
- package/dist/settings.schema.json +1064 -0
- package/dist/simslim-Ca3487H6.mjs +436 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
- package/dist/spawn-claims-CUleC2cM.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-F9gv5dcC.mjs} +159 -114
- package/dist/start-VoFsPSes.mjs +2 -0
- package/dist/{state-DZobzxLW.mjs → state-WGdIbi_d.mjs} +5 -3
- package/dist/{stats-BYcZ6n1h.mjs → stats-BAgJaLA4.mjs} +66 -5
- package/dist/{stats-CLg5RuDS.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/status-DLCD-o3s.mjs +764 -0
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{guide-status-Craq9z0t.mjs → stim-installations-CINXy_su.mjs} +3 -122
- package/dist/{stop-C8JW6kKp.mjs → stop-Dj4pfmyv.mjs} +111 -31
- package/dist/{stop-B1kOpYei.mjs → stop-ZvOeTmKb.mjs} +2 -2
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +228 -42
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-BXA96myD.mjs} +14 -9
- package/dist/workspaces-BTUyFfkv.mjs +1003 -0
- package/dist/worktree-4aZg2NnI.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-BMS7GeqB.mjs} +523 -61
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-BlizKDpZ.mjs} +200 -54
- package/dist/{xcode-B6YaWeg0.mjs → xcode-B2tBkf0m.mjs} +66 -57
- package/package.json +6 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/device-lease-Ffz_M5t0.mjs +0 -359
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/logs-query-BGL-Pl12.mjs +0 -290
- package/dist/metro-C7bcJ0uo.mjs +0 -233
- package/dist/ownership-wolE-0Do.mjs +0 -470
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/workspace-state-BT5E3SA2.mjs +0 -146
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
1
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
2
2
|
//#region src/collector/ios-device.ts
|
|
3
3
|
const CONSOLE_ENV = { OS_ACTIVITY_DT_MODE: "enable" };
|
|
4
4
|
const DEV_MENU_LAUNCH_ARGS = [
|
|
@@ -13,6 +13,7 @@ const FATAL_MARKERS = [
|
|
|
13
13
|
/^\*\*\* Assertion failure in/,
|
|
14
14
|
/^(?:\S+:\d+: )?Fatal error: /
|
|
15
15
|
];
|
|
16
|
+
const TOOL_ERROR_PREFIX = "ERROR: ";
|
|
16
17
|
const MIRROR_LINE = /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+[+-]\d{4}) (.+?)\[(\d+):(\d+)\] ?(?:\[([^\]\s]+)\] )?([\s\S]*)$/;
|
|
17
18
|
function deviceConsoleLevel(message) {
|
|
18
19
|
const text = typeof message === "string" ? message : "";
|
|
@@ -78,4 +79,4 @@ function startIosDeviceConsole({ udid, bundleId, payloadUrl = null, spawnFn = nu
|
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
81
|
//#endregion
|
|
81
|
-
export { startIosDeviceConsole as i,
|
|
82
|
+
export { startIosDeviceConsole as a, parseDeviceConsoleLine as i, TOOL_ERROR_PREFIX as n, deviceConsoleLevel as r, DEV_MENU_LAUNCH_ARGS as t };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
2
|
+
import { n as TOOL_ERROR_PREFIX } from "./ios-device-BiOsSVzd.mjs";
|
|
3
|
+
import { i as INSTALL_ERROR } from "./app-install-CrJ6t_bv.mjs";
|
|
3
4
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { tmpdir } from "node:os";
|
|
@@ -34,7 +35,10 @@ function parseDevicectlDevices(payload) {
|
|
|
34
35
|
bootState: text(properties.bootState),
|
|
35
36
|
developerModeStatus: text(properties.developerModeStatus),
|
|
36
37
|
pairingState: text(connection.pairingState),
|
|
37
|
-
transportType: text(connection.transportType)
|
|
38
|
+
transportType: text(connection.transportType),
|
|
39
|
+
platform: text(hardware.platform),
|
|
40
|
+
reality: text(hardware.reality),
|
|
41
|
+
tunnelState: text(connection.tunnelState)
|
|
38
42
|
});
|
|
39
43
|
}
|
|
40
44
|
return out;
|
|
@@ -63,18 +67,47 @@ function listIosDevices({ exec = null } = {}) {
|
|
|
63
67
|
}
|
|
64
68
|
const DEVELOPER_MODE_REMEDY = "Turn on Settings > Privacy & Security > Developer Mode on the phone, restart it, then reconnect.";
|
|
65
69
|
const PAIRING_REMEDY = "Unlock the phone, tap Trust on the pairing prompt, then reconnect the cable.";
|
|
66
|
-
const
|
|
70
|
+
const NOT_A_PHONE_REMEDY = "Name a physical iPhone or iPad from `xcrun devicectl list devices`, or run `stim ios` without --device to use this workspace's simulator.";
|
|
71
|
+
const UNREACHABLE_REMEDY = "Connect the phone with a cable, or unlock it on the same Wi-Fi network as this Mac, then check `xcrun devicectl list devices`.";
|
|
67
72
|
const WIRED_TRANSPORTS = /* @__PURE__ */ new Set(["wired", "usb"]);
|
|
73
|
+
const WIRELESS_TRANSPORT = "localnetwork";
|
|
74
|
+
function isIosHardware(device) {
|
|
75
|
+
return (device.platform == null || device.platform.toLowerCase() === "ios") && (device.reality == null || device.reality.toLowerCase() === "physical");
|
|
76
|
+
}
|
|
77
|
+
function isReachable(device) {
|
|
78
|
+
return device.tunnelState?.toLowerCase() !== "unavailable";
|
|
79
|
+
}
|
|
68
80
|
function isWired(device) {
|
|
69
81
|
return device.transportType === null || WIRED_TRANSPORTS.has(device.transportType.toLowerCase());
|
|
70
82
|
}
|
|
83
|
+
function isWirelessIosDevice(device) {
|
|
84
|
+
return device.transportType?.toLowerCase() === WIRELESS_TRANSPORT;
|
|
85
|
+
}
|
|
86
|
+
function isPhysical(device) {
|
|
87
|
+
return isIosHardware(device) && isReachable(device) && (isWired(device) || isWirelessIosDevice(device));
|
|
88
|
+
}
|
|
89
|
+
function notUsableRefusal(device) {
|
|
90
|
+
if (!isIosHardware(device)) return {
|
|
91
|
+
error: `${describe(device)} is a ${[device.reality, device.platform].filter(Boolean).join(" ")} device, and \`ios --device\` installs only on a physical iPhone or iPad.`,
|
|
92
|
+
remedy: NOT_A_PHONE_REMEDY
|
|
93
|
+
};
|
|
94
|
+
if (!isReachable(device)) return {
|
|
95
|
+
error: `${describe(device)} is paired, but devicectl reports it unavailable: it cannot reach the phone right now.`,
|
|
96
|
+
remedy: UNREACHABLE_REMEDY
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
error: `${describe(device)} is reached over ${device.transportType}, and Stim installs on a phone only over a cable or Wi-Fi.`,
|
|
100
|
+
remedy: NOT_A_PHONE_REMEDY
|
|
101
|
+
};
|
|
102
|
+
}
|
|
71
103
|
function describe(device) {
|
|
72
104
|
return `${device.udid} (${device.name})`;
|
|
73
105
|
}
|
|
74
|
-
function
|
|
106
|
+
function selected(device) {
|
|
75
107
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
108
|
+
udid: device.udid,
|
|
109
|
+
name: device.name,
|
|
110
|
+
...isWirelessIosDevice(device) ? { wireless: true } : {}
|
|
78
111
|
};
|
|
79
112
|
}
|
|
80
113
|
function unhealthy(device) {
|
|
@@ -89,13 +122,13 @@ function unhealthy(device) {
|
|
|
89
122
|
return null;
|
|
90
123
|
}
|
|
91
124
|
function iosPoolCandidates(devices) {
|
|
92
|
-
return (Array.isArray(devices) ? devices : []).filter((device) =>
|
|
125
|
+
return (Array.isArray(devices) ? devices : []).filter((device) => isPhysical(device) && unhealthy(device) === null);
|
|
93
126
|
}
|
|
94
127
|
function iosPoolNoCandidatesRefusal(devices) {
|
|
95
128
|
const listed = Array.isArray(devices) ? devices : [];
|
|
96
|
-
const
|
|
97
|
-
const problems =
|
|
98
|
-
if (
|
|
129
|
+
const physical = listed.filter(isPhysical);
|
|
130
|
+
const problems = physical.map((device) => unhealthy(device));
|
|
131
|
+
if (physical.length > 0 && problems.every((problem) => problem !== null)) {
|
|
99
132
|
const reasons = problems;
|
|
100
133
|
return {
|
|
101
134
|
error: reasons.map((reason) => reason.error).join(" "),
|
|
@@ -104,42 +137,52 @@ function iosPoolNoCandidatesRefusal(devices) {
|
|
|
104
137
|
}
|
|
105
138
|
return resolveIosPhysicalDevice(null, listed);
|
|
106
139
|
}
|
|
140
|
+
function pickOne(devices) {
|
|
141
|
+
if (devices.length === 1) return unhealthy(devices[0]) ?? selected(devices[0]);
|
|
142
|
+
if (devices.length > 1) return {
|
|
143
|
+
error: `Several devices are connected: ${devices.map(describe).join(", ")}.`,
|
|
144
|
+
remedy: "Name the one to build for with `stim ios --device <udid>`."
|
|
145
|
+
};
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
107
148
|
function resolveIosPhysicalDevice(requested, devices) {
|
|
108
149
|
const listed = Array.isArray(devices) ? devices : [];
|
|
109
|
-
const
|
|
110
|
-
const wireless = listed.filter((d) => !isWired(d));
|
|
150
|
+
const physical = listed.filter(isPhysical);
|
|
111
151
|
if (requested) {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const overNetwork = wireless.find((d) => d.udid.toLowerCase() === requested.toLowerCase());
|
|
118
|
-
if (overNetwork) return wirelessRefusal(overNetwork);
|
|
152
|
+
const same = (d) => d.udid.toLowerCase() === requested.toLowerCase();
|
|
153
|
+
const match = physical.find(same);
|
|
154
|
+
if (match) return unhealthy(match) ?? selected(match);
|
|
155
|
+
const other = listed.find(same);
|
|
156
|
+
if (other) return notUsableRefusal(other);
|
|
119
157
|
return {
|
|
120
|
-
error:
|
|
158
|
+
error: physical.length ? `${requested} is not connected. devicectl reports these devices: ${physical.map(describe).join(", ")}.` : `${requested} is not connected, and devicectl reports no device over a cable or Wi-Fi at all.`,
|
|
121
159
|
remedy: "Check the cable and `xcrun devicectl list devices`, then retry with a UDID it lists."
|
|
122
160
|
};
|
|
123
161
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return unhealthy(only) ?? {
|
|
127
|
-
udid: only.udid,
|
|
128
|
-
name: only.name
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
if (cabled.length > 1) return {
|
|
132
|
-
error: `Several devices are connected: ${cabled.map(describe).join(", ")}.`,
|
|
133
|
-
remedy: "Name the one to build for with `stim ios --device <udid>`."
|
|
134
|
-
};
|
|
135
|
-
const onlyWireless = wireless[0];
|
|
136
|
-
if (onlyWireless) return wirelessRefusal(onlyWireless);
|
|
162
|
+
const chosen = pickOne(physical);
|
|
163
|
+
if (chosen) return chosen;
|
|
137
164
|
return {
|
|
138
165
|
error: "No physical iOS device is connected.",
|
|
139
166
|
remedy: "Plug the phone in, unlock it, tap Trust, turn on Settings > Privacy & Security > Developer Mode, then check `xcrun devicectl list devices`."
|
|
140
167
|
};
|
|
141
168
|
}
|
|
142
169
|
const DEVICECTL_INSTALL_TIMEOUT_MS = 3e5;
|
|
170
|
+
const WIRELESS_INSTALL_TIMEOUT_MS = 9e5;
|
|
171
|
+
const LAUNCH_PROBE_TIMEOUT_MS = 45e3;
|
|
172
|
+
const WIRELESS_LAUNCH_PROBE_TIMEOUT_MS = 12e4;
|
|
173
|
+
const WIRELESS_ERROR = "STIM_DEVICE_WIRELESS_FAILED";
|
|
174
|
+
function iosDeviceBounds(wireless) {
|
|
175
|
+
return wireless ? {
|
|
176
|
+
installMs: WIRELESS_INSTALL_TIMEOUT_MS,
|
|
177
|
+
launchMs: WIRELESS_LAUNCH_PROBE_TIMEOUT_MS
|
|
178
|
+
} : {
|
|
179
|
+
installMs: DEVICECTL_INSTALL_TIMEOUT_MS,
|
|
180
|
+
launchMs: LAUNCH_PROBE_TIMEOUT_MS
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const WIRELESS_REMEDY = "Connect the phone with a cable so devicectl uses it instead of Wi-Fi, keep the phone unlocked, then run the command again.";
|
|
184
|
+
const WIRELESS_DROP = /disconnected|not connected|connection (?:was )?(?:lost|interrupted|reset)|network connection was lost|timed out/i;
|
|
185
|
+
const WIRELESS_CONSOLE_DROP = /disconnected|connection (?:was )?(?:lost|interrupted|reset)|not connected|timed out/i;
|
|
143
186
|
const LOCKED_REMEDY = "Unlock the phone and keep it awake, then run the command again.";
|
|
144
187
|
function errorText(error) {
|
|
145
188
|
const withOutput = error;
|
|
@@ -170,8 +213,33 @@ function iosInstallRemedy(kind, { udid, bundleId }) {
|
|
|
170
213
|
default: return `Check that ${udid} is still connected and unlocked (\`xcrun devicectl list devices\`), and that the app was built for the iphoneos SDK.`;
|
|
171
214
|
}
|
|
172
215
|
}
|
|
173
|
-
function
|
|
216
|
+
function wirelessInstallFailure(error, { udid, appPath, wireless }) {
|
|
217
|
+
if (!wireless) return null;
|
|
218
|
+
const failure = errorText(error);
|
|
219
|
+
if (iosInstallFailureKind(failure) !== null) return null;
|
|
220
|
+
const timedOut = error?.code === "ETIMEDOUT";
|
|
221
|
+
if (!timedOut && !WIRELESS_DROP.test(failure)) return null;
|
|
222
|
+
const what = timedOut ? `did not finish within ${Math.round(WIRELESS_INSTALL_TIMEOUT_MS / 1e3)}s` : "lost the connection to the phone";
|
|
223
|
+
return {
|
|
224
|
+
failed: true,
|
|
225
|
+
code: WIRELESS_ERROR,
|
|
226
|
+
reason: `devicectl ${what} while installing ${appPath} on ${udid} over Wi-Fi (localNetwork): ${failure}`,
|
|
227
|
+
remedy: WIRELESS_REMEDY
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Installs with one bounded devicectl call. A signer conflict adds an uninstall and a
|
|
232
|
+
* second install, each with the same bound; `beforeStep` runs before each of those two
|
|
233
|
+
* so the caller can extend its device lease.
|
|
234
|
+
*/
|
|
235
|
+
function installIosDeviceApp({ udid, appPath, bundleId = null, wireless = false }, { exec = null, beforeStep = () => {} } = {}) {
|
|
174
236
|
const e = exec || getExecutor();
|
|
237
|
+
const timeoutMs = iosDeviceBounds(wireless).installMs;
|
|
238
|
+
const target = {
|
|
239
|
+
udid,
|
|
240
|
+
appPath,
|
|
241
|
+
wireless
|
|
242
|
+
};
|
|
175
243
|
const install = () => {
|
|
176
244
|
e.runFile("xcrun", [
|
|
177
245
|
"devicectl",
|
|
@@ -181,7 +249,7 @@ function installIosDeviceApp({ udid, appPath, bundleId = null }, { exec = null }
|
|
|
181
249
|
"--device",
|
|
182
250
|
udid,
|
|
183
251
|
appPath
|
|
184
|
-
], { timeoutMs
|
|
252
|
+
], { timeoutMs });
|
|
185
253
|
};
|
|
186
254
|
try {
|
|
187
255
|
install();
|
|
@@ -190,6 +258,8 @@ function installIosDeviceApp({ udid, appPath, bundleId = null }, { exec = null }
|
|
|
190
258
|
appPath
|
|
191
259
|
};
|
|
192
260
|
} catch (err) {
|
|
261
|
+
const dropped = wirelessInstallFailure(err, target);
|
|
262
|
+
if (dropped) return dropped;
|
|
193
263
|
const failure = errorText(err);
|
|
194
264
|
const kind = iosInstallFailureKind(failure);
|
|
195
265
|
if (kind !== "signer" || !bundleId) return {
|
|
@@ -202,6 +272,7 @@ function installIosDeviceApp({ udid, appPath, bundleId = null }, { exec = null }
|
|
|
202
272
|
})
|
|
203
273
|
};
|
|
204
274
|
try {
|
|
275
|
+
beforeStep();
|
|
205
276
|
e.runFile("xcrun", [
|
|
206
277
|
"devicectl",
|
|
207
278
|
"device",
|
|
@@ -210,26 +281,28 @@ function installIosDeviceApp({ udid, appPath, bundleId = null }, { exec = null }
|
|
|
210
281
|
"--device",
|
|
211
282
|
udid,
|
|
212
283
|
bundleId
|
|
213
|
-
], { timeoutMs
|
|
284
|
+
], { timeoutMs });
|
|
214
285
|
} catch (uninstallErr) {
|
|
215
|
-
|
|
286
|
+
const uninstallKind = iosInstallFailureKind(errorText(uninstallErr));
|
|
287
|
+
return wirelessInstallFailure(uninstallErr, target) ?? {
|
|
216
288
|
failed: true,
|
|
217
|
-
code:
|
|
289
|
+
code: "STIM_INSTALL_FAILED",
|
|
218
290
|
reason: `devicectl refused to install ${appPath} over the copy of ${bundleId} already on ${udid}, which a different team signed, and the uninstall failed too: ${errorText(uninstallErr)}`,
|
|
219
|
-
remedy: iosInstallRemedy("signer", {
|
|
291
|
+
remedy: iosInstallRemedy(uninstallKind ?? "signer", {
|
|
220
292
|
udid,
|
|
221
293
|
bundleId
|
|
222
294
|
})
|
|
223
295
|
};
|
|
224
296
|
}
|
|
225
297
|
try {
|
|
298
|
+
beforeStep();
|
|
226
299
|
install();
|
|
227
300
|
} catch (retryErr) {
|
|
228
|
-
return {
|
|
301
|
+
return wirelessInstallFailure(retryErr, target) ?? {
|
|
229
302
|
failed: true,
|
|
230
|
-
code:
|
|
303
|
+
code: "STIM_INSTALL_FAILED",
|
|
231
304
|
reason: `devicectl could not install ${appPath} on ${udid} even after uninstalling ${bundleId}: ${errorText(retryErr)}`,
|
|
232
|
-
remedy: iosInstallRemedy(
|
|
305
|
+
remedy: iosInstallRemedy(iosInstallFailureKind(errorText(retryErr)), {
|
|
233
306
|
udid,
|
|
234
307
|
bundleId
|
|
235
308
|
})
|
|
@@ -301,6 +374,8 @@ const LAUNCH_REFUSALS = [
|
|
|
301
374
|
["untrusted-developer", /FBSOpenApplicationErrorDomain error 3\b/],
|
|
302
375
|
["untrusted-developer", /denied by service delegate[^\n]*for reason: Security/],
|
|
303
376
|
["locked", /device is locked|is locked\b|passcode/i],
|
|
377
|
+
["locked", /BSErrorCodeDescription = Locked\b/],
|
|
378
|
+
["locked", /\bunlocked\b[^\n]*FBSOpenApplicationErrorDomain error 7\b/],
|
|
304
379
|
["not-installed", /(?:application|app)[^\n]*\b(?:is )?(?:unknown to FrontBoard|not installed)/i]
|
|
305
380
|
];
|
|
306
381
|
function iosLaunchRefusalKind(output) {
|
|
@@ -315,7 +390,6 @@ function iosLaunchRemedy(kind, { udid, bundleId }) {
|
|
|
315
390
|
default: return `Run \`xcrun devicectl device process launch --console --device ${udid} ${bundleId}\` to see what the phone reports.`;
|
|
316
391
|
}
|
|
317
392
|
}
|
|
318
|
-
const LAUNCH_PROBE_TIMEOUT_MS = 45e3;
|
|
319
393
|
const LAUNCH_PROBE_POLL_MS = 1e3;
|
|
320
394
|
const COLLECTOR_ENDED_EVENTS = /* @__PURE__ */ new Set(["collector_failed", "collector_stopped"]);
|
|
321
395
|
function launchEvidence(records) {
|
|
@@ -326,7 +400,12 @@ function launchEvidence(records) {
|
|
|
326
400
|
if (entry.event === "collector_started" || entry.event === "collector_empty") continue;
|
|
327
401
|
lines.push(msg);
|
|
328
402
|
}
|
|
329
|
-
return lines
|
|
403
|
+
return lines;
|
|
404
|
+
}
|
|
405
|
+
function devicectlErrorText(records) {
|
|
406
|
+
const own = records.filter((entry) => entry.proc === void 0 && typeof entry.msg === "string");
|
|
407
|
+
const start = own.findIndex((entry) => entry.msg.startsWith(TOOL_ERROR_PREFIX));
|
|
408
|
+
return start < 0 ? "" : own.slice(start).map((entry) => entry.msg).join("\n");
|
|
330
409
|
}
|
|
331
410
|
function collectorRecordsFor(records, collectorPid) {
|
|
332
411
|
if (!collectorPid) return [];
|
|
@@ -334,7 +413,7 @@ function collectorRecordsFor(records, collectorPid) {
|
|
|
334
413
|
const start = records.findIndex((entry) => entry.event === "collector_started" && typeof entry.msg === "string" && marker.test(entry.msg));
|
|
335
414
|
return start < 0 ? [] : records.slice(start);
|
|
336
415
|
}
|
|
337
|
-
async function awaitIosDeviceLaunch({ udid, bundleId, appName, collectorPid = null, readRecords, probe, timeoutMs =
|
|
416
|
+
async function awaitIosDeviceLaunch({ udid, bundleId, appName, collectorPid = null, readRecords, probe, wireless = false, timeoutMs = iosDeviceBounds(wireless).launchMs, pollMs = LAUNCH_PROBE_POLL_MS, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) }) {
|
|
338
417
|
const probeProcess = probe ?? (() => iosDeviceProcess({
|
|
339
418
|
udid,
|
|
340
419
|
appName
|
|
@@ -346,8 +425,16 @@ async function awaitIosDeviceLaunch({ udid, bundleId, appName, collectorPid = nu
|
|
|
346
425
|
const pid = probeProcess();
|
|
347
426
|
if (typeof pid === "number") return { pid };
|
|
348
427
|
if (ended) {
|
|
349
|
-
const
|
|
350
|
-
const
|
|
428
|
+
const evidence = launchEvidence(records);
|
|
429
|
+
const lines = evidence.slice(-6);
|
|
430
|
+
const kind = iosLaunchRefusalKind(evidence.join("\n"));
|
|
431
|
+
if (wireless && kind === null && WIRELESS_CONSOLE_DROP.test(devicectlErrorText(records))) return {
|
|
432
|
+
failed: true,
|
|
433
|
+
code: WIRELESS_ERROR,
|
|
434
|
+
reason: `devicectl lost the Wi-Fi (localNetwork) connection to ${udid} while launching ${bundleId}.`,
|
|
435
|
+
remedy: WIRELESS_REMEDY,
|
|
436
|
+
lines
|
|
437
|
+
};
|
|
351
438
|
return {
|
|
352
439
|
failed: true,
|
|
353
440
|
reason: `devicectl could not keep ${bundleId} running on ${udid}: the console ended before the app appeared in the device's process list.`,
|
|
@@ -359,11 +446,21 @@ async function awaitIosDeviceLaunch({ udid, bundleId, appName, collectorPid = nu
|
|
|
359
446
|
};
|
|
360
447
|
}
|
|
361
448
|
if (now() >= deadline) {
|
|
362
|
-
const
|
|
449
|
+
const evidence = launchEvidence(records);
|
|
450
|
+
const lines = evidence.slice(-6);
|
|
451
|
+
const kind = iosLaunchRefusalKind(evidence.join("\n"));
|
|
452
|
+
const reason = `${bundleId} did not appear in ${udid}'s process list within ${Math.round(timeoutMs / 1e3)}s of the launch`;
|
|
453
|
+
if (wireless && kind === null) return {
|
|
454
|
+
failed: true,
|
|
455
|
+
code: WIRELESS_ERROR,
|
|
456
|
+
reason: `${reason} over Wi-Fi (localNetwork).`,
|
|
457
|
+
remedy: WIRELESS_REMEDY,
|
|
458
|
+
lines
|
|
459
|
+
};
|
|
363
460
|
return {
|
|
364
461
|
failed: true,
|
|
365
|
-
reason: `${
|
|
366
|
-
remedy: iosLaunchRemedy(
|
|
462
|
+
reason: `${reason}.`,
|
|
463
|
+
remedy: iosLaunchRemedy(kind, {
|
|
367
464
|
udid,
|
|
368
465
|
bundleId
|
|
369
466
|
}),
|
|
@@ -410,4 +507,4 @@ function localNetworkPending(records, { since = 0, pid = null, lanOrigin }) {
|
|
|
410
507
|
return false;
|
|
411
508
|
}
|
|
412
509
|
//#endregion
|
|
413
|
-
export {
|
|
510
|
+
export { iosPoolCandidates as a, listIosDevices as c, verifyIosDeviceReleaseLaunch as d, iosDeviceProcess as i, localNetworkPending as l, installIosDeviceApp as n, iosPoolNoCandidatesRefusal as o, iosDeviceBounds as r, isWirelessIosDevice as s, awaitIosDeviceLaunch as t, resolveIosPhysicalDevice as u };
|