stim 1.18.0 → 1.20.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 +21 -4
- package/dist/{activity-BxnkDZDi.mjs → activity-BrGh9EAI.mjs} +3 -3
- package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
- package/dist/android-0vv-OruW.mjs +6 -0
- package/dist/android-Brx6EKvJ.mjs +1258 -0
- package/dist/{android-DC3ZLuw0.mjs → android-BsYNR81W.mjs} +103 -45
- package/dist/{android-CBwCNicO.mjs → android-CK3fpEyZ.mjs} +2 -2
- package/dist/{android-cas-BBFyr9CA.mjs → android-cas-DCAuXryb.mjs} +9 -5
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api-run.mjs +159 -8
- package/dist/{api-D0VtFhqk.mjs → api-zuX3ynYN.mjs} +9 -7
- package/dist/api.d.mts +104 -4
- package/dist/api.mjs +1 -1
- package/dist/{app-install-D-PUENug.mjs → app-install-0LgaQRT7.mjs} +39 -18
- package/dist/artifact-CnC0mfov.mjs +807 -0
- package/dist/artifact-DClXJNWx.mjs +772 -0
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
- package/dist/{web-DTU0uiWj.mjs → browser-web-CzBmhmgs.mjs} +136 -174
- package/dist/{budget-DIhL2BKx.mjs → budget-BONq9vXY.mjs} +3096 -3244
- package/dist/build-BixRI6sB.mjs +462 -0
- package/dist/build-plan-CP0tckNU.mjs +553 -0
- package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/ccache-CjHQ5F8g.mjs +142 -0
- package/dist/{chrome-DJnmnS5q.mjs → chrome-Dp2lMLBe.mjs} +1 -1
- package/dist/{cli-DNJMwADx.mjs → cli-B2R8wH1F.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-DzhapoMB.mjs → client-BLy1Pw2V.mjs} +172 -165
- package/dist/collector-run.d.mts +10 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-CBtzyIgF.mjs → command-output-BjPN99ZB.mjs} +2 -2
- package/dist/{config-CgYMahz7.mjs → config-D0LhTY3S.mjs} +13 -13
- package/dist/{created-devices-DKbeWsiK.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
- package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
- package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
- package/dist/{dev-client-CLnIH02x.mjs → dev-client-ClATaJoH.mjs} +2 -2
- package/dist/{device-D7oCHGWi.mjs → device-B7lsC0K1.mjs} +8 -8
- package/dist/device-DVCwAFlX.mjs +727 -0
- package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-Ca_ke1LE.mjs} +25 -15
- package/dist/device-host-worker.mjs +38 -18
- package/dist/{device-ios-6MewKKnc.mjs → device-ios-CRUqPxKw.mjs} +12 -11
- package/dist/{device-lease-Co-EwifR.mjs → device-lease-DHOBXGgS.mjs} +135 -22
- package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
- package/dist/{device-pool-F5WvRPtD.mjs → device-pool-L2-5GxMy.mjs} +3 -3
- package/dist/{device-remote-tHbd1fKy.mjs → device-remote-Bmg42063.mjs} +17 -69
- package/dist/doctor-C2MSuMMg.mjs +515 -0
- package/dist/{doctor-B9ckYUoU.mjs → doctor-DPAqhVCK.mjs} +334 -721
- package/dist/doctor-watchman-CB4NnVZm.mjs +260 -0
- package/dist/{simslim-EHBQ2R4G.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
- package/dist/{stim-installations-aR_WsNOA.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
- package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
- package/dist/errors-DzkMYh8Q.mjs +205 -0
- package/dist/{exec-DWhCZDGm.mjs → exec-B81Qodjn.mjs} +69 -15
- package/dist/{gc-Dh6mXOKC.mjs → gc-PWp34zGb.mjs} +23 -22
- package/dist/{gradle-C6GKnunQ.mjs → gradle-C2OEKCCI.mjs} +50 -125
- package/dist/{guide-tm6igAaa.mjs → guide-Dai9lphv.mjs} +862 -538
- package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
- package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-Io01s5By.mjs} +9 -3
- package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
- package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
- package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
- package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-BdAQi21M.mjs} +23 -16
- package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
- package/dist/ios-BZ9dg2Fr.mjs +9 -0
- package/dist/{ios-B3SbOWdw.mjs → ios-CXLIUxXJ.mjs} +180 -24
- package/dist/ios-CZuv6gRv.mjs +1112 -0
- package/dist/{ios-Bvbf0SGY.mjs → ios-VGvNdsv2.mjs} +1 -1
- package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-B1B14xND.mjs} +1 -1
- package/dist/{ios-device-vOaByMhw.mjs → ios-device-BreZOpM0.mjs} +3 -3
- package/dist/ios-project-B9drt_aY.mjs +197 -0
- package/dist/{ios-state-B2pES6Vs.mjs → ios-state-CjrL2qv-.mjs} +1 -1
- package/dist/js-swap-C8icNYIY.mjs +432 -0
- package/dist/launch-DxH0THLP.mjs +745 -0
- package/dist/launch-YrbqaIFj.mjs +1530 -0
- package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
- package/dist/{logs-1Ylc1Ri6.mjs → logs-DHaRNfg7.mjs} +11 -11
- package/dist/macos-C0iljhsN.mjs +2 -0
- package/dist/{macos-DF6C7wUU.mjs → macos-V_3Ui7g4.mjs} +125 -155
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +13 -10
- package/dist/{metro-Dh8T4Ytd.mjs → metro-D_j9sN-B.mjs} +209 -43
- package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
- package/dist/miss-reason-BPAzZS0r.mjs +238 -0
- package/dist/{named-ports-BFIz1Shz.mjs → named-ports-C2lvoPsb.mjs} +12 -5
- package/dist/native-android-lHzaew7r.mjs +226 -0
- package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
- package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
- package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
- package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
- package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
- package/dist/offload-worker.d.mts +12 -6
- package/dist/offload-worker.mjs +409 -73
- package/dist/{ownership-D6Se7gg_.mjs → ownership-DXzMMSx6.mjs} +2 -2
- package/dist/{placement-log-BcPhRwR4.mjs → placement-log-reFbjqEr.mjs} +7 -3
- package/dist/plan-BDk2AeY_.mjs +260 -0
- package/dist/plan-placement-D_YYlE6N.mjs +73 -0
- package/dist/{ports-BLTtfBq-.mjs → ports-jzvAJXXL.mjs} +3 -3
- package/dist/{prebuild-juCyreaR.mjs → prebuild-Bw44QxVh.mjs} +4 -4
- package/dist/{preview-D5V07Nrl.mjs → preview-BaBJ72Al.mjs} +51 -34
- package/dist/project-B8_duAzW.mjs +1067 -0
- package/dist/project-plan-BPwbLwQu.mjs +10 -0
- package/dist/{pull-request-u4vp7zmK.mjs → pull-request-vOhLNmIb.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/react-native-android-chm1DMlA.mjs +921 -0
- package/dist/react-native-build-oAw6gQeW.mjs +239 -0
- package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
- package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
- package/dist/{recordings-BAWltsVt.mjs → recordings-Bk-VivUV.mjs} +1 -1
- package/dist/{reload-DvyWzVjJ.mjs → reload-D34GkY78.mjs} +17 -14
- package/dist/remote-BU9UyhCJ.mjs +192 -0
- package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
- package/dist/result-BDoRk1k3.mjs +186 -0
- package/dist/{run-vhtDgpHO.mjs → run-qvff78hv.mjs} +3 -3
- package/dist/{server-bare-B9E7S1aR.mjs → server-bare-dWjAarki.mjs} +6 -6
- package/dist/server-command-7XIKlWtO.mjs +69 -0
- package/dist/{server-expo-DoBHhuzK.mjs → server-expo-CsYu2aKL.mjs} +107 -82
- package/dist/server-expo-DV43vep4.mjs +2 -0
- package/dist/settings-Bbztm4oV.mjs +1503 -0
- package/dist/{settings-Byp2AQ_E.mjs → settings-CT3E71-i.mjs} +6 -7
- package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
- package/dist/settings.schema.json +156 -6
- package/dist/simslim-ChMfe8rg.mjs +149 -0
- package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-B9hn96wd.mjs} +6 -6
- package/dist/{stage-g_WqWeaE.mjs → stage-BNKKdDNc.mjs} +6 -3
- package/dist/start-CbQCSnXQ.mjs +2 -0
- package/dist/{start-D-IeOyoK.mjs → start-CdvcTaXr.mjs} +113 -77
- package/dist/{state-xnqpx3AD.mjs → state-Boo0IMJq.mjs} +4 -2
- package/dist/{state-BG-aAk4k.mjs → state-DI84A-uu.mjs} +29 -10
- package/dist/{stats-DY6ekz8F.mjs → stats-BIIDrjA8.mjs} +6 -6
- package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
- package/dist/{status-DCjZeE-K.mjs → status-DARMkc9q.mjs} +80 -294
- package/dist/status-watch-DvmI3SmN.mjs +296 -0
- package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
- package/dist/{stop-DIJtD2GL.mjs → stop-CCZS-C9m.mjs} +2 -2
- package/dist/stop-WQPQHLuy.mjs +72 -0
- package/dist/{stop-BTjs3xbc.mjs → stop-iNemHsJC.mjs} +81 -33
- package/dist/supervisor-run.d.mts +7 -2
- package/dist/supervisor-run.mjs +32 -20
- package/dist/{support-Bwvbrq5-.mjs → support-CnE_SIjt.mjs} +17 -7
- package/dist/{support-BaayeYCf.mjs → support-DCco5fut.mjs} +61 -8
- package/dist/swiftpm-macos-afeNUExW.mjs +119 -0
- package/dist/{native-run-B06FkmZx.mjs → tailnet-CoJUb2tB.mjs} +113 -6
- package/dist/toolchain-BIupIro1.mjs +2 -0
- package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-DqyDXs30.mjs} +225 -315
- package/dist/{trigger-CJMhwXe8.mjs → trigger-C0MWBi8O.mjs} +3 -3
- package/dist/trigger-SHLOWJ4O.mjs +2 -0
- package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-C3ASD6z5.mjs} +134 -37
- package/dist/{status-Dcr0Qexd.mjs → watchman-CQl51YZu.mjs} +75 -7
- package/dist/web-B3eldHFH.mjs +123 -0
- package/dist/web-BLXpOe6b.mjs +2 -0
- package/dist/web-run.mjs +10 -10
- package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
- package/dist/{workspaces-xXItD8Dj.mjs → workspaces-D2xSHBDY.mjs} +1297 -1211
- package/dist/{worktree-BSYlofkq.mjs → worktree-BxDqaTev.mjs} +102 -63
- package/dist/worktree-q7_OZNY0.mjs +2 -0
- package/package.json +8 -6
- package/shim/bundle-response.cjs +2 -1
- package/shim/bundle-response.d.cts +1 -1
- package/shim/expo-metro-config.cjs +1 -1
- package/shim/native-android.gradle +101 -0
- package/dist/android-BKA16DTf.mjs +0 -4
- package/dist/android-BvwuMUJ9.mjs +0 -3572
- package/dist/guide-status-Bhf9SJXc.mjs +0 -125
- package/dist/ios-CPdkoKaa.mjs +0 -3953
- package/dist/ios-DNpdygiv.mjs +0 -7
- package/dist/macos-Ck7OBMNY.mjs +0 -2
- package/dist/metro-store-BAHFcJm6.mjs +0 -106
- package/dist/plan-placement-CtxkCO54.mjs +0 -1859
- package/dist/project-C3ChRLZy.mjs +0 -212
- package/dist/projects-DD7dBTCj.mjs +0 -92
- package/dist/server-expo-Db9HBUoa.mjs +0 -2
- package/dist/settings-CQyMElEP.mjs +0 -701
- package/dist/start-NTc1Ifqs.mjs +0 -2
- package/dist/stop-BGhKMOuH.mjs +0 -48
- package/dist/trigger-DWAq9hkw.mjs +0 -2
- package/dist/web-B6_bFDn7.mjs +0 -2
- package/dist/worktree-BJfnU6r5.mjs +0 -2
- package/dist/worktree-CsKYexJM.mjs +0 -753
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-B81Qodjn.mjs";
|
|
2
|
+
import { d as androidToolPath } from "./android-BsYNR81W.mjs";
|
|
3
|
+
import { b as parseSimctlList } from "./ios-CXLIUxXJ.mjs";
|
|
4
|
+
import { n as easMachineStateRoot } from "./eas-session-ledger-DZlC-Fq3.mjs";
|
|
5
|
+
import { readdirSync, watch } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
//#region src/status-watch.ts
|
|
8
|
+
const WATCH_FALLBACK_MS = 3e4;
|
|
9
|
+
const WATCH_LIGHT_INTERVAL_MS = 15e3;
|
|
10
|
+
const WATCH_SIMCTL_INTERVAL_MS = 5e3;
|
|
11
|
+
const ADB_RESTART_MIN_MS = 1e3;
|
|
12
|
+
const ADB_RESTART_MAX_MS = 6e4;
|
|
13
|
+
const SIMCTL_TIMEOUT_MS = 1e4;
|
|
14
|
+
/**
|
|
15
|
+
* Coalesces change signals into refreshes: a burst of full triggers runs `run('full')` once after `debounceMs` of
|
|
16
|
+
* quiet, at most one run is in flight, and a trigger that arrives during a run causes exactly one more run after it.
|
|
17
|
+
* A `light` trigger runs `run('light')` no sooner than `debounceMs` from the trigger and `lightIntervalMs` from the
|
|
18
|
+
* start of the previous run, unless a queued full run covers it; later light triggers do not postpone it.
|
|
19
|
+
*/
|
|
20
|
+
function createRefreshScheduler({ debounceMs, lightIntervalMs = 0, run }) {
|
|
21
|
+
let timer = null;
|
|
22
|
+
let queued = "full";
|
|
23
|
+
let running = false;
|
|
24
|
+
let pending = null;
|
|
25
|
+
let stopped = false;
|
|
26
|
+
let lastRunAt = -Infinity;
|
|
27
|
+
const fire = async () => {
|
|
28
|
+
timer = null;
|
|
29
|
+
running = true;
|
|
30
|
+
lastRunAt = Date.now();
|
|
31
|
+
try {
|
|
32
|
+
await run(queued);
|
|
33
|
+
} finally {
|
|
34
|
+
running = false;
|
|
35
|
+
if (pending) {
|
|
36
|
+
const next = pending;
|
|
37
|
+
pending = null;
|
|
38
|
+
trigger(next);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function trigger(kind = "full", delayMs = debounceMs) {
|
|
43
|
+
if (stopped) return;
|
|
44
|
+
if (running) {
|
|
45
|
+
pending = pending === "full" ? "full" : kind;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (kind === "light") {
|
|
49
|
+
if (timer) return;
|
|
50
|
+
queued = "light";
|
|
51
|
+
timer = setTimeout(() => void fire(), Math.max(delayMs, lastRunAt + lightIntervalMs - Date.now()));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (timer) clearTimeout(timer);
|
|
55
|
+
queued = "full";
|
|
56
|
+
timer = setTimeout(() => void fire(), delayMs);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
trigger,
|
|
60
|
+
stop() {
|
|
61
|
+
stopped = true;
|
|
62
|
+
if (timer) clearTimeout(timer);
|
|
63
|
+
timer = null;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Which refresh a change to `name` in a watched `$STIM_HOME` directory needs: `light` for a log append or a running
|
|
69
|
+
* build's detail, which can change only the log-derived fields, `full` for anything else that can change the payload,
|
|
70
|
+
* null for none. A null name means the platform did not report one.
|
|
71
|
+
*/
|
|
72
|
+
function statusChange(dir, name) {
|
|
73
|
+
if (dir === "archive" && (name?.startsWith(".incoming-") || name?.startsWith(".removing-") || name?.startsWith(".lock"))) return null;
|
|
74
|
+
if (name?.includes(".lock")) return null;
|
|
75
|
+
if (dir === "logs") return "light";
|
|
76
|
+
if (name === null) return "full";
|
|
77
|
+
switch (dir) {
|
|
78
|
+
case "home":
|
|
79
|
+
if (name === "maintenance") return "light";
|
|
80
|
+
return name.startsWith("config.json") || name === "archive" || name === "workspaces" || name === "device-locks" ? "full" : null;
|
|
81
|
+
case "workspace":
|
|
82
|
+
if (name.startsWith("build-detail.json")) return "light";
|
|
83
|
+
return name.startsWith("state.json") || name.startsWith("ended-agents.json") || name === "logs" ? "full" : null;
|
|
84
|
+
case "maintenance": return name === "state.json" ? "light" : null;
|
|
85
|
+
case "eas": return name.startsWith("sessions.json") ? "full" : null;
|
|
86
|
+
default: return "full";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** A stable summary of every simulator's state, or null when the listing is unreadable. */
|
|
90
|
+
function simulatorSignature(simctlJson) {
|
|
91
|
+
try {
|
|
92
|
+
return parseSimctlList(simctlJson, { includeUnavailable: true }).map((sim) => `${sim.udid}:${sim.state}`).toSorted().join(",");
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Calls `onChange` when anything `stim status` reports may have changed:
|
|
99
|
+
* `$STIM_HOME` files, adb device arrivals and departures, and simulator
|
|
100
|
+
* state. simctl has no push API reachable from Node, so it is polled.
|
|
101
|
+
*/
|
|
102
|
+
function watchStatusSources({ home, onChange, platform = process.platform, simctlIntervalMs = WATCH_SIMCTL_INTERVAL_MS }) {
|
|
103
|
+
let stopped = false;
|
|
104
|
+
const watchers = /* @__PURE__ */ new Map();
|
|
105
|
+
const desiredDirs = () => {
|
|
106
|
+
const dirs = /* @__PURE__ */ new Map([
|
|
107
|
+
[home, "home"],
|
|
108
|
+
[join(home, "archive"), "archive"],
|
|
109
|
+
[join(home, "workspaces"), "workspaces"],
|
|
110
|
+
[join(home, "maintenance"), "maintenance"],
|
|
111
|
+
[join(home, "device-locks"), "leases"],
|
|
112
|
+
[easMachineStateRoot(), "eas"]
|
|
113
|
+
]);
|
|
114
|
+
let names = [];
|
|
115
|
+
try {
|
|
116
|
+
names = readdirSync(join(home, "workspaces"));
|
|
117
|
+
} catch {}
|
|
118
|
+
for (const name of names) {
|
|
119
|
+
const dir = join(home, "workspaces", name);
|
|
120
|
+
dirs.set(dir, "workspace");
|
|
121
|
+
dirs.set(join(dir, "logs"), "logs");
|
|
122
|
+
}
|
|
123
|
+
return dirs;
|
|
124
|
+
};
|
|
125
|
+
const reconcile = () => {
|
|
126
|
+
if (stopped) return;
|
|
127
|
+
const desired = desiredDirs();
|
|
128
|
+
for (const [dir, watcher] of watchers) if (!desired.has(dir)) {
|
|
129
|
+
watcher.close();
|
|
130
|
+
watchers.delete(dir);
|
|
131
|
+
}
|
|
132
|
+
for (const [dir, kind] of desired) {
|
|
133
|
+
if (watchers.has(dir)) continue;
|
|
134
|
+
try {
|
|
135
|
+
const watcher = watch(dir, (_event, name) => {
|
|
136
|
+
const change = statusChange(kind, name === null ? null : String(name));
|
|
137
|
+
if (!change) return;
|
|
138
|
+
if (kind === "home" || kind === "workspaces" || kind === "workspace") {
|
|
139
|
+
listingStaleBefore = Date.now();
|
|
140
|
+
reconcile();
|
|
141
|
+
}
|
|
142
|
+
onChange(change);
|
|
143
|
+
});
|
|
144
|
+
watcher.on("error", () => {
|
|
145
|
+
watcher.close();
|
|
146
|
+
watchers.delete(dir);
|
|
147
|
+
});
|
|
148
|
+
watchers.set(dir, watcher);
|
|
149
|
+
} catch {}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const adb = trackAdbDevices(() => onChange("full"));
|
|
153
|
+
let simctl = null;
|
|
154
|
+
let listing = null;
|
|
155
|
+
let listingStaleBefore = 0;
|
|
156
|
+
let simTimer = null;
|
|
157
|
+
if (platform === "darwin") {
|
|
158
|
+
let last = null;
|
|
159
|
+
const check = () => {
|
|
160
|
+
if (simctl || stopped) return;
|
|
161
|
+
const startedAt = Date.now();
|
|
162
|
+
let out = "";
|
|
163
|
+
const child = getExecutor().spawn("xcrun", [
|
|
164
|
+
"simctl",
|
|
165
|
+
"list",
|
|
166
|
+
"devices",
|
|
167
|
+
"--json"
|
|
168
|
+
], {
|
|
169
|
+
stdio: [
|
|
170
|
+
"ignore",
|
|
171
|
+
"pipe",
|
|
172
|
+
"ignore"
|
|
173
|
+
],
|
|
174
|
+
timeout: SIMCTL_TIMEOUT_MS,
|
|
175
|
+
killSignal: "SIGKILL"
|
|
176
|
+
});
|
|
177
|
+
simctl = child;
|
|
178
|
+
child.stdout?.on("data", (chunk) => out += chunk.toString());
|
|
179
|
+
child.on("error", () => {
|
|
180
|
+
simctl = null;
|
|
181
|
+
});
|
|
182
|
+
child.on("close", () => {
|
|
183
|
+
simctl = null;
|
|
184
|
+
const signature = simulatorSignature(out);
|
|
185
|
+
if (signature === null || stopped) return;
|
|
186
|
+
listing = {
|
|
187
|
+
at: startedAt,
|
|
188
|
+
json: out
|
|
189
|
+
};
|
|
190
|
+
if (last !== null && signature !== last) onChange("full");
|
|
191
|
+
last = signature;
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
check();
|
|
195
|
+
simTimer = setInterval(check, simctlIntervalMs);
|
|
196
|
+
}
|
|
197
|
+
reconcile();
|
|
198
|
+
return {
|
|
199
|
+
reconcile,
|
|
200
|
+
simulatorListing: () => listing && listing.at > listingStaleBefore && Date.now() - listing.at <= 2 * simctlIntervalMs ? listing.json : null,
|
|
201
|
+
stop() {
|
|
202
|
+
stopped = true;
|
|
203
|
+
for (const watcher of watchers.values()) watcher.close();
|
|
204
|
+
watchers.clear();
|
|
205
|
+
if (simTimer) clearInterval(simTimer);
|
|
206
|
+
simctl?.kill("SIGKILL");
|
|
207
|
+
adb.stop();
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Runs `adb track-devices` and calls `onChange` on every device list it
|
|
213
|
+
* reports. adb exits when its server restarts, so the tracker restarts with a
|
|
214
|
+
* doubling delay that resets once a run lasts a minute.
|
|
215
|
+
*/
|
|
216
|
+
function trackAdbDevices(onChange) {
|
|
217
|
+
const exec = getExecutor();
|
|
218
|
+
const resolved = androidToolPath("adb");
|
|
219
|
+
const adb = resolved === "adb" ? exec.findExecutable("adb") : resolved;
|
|
220
|
+
if (!adb) return { stop() {} };
|
|
221
|
+
let child = null;
|
|
222
|
+
let restart = null;
|
|
223
|
+
let delay = ADB_RESTART_MIN_MS;
|
|
224
|
+
let stopped = false;
|
|
225
|
+
const start = () => {
|
|
226
|
+
restart = null;
|
|
227
|
+
if (stopped) return;
|
|
228
|
+
const startedAt = Date.now();
|
|
229
|
+
const current = exec.spawn(adb, ["track-devices"], { stdio: [
|
|
230
|
+
"ignore",
|
|
231
|
+
"pipe",
|
|
232
|
+
"ignore"
|
|
233
|
+
] });
|
|
234
|
+
child = current;
|
|
235
|
+
current.stdout?.on("data", () => onChange());
|
|
236
|
+
current.on("error", () => {});
|
|
237
|
+
current.on("close", () => {
|
|
238
|
+
if (child === current) child = null;
|
|
239
|
+
if (stopped) return;
|
|
240
|
+
if (Date.now() - startedAt >= ADB_RESTART_MAX_MS) delay = ADB_RESTART_MIN_MS;
|
|
241
|
+
restart = setTimeout(start, delay);
|
|
242
|
+
delay = Math.min(delay * 2, ADB_RESTART_MAX_MS);
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
start();
|
|
246
|
+
return { stop() {
|
|
247
|
+
stopped = true;
|
|
248
|
+
if (restart) clearTimeout(restart);
|
|
249
|
+
child?.kill("SIGTERM");
|
|
250
|
+
} };
|
|
251
|
+
}
|
|
252
|
+
function ownerKey(owner) {
|
|
253
|
+
return JSON.stringify([
|
|
254
|
+
owner.kind,
|
|
255
|
+
owner.name,
|
|
256
|
+
owner.workspace,
|
|
257
|
+
owner.slot ?? null,
|
|
258
|
+
owner.id,
|
|
259
|
+
owner.owned
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
function ownerSteady(before, after) {
|
|
263
|
+
return Math.abs(after.cpuPercent - before.cpuPercent) < 5 && Math.abs(after.memoryMb - before.memoryMb) < 16;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The payload `status --watch --json` prints. A usage figure keeps its value from the `previous` printed payload until it moves by a step: an owner's `cpuPercent`
|
|
267
|
+
* and `memoryMb`, an environment's `memoryMb` and `capacity.committedMb`. An owner's row is kept whole, `residentMb`
|
|
268
|
+
* and `processes` included, until one of its two figures moves, so a Mac whose processes only jitter prints no new line.
|
|
269
|
+
*/
|
|
270
|
+
function watchPayload(previous, next) {
|
|
271
|
+
const payload = { ...next };
|
|
272
|
+
if (!previous) return payload;
|
|
273
|
+
if (previous.machine && next.machine && previous.machine.memorySource === next.machine.memorySource) {
|
|
274
|
+
const before = new Map(previous.machine.owners.map((owner) => [ownerKey(owner), owner]));
|
|
275
|
+
payload.machine = {
|
|
276
|
+
...next.machine,
|
|
277
|
+
owners: next.machine.owners.map((owner) => {
|
|
278
|
+
const old = before.get(ownerKey(owner));
|
|
279
|
+
return old && ownerSteady(old, owner) ? old : owner;
|
|
280
|
+
})
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const memory = new Map(previous.environments.map((env) => [env.path, env]));
|
|
284
|
+
payload.environments = payload.environments.map((env) => {
|
|
285
|
+
const old = memory.get(env.path);
|
|
286
|
+
return old && old.memorySource === env.memorySource && Math.abs(env.memoryMb - old.memoryMb) < 16 ? {
|
|
287
|
+
...env,
|
|
288
|
+
memoryMb: old.memoryMb
|
|
289
|
+
} : env;
|
|
290
|
+
});
|
|
291
|
+
const { capacity } = previous;
|
|
292
|
+
if (capacity.overCapacity === next.capacity.overCapacity && capacity.liveCount === next.capacity.liveCount && capacity.totalMemoryMb === next.capacity.totalMemoryMb && Math.abs(next.capacity.committedMb - capacity.committedMb) < 16) payload.capacity = capacity;
|
|
293
|
+
return payload;
|
|
294
|
+
}
|
|
295
|
+
//#endregion
|
|
296
|
+
export { watchStatusSources as a, watchPayload as i, WATCH_LIGHT_INTERVAL_MS as n, createRefreshScheduler as r, WATCH_FALLBACK_MS as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
1
|
+
import { t as getExecutor } from "./exec-B81Qodjn.mjs";
|
|
2
2
|
//#region src/devices/stim-desktop.ts
|
|
3
3
|
const LAUNCH_SERVICES_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationWithBundleIdentifier('dev.stim.desktop'); url.isNil() ? '' : url.path.js`;
|
|
4
4
|
const SCHEME_HANDLER_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationToOpenURL($.NSURL.URLWithString('stim-desktop://workspace')); url.isNil() ? '' : url.path.js`;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-
|
|
1
|
+
import { P as resolveSupervisorTarget } from "./workspaces-D2xSHBDY.mjs";
|
|
2
|
+
import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-iNemHsJC.mjs";
|
|
3
3
|
export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop, stopWorkspaceNow };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
+
import { c as writeWorkspaceState, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
|
|
3
|
+
import { m as runningBundleInstances } from "./workspaces-D2xSHBDY.mjs";
|
|
4
|
+
import { a as withWorkspaceProcessLock } from "./named-ports-C2lvoPsb.mjs";
|
|
5
|
+
import { a as macosRuntimeClaim, o as requiredMacosRecord } from "./state-Boo0IMJq.mjs";
|
|
6
|
+
import { n as stopHostedMacos } from "./hosted-macos-Aziw9T_9.mjs";
|
|
7
|
+
import { readMacosRecord } from "@stim-cli/core/state";
|
|
8
|
+
//#region src/macos/stop.ts
|
|
9
|
+
const APP_EXIT_MS = 5e3;
|
|
10
|
+
const SUPERVISOR_EXIT_MS = 12e3;
|
|
11
|
+
function signal(pid, name) {
|
|
12
|
+
try {
|
|
13
|
+
process.kill(pid, name);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error.code !== "ESRCH") throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function stopProcesses(records, waitMs = APP_EXIT_MS) {
|
|
19
|
+
let live = [...new Map(records.map((record) => [record.pid, record])).values()];
|
|
20
|
+
for (const name of ["SIGTERM", "SIGKILL"]) {
|
|
21
|
+
live = live.filter((record) => {
|
|
22
|
+
const identity = (0, process_identity_exports.inspectProcessIdentity)(record);
|
|
23
|
+
if (identity === "gone" || identity === "different") return false;
|
|
24
|
+
if (identity !== "same") throw Object.assign(/* @__PURE__ */ new Error(`Cannot verify macOS owner pid ${record.pid}; no signal was sent.`), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
for (const record of live) signal(record.pid, name);
|
|
28
|
+
const exited = await Promise.all(live.map((record) => (0, process_identity_exports.waitForProcessExit)(record, waitMs)));
|
|
29
|
+
live = live.filter((_, index) => !exited[index]);
|
|
30
|
+
if (!live.length) return;
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Owned macOS process ${live.map((record) => record.pid).join(", ")} did not exit.`);
|
|
33
|
+
}
|
|
34
|
+
/** Stops every running copy of the workspace's owned app bundle, including copies LaunchServices started. */
|
|
35
|
+
async function stopBundleInstances(root) {
|
|
36
|
+
const instances = runningBundleInstances(root);
|
|
37
|
+
await stopProcesses(instances);
|
|
38
|
+
return instances.length > 0;
|
|
39
|
+
}
|
|
40
|
+
async function stopMacosAppHeld(root) {
|
|
41
|
+
const record = requiredMacosRecord(root);
|
|
42
|
+
if (record?.supervisor) await stopProcesses([record.supervisor], SUPERVISOR_EXIT_MS);
|
|
43
|
+
const app = readMacosRecord(root)?.app ?? record?.app;
|
|
44
|
+
if (app) await stopProcesses([app]);
|
|
45
|
+
const instances = runningBundleInstances(root);
|
|
46
|
+
await stopProcesses(instances);
|
|
47
|
+
if (!record) return instances.length > 0;
|
|
48
|
+
const claims = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
|
|
49
|
+
if (claims.unresolved.length || claims.live.length) throw Object.assign(/* @__PURE__ */ new Error("The macOS runtime claim cannot be released; inspect its recorded owner before cleanup."), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/** Stops the workspace's app here, or its session on the hosting Mac, which must confirm the session stopped. */
|
|
53
|
+
function stopMacosApp(root) {
|
|
54
|
+
const stop = async () => {
|
|
55
|
+
const record = requiredMacosRecord(root);
|
|
56
|
+
if (!record?.host) return stopMacosAppHeld(root);
|
|
57
|
+
await stopHostedMacos(root, record.host);
|
|
58
|
+
const { host: _host, hostLaunched: _launched, ...stopped } = record;
|
|
59
|
+
writeWorkspaceState(root, { macos: {
|
|
60
|
+
...stopped,
|
|
61
|
+
supervisor: void 0
|
|
62
|
+
} });
|
|
63
|
+
return true;
|
|
64
|
+
};
|
|
65
|
+
return withWorkspaceProcessLock(workspaceDir(root), "macos-launch", stop, {
|
|
66
|
+
external: true,
|
|
67
|
+
waitMs: 0,
|
|
68
|
+
ownerPurpose: "stop macOS app"
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { stopMacosApp as n, stopMacosAppHeld as r, stopBundleInstances as t };
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { B as parseDeviceSlotKey, D as withConfigLock$1, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { f as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
2
|
+
import { n as debugLog } from "./exec-B81Qodjn.mjs";
|
|
3
|
+
import { B as parseDeviceSlotKey, D as withConfigLock$1, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-D0LhTY3S.mjs";
|
|
4
|
+
import { n as fileLeaseIo, u as releaseWorkspaceLeases } from "./device-lease-DHOBXGgS.mjs";
|
|
5
|
+
import { a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
|
|
6
|
+
import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-BjPN99ZB.mjs";
|
|
7
|
+
import { A as clearWorkspaceSupervisor, D as clearManagedMetroTunnel, N as readRemoteSession, O as clearRemoteSession, j as readMetroTunnel, k as clearWorkspaceLaunches, n as findCommandWorkspace, w as MODE_COMMAND } from "./project-B8_duAzW.mjs";
|
|
8
|
+
import { d as signalProcessTree, r as killMetroTree, s as pidExists, u as resolveProjectMetro } from "./metro-D_j9sN-B.mjs";
|
|
9
|
+
import { D as stopTunnel, P as resolveSupervisorTarget, b as teardownOwnedIosSim, v as teardownOwnedAvd, y as teardownOwnedBrowser } from "./workspaces-D2xSHBDY.mjs";
|
|
10
|
+
import { _t as withdrawDevServerStopRequest, ht as requestDevServerStop, pt as logVanishedSupervisor } from "./budget-BONq9vXY.mjs";
|
|
11
|
+
import { a as withWorkspaceProcessLock } from "./named-ports-C2lvoPsb.mjs";
|
|
12
|
+
import { _ as nativeRunHolder, d as NATIVE_RUN_LOCK, f as NATIVE_RUN_WAIT_MS, g as describeNativeRunHolder, h as decideStopAction, m as clearNativeRunCancel, v as nativeRunWaitNotice, y as requestNativeRunCancel } from "./tailnet-CoJUb2tB.mjs";
|
|
13
|
+
import { f as resolveEasCliBin } from "./remote-cache-Bsts6f6Y.mjs";
|
|
14
|
+
import { t as macosAppPresent } from "./state-Boo0IMJq.mjs";
|
|
15
|
+
import { i as stopHostedAndroid } from "./hosted-android-DQ-Agsd8.mjs";
|
|
16
|
+
import { i as endRecordedSession } from "./device-remote-Bmg42063.mjs";
|
|
17
|
+
import { n as verifyCollectorOwnership } from "./ownership-DXzMMSx6.mjs";
|
|
18
|
+
import { r as stopHostedIos } from "./hosted-ios-DIxFnYp-.mjs";
|
|
19
|
+
import { n as stopMacosApp } from "./stop-WQPQHLuy.mjs";
|
|
18
20
|
import { hostedAndroidDeviceName, hostedAndroidRecords, hostedIosRecords, hostedNativeRecords, isJsonObject, parseHostedNativePlacement } from "@stim-cli/core/state";
|
|
19
21
|
import chalk from "chalk";
|
|
20
22
|
//#region src/commands/stop.ts
|
|
@@ -249,10 +251,9 @@ async function stopWorkspaceHostedNative(root, slot, report, failed) {
|
|
|
249
251
|
};
|
|
250
252
|
}
|
|
251
253
|
async function stopWorkspaceMacos(root, failed, enabled) {
|
|
252
|
-
if (enabled === false ||
|
|
254
|
+
if (enabled === false || !macosAppPresent(root)) return void 0;
|
|
253
255
|
try {
|
|
254
|
-
await stopMacosApp(root);
|
|
255
|
-
return { status: "stopped" };
|
|
256
|
+
return await stopMacosApp(root) ? { status: "stopped" } : void 0;
|
|
256
257
|
} catch (error) {
|
|
257
258
|
const reason = error instanceof Error ? error.message : String(error);
|
|
258
259
|
failed(reason);
|
|
@@ -262,7 +263,7 @@ async function stopWorkspaceMacos(root, failed, enabled) {
|
|
|
262
263
|
};
|
|
263
264
|
}
|
|
264
265
|
}
|
|
265
|
-
async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid) => signalProcessTree(pid), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, hostedSlot, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
|
|
266
|
+
async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid, group) => signalProcessTree(pid, "SIGTERM", { group }), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, hostedSlot, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
|
|
266
267
|
const proj = project === void 0 ? getProject(root) : project;
|
|
267
268
|
const sup = state === void 0 ? readSupervisorState(root) : state;
|
|
268
269
|
const collectorRecords = collectors === void 0 ? readCollectorState(root) : collectors;
|
|
@@ -292,6 +293,7 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
292
293
|
let ok = true;
|
|
293
294
|
let stillHolding = null;
|
|
294
295
|
let keepPort = null;
|
|
296
|
+
debugLog.log("stop.phase.start", { phase: "supervisor" });
|
|
295
297
|
const target = resolveSupervisorTarget({
|
|
296
298
|
state: sup,
|
|
297
299
|
record: proj?.supervisor ?? null,
|
|
@@ -329,6 +331,11 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
329
331
|
stillHolding = outcomes.supervisor.reason;
|
|
330
332
|
}
|
|
331
333
|
}
|
|
334
|
+
debugLog.log("stop.phase.end", {
|
|
335
|
+
phase: "supervisor",
|
|
336
|
+
status: outcomes.supervisor.status
|
|
337
|
+
});
|
|
338
|
+
debugLog.log("stop.phase.start", { phase: "collectors" });
|
|
332
339
|
outcomes.collectors = await reapCollectors(root, collectorRecords, {
|
|
333
340
|
isAlive,
|
|
334
341
|
signal: signalCollector,
|
|
@@ -344,10 +351,22 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
344
351
|
} else if (outcomes.collectors.entries.some((entry) => entry.status === "failed")) {
|
|
345
352
|
ok = false;
|
|
346
353
|
stillHolding ??= "a collector could not be stopped";
|
|
347
|
-
} else if (outcomes.collectors.entries.length
|
|
348
|
-
|
|
349
|
-
|
|
354
|
+
} else if (outcomes.collectors.entries.length) {
|
|
355
|
+
debugLog.log("stop.phase.start", { phase: "clear-collectors" });
|
|
356
|
+
const cleared = clearCollectors(root, collectorRecords);
|
|
357
|
+
debugLog.log("stop.phase.end", {
|
|
358
|
+
phase: "clear-collectors",
|
|
359
|
+
cleared
|
|
360
|
+
});
|
|
361
|
+
if (cleared === false) {
|
|
362
|
+
ok = false;
|
|
363
|
+
stillHolding ??= "a replacement collector appeared during cleanup";
|
|
364
|
+
}
|
|
350
365
|
}
|
|
366
|
+
debugLog.log("stop.phase.end", {
|
|
367
|
+
phase: "collectors",
|
|
368
|
+
status: outcomes.collectors.status
|
|
369
|
+
});
|
|
351
370
|
if (outcomes.supervisor.status === "stopped" || outcomes.supervisor.status === "timeout" || outcomes.supervisor.status === "unverified" || outcomes.supervisor.status === "failed") outcomes.metro = {
|
|
352
371
|
status: "skipped",
|
|
353
372
|
reason: "the supervisor owns the dev server on this port"
|
|
@@ -627,6 +646,7 @@ async function stopSupervisor(target, { root, killGroup, waiter, report }) {
|
|
|
627
646
|
const reason = `supervisor pid ${target.pid} did not exit within ${Math.round(DEFAULT_WAIT_MS / 1e3)}s of SIGTERM`;
|
|
628
647
|
report(chalk.red(phaseLine("stop", reason)));
|
|
629
648
|
report(chalk.dim(phaseLine("", `inspect it with \`ps -p ${target.pid}\`, or signal it yourself: kill -9 -${target.pid}`)));
|
|
649
|
+
if (target.mode === "command-child") report(chalk.dim(phaseLine("", "metro.command runs in its own process group: once the supervisor is gone, run stim stop again to stop it")));
|
|
630
650
|
return {
|
|
631
651
|
status: "timeout",
|
|
632
652
|
pid: target.pid,
|
|
@@ -659,7 +679,7 @@ async function stopMetro(port, root, { server, supervisorGone, signalServer, ins
|
|
|
659
679
|
report(chalk.dim(phaseLine("metro", `sending SIGTERM to dev server pid ${serverPid} left by the supervisor`)));
|
|
660
680
|
let signalled = false;
|
|
661
681
|
try {
|
|
662
|
-
signalled = signalServer(serverPid);
|
|
682
|
+
signalled = signalServer(serverPid, server?.mode === MODE_COMMAND);
|
|
663
683
|
} catch {}
|
|
664
684
|
if (signalled ? await waiter(serverPid, serverProcessToken) : ["gone", "different"].includes(inspectIdentity(serverRecord))) {
|
|
665
685
|
report(chalk.green(phaseLine("metro", `dev server pid ${serverPid}`)));
|
|
@@ -731,11 +751,25 @@ function shutDownDevices(project, workspace, { teardownIos, teardownAvd, report
|
|
|
731
751
|
reason: "Stim does not own this device"
|
|
732
752
|
};
|
|
733
753
|
report(chalk.dim(phaseLine("device", `${iosUdid} is not Stim-owned, leaving it running`)));
|
|
734
|
-
} else
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
754
|
+
} else {
|
|
755
|
+
debugLog.log("stop.device.start", {
|
|
756
|
+
platform: "ios",
|
|
757
|
+
slot,
|
|
758
|
+
deviceId: iosUdid
|
|
759
|
+
});
|
|
760
|
+
const result = teardownIos(iosUdid, {
|
|
761
|
+
del: false,
|
|
762
|
+
label: iosName,
|
|
763
|
+
workspace
|
|
764
|
+
});
|
|
765
|
+
debugLog.log("stop.device.end", {
|
|
766
|
+
platform: "ios",
|
|
767
|
+
slot,
|
|
768
|
+
deviceId: iosUdid,
|
|
769
|
+
status: result.status
|
|
770
|
+
});
|
|
771
|
+
device[iosKey] = reportDevice(iosUdid, result, report, "ios");
|
|
772
|
+
}
|
|
739
773
|
}
|
|
740
774
|
const android = platforms.android;
|
|
741
775
|
if (android?.avdName) {
|
|
@@ -747,10 +781,24 @@ function shutDownDevices(project, workspace, { teardownIos, teardownAvd, report
|
|
|
747
781
|
reason: "Stim does not own this device"
|
|
748
782
|
};
|
|
749
783
|
report(chalk.dim(phaseLine("device", `${android.avdName} is not Stim-owned, leaving it running`)));
|
|
750
|
-
} else
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
784
|
+
} else {
|
|
785
|
+
debugLog.log("stop.device.start", {
|
|
786
|
+
platform: "android",
|
|
787
|
+
slot,
|
|
788
|
+
deviceId: android.avdName
|
|
789
|
+
});
|
|
790
|
+
const result = teardownAvd(android.avdName, {
|
|
791
|
+
del: false,
|
|
792
|
+
workspace
|
|
793
|
+
});
|
|
794
|
+
debugLog.log("stop.device.end", {
|
|
795
|
+
platform: "android",
|
|
796
|
+
slot,
|
|
797
|
+
deviceId: android.avdName,
|
|
798
|
+
status: result.status
|
|
799
|
+
});
|
|
800
|
+
device[androidKey] = reportDevice(android.avdName, result, report, "android");
|
|
801
|
+
}
|
|
754
802
|
}
|
|
755
803
|
}
|
|
756
804
|
return device;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as clearWorkspaceSupervisor, i as clearExpoMetroTunnel, n as MODE_BARE, o as readPidFile, r as MODE_EXPO, s as writePidFile, t as SettingsObject } from "./settings-vk3mJGSm.mjs";
|
|
2
2
|
import { t as NdjsonWriter } from "./ndjson-Du3j0AQ9.mjs";
|
|
3
3
|
import { DevServerStopRecord, DeviceActivity, DeviceIdleShutdownRecord, IOS_SIMULATOR_APPS } from "@stim-cli/core/state";
|
|
4
4
|
//#region src/supervisor/types.d.ts
|
|
@@ -21,6 +21,7 @@ type ServerStarter = (opts: {
|
|
|
21
21
|
tunnel?: boolean;
|
|
22
22
|
resetCache?: boolean;
|
|
23
23
|
onTunnelUrl?: ((url: string) => void) | null;
|
|
24
|
+
settings?: SettingsObject;
|
|
24
25
|
}) => Promise<ServerHandle>;
|
|
25
26
|
//#endregion
|
|
26
27
|
//#region src/supervisor/idle-stop.d.ts
|
|
@@ -91,13 +92,17 @@ interface RunSupervisorOptions {
|
|
|
91
92
|
isExpo?: (projectRoot: string) => boolean;
|
|
92
93
|
startBare?: ServerStarter | null;
|
|
93
94
|
startExpo?: ServerStarter | null;
|
|
95
|
+
startCommand?: ((opts: Parameters<ServerStarter>[0] & {
|
|
96
|
+
command: readonly string[];
|
|
97
|
+
}) => Promise<ServerHandle>) | null;
|
|
98
|
+
settings?: SettingsObject | null;
|
|
94
99
|
now?: () => number;
|
|
95
100
|
onExit?: (code: number) => void;
|
|
96
101
|
attachSignals?: boolean;
|
|
97
102
|
stderr?: (line: string) => void;
|
|
98
103
|
watchman?: WatchmanCommand;
|
|
99
104
|
}
|
|
100
|
-
declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, deviceIdleMinutes, deviceIdle, isExpo, startBare, startExpo, now, onExit, attachSignals, stderr, watchman }: RunSupervisorOptions): Promise<{
|
|
105
|
+
declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, deviceIdleMinutes, deviceIdle, isExpo, startBare, startExpo, startCommand, settings: settingsOverride, now, onExit, attachSignals, stderr, watchman }: RunSupervisorOptions): Promise<{
|
|
101
106
|
mode: string;
|
|
102
107
|
server: ServerHandle | undefined;
|
|
103
108
|
shutdown: (code: number, event: string, msg: string, stop?: DevServerStopRecord) => Promise<void>;
|