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
package/dist/supervisor-run.mjs
CHANGED
|
@@ -1,22 +1,150 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { r as detectIsExpo } from "./project-
|
|
1
|
+
import { B as parseDeviceSlotKey, H as projectDeviceSlots, T as setSupervisor, o as clearSupervisor, p as getProject } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
|
+
import { t as relaunchWithLogFile } from "./detached-entry-CiTEgMR1.mjs";
|
|
4
|
+
import { r as detectIsExpo } from "./project-Du91Ilvc.mjs";
|
|
5
|
+
import { C as workspaceStateFile, a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
|
|
6
|
+
import { n as withIdleWorkspace } from "./in-use-DvBw0Kxo.mjs";
|
|
7
|
+
import { r as createActivityReader } from "./activity-BxwdD81S.mjs";
|
|
8
|
+
import { a as parseLease, r as leaseIsExpired, s as parseWorkspaceLeases, t as deviceLeasePath } from "./device-lease-D-hLqx1b.mjs";
|
|
9
|
+
import { l as readPidFile, n as MODE_EXPO, p as writePidFile, r as clearExpoMetroTunnel, s as clearWorkspaceSupervisor, t as MODE_BARE } from "./state-DcW6vOd_.mjs";
|
|
10
|
+
import { C as parseSubscriberNames, O as runWatchman, T as parseWatchRoots, s as workspaceBuildInProgress, w as parseTriggerCount } from "./idle-DYVymG92.mjs";
|
|
11
|
+
import { z as ownedAvdSerialResolver } from "./android-B_NumVyQ.mjs";
|
|
12
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
|
|
5
13
|
import { t as describeError } from "./errors-B6W7FkxQ.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { n as
|
|
11
|
-
import { R as ownedAvdSerialResolver } from "./android-d6rGq1pA.mjs";
|
|
12
|
-
import { c as vanishedSupervisorMessage, i as devServerStopRecord, r as devServerStopLevel, t as describeDevServerStop } from "./stop-cause-hjGBOZTG.mjs";
|
|
13
|
-
import { s as workspaceBuildInProgress } from "./idle-DXtx3RbX.mjs";
|
|
14
|
-
import { n as withIdleWorkspace } from "./in-use-DlqBDKqY.mjs";
|
|
14
|
+
import { r as createNdjsonWriter } from "./ndjson-PclOIwVY.mjs";
|
|
15
|
+
import { c as vanishedSupervisorMessage, i as devServerStopRecord, r as devServerStopLevel, t as describeDevServerStop } from "./stop-cause-CidxIqup.mjs";
|
|
16
|
+
import { l as probeHostedSession } from "./hosted-client-a-WmqE2L.mjs";
|
|
17
|
+
import { t as clearHostedMetro } from "./metro-gateway-BJ-rxQAB.mjs";
|
|
18
|
+
import { n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-CTsDnAde.mjs";
|
|
15
19
|
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
20
|
+
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
21
|
+
import { LOG_ROTATE_BYTES, createMetroGateway } from "@stim-cli/core";
|
|
22
|
+
import { DEV_SERVER_STOP_REQUEST_KEY, HOSTED_METRO_GATEWAYS_KEY, HOSTED_METRO_REQUESTS_KEY, IDLE_STOP_KEY, hostedIosPlacements, hostedMetroGateways, hostedMetroRequests, readDevServerStopRequest } from "@stim-cli/core/state";
|
|
19
23
|
import { fileURLToPath } from "node:url";
|
|
24
|
+
//#region src/supervisor/hosted-metro.ts
|
|
25
|
+
function reconcileHostedMetro(requests, active) {
|
|
26
|
+
const same = (session) => JSON.stringify(requests[session]) === JSON.stringify(active[session]);
|
|
27
|
+
return {
|
|
28
|
+
close: Object.keys(active).filter((session) => !same(session)),
|
|
29
|
+
open: Object.keys(requests).filter((session) => !same(session))
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function watchHostedMetro(root, metroPort, processToken) {
|
|
33
|
+
const active = {};
|
|
34
|
+
const bridges = /* @__PURE__ */ new Map();
|
|
35
|
+
let closed = false;
|
|
36
|
+
let running = Promise.resolve();
|
|
37
|
+
let probingAt = 0;
|
|
38
|
+
let probing = false;
|
|
39
|
+
let stamp = "";
|
|
40
|
+
let cached = null;
|
|
41
|
+
updateWorkspaceState(root, (state) => state.supervisor?.processToken === processToken ? {
|
|
42
|
+
...state,
|
|
43
|
+
supervisor: {
|
|
44
|
+
...state.supervisor,
|
|
45
|
+
hostedMetro: true
|
|
46
|
+
}
|
|
47
|
+
} : state);
|
|
48
|
+
const readState = () => {
|
|
49
|
+
const file = statSync(workspaceStateFile(root));
|
|
50
|
+
const next = `${file.ino}:${file.mtimeMs}:${file.ctimeMs}:${file.size}`;
|
|
51
|
+
if (next !== stamp) {
|
|
52
|
+
cached = readWorkspaceState$1(root);
|
|
53
|
+
stamp = next;
|
|
54
|
+
}
|
|
55
|
+
return cached;
|
|
56
|
+
};
|
|
57
|
+
const publish = (session, gateway) => updateWorkspaceState(root, (state) => {
|
|
58
|
+
const gateways = { ...hostedMetroGateways(state) };
|
|
59
|
+
if (state.supervisor?.processToken !== processToken) return state;
|
|
60
|
+
if (gateway) gateways[session] = gateway;
|
|
61
|
+
else delete gateways[session];
|
|
62
|
+
return {
|
|
63
|
+
...state,
|
|
64
|
+
[HOSTED_METRO_GATEWAYS_KEY]: gateways
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
const reconcile = async () => {
|
|
68
|
+
if (closed) return;
|
|
69
|
+
const state = readState();
|
|
70
|
+
if (state?.supervisor?.processToken !== processToken) return;
|
|
71
|
+
const placements = Object.values(hostedIosPlacements(state));
|
|
72
|
+
const sessions = new Set(placements.map((placement) => placement.session));
|
|
73
|
+
const requests = Object.fromEntries(Object.entries(hostedMetroRequests(state)).filter(([session]) => sessions.has(session)));
|
|
74
|
+
if (Object.keys(requests).length !== Object.keys(hostedMetroRequests(state)).length) updateWorkspaceState(root, (current) => {
|
|
75
|
+
if (current.supervisor?.processToken !== processToken) return current;
|
|
76
|
+
const recorded = new Set(Object.values(hostedIosPlacements(current)).map((placement) => placement.session));
|
|
77
|
+
return {
|
|
78
|
+
...current,
|
|
79
|
+
[HOSTED_METRO_REQUESTS_KEY]: Object.fromEntries(Object.entries(hostedMetroRequests(current)).filter(([session]) => recorded.has(session)))
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const actions = reconcileHostedMetro(requests, active);
|
|
83
|
+
for (const session of actions.close) {
|
|
84
|
+
await bridges.get(session)?.close();
|
|
85
|
+
bridges.delete(session);
|
|
86
|
+
delete active[session];
|
|
87
|
+
publish(session, null);
|
|
88
|
+
}
|
|
89
|
+
for (const session of actions.open) {
|
|
90
|
+
const request = requests[session];
|
|
91
|
+
active[session] = request;
|
|
92
|
+
const bridge = createMetroGateway({
|
|
93
|
+
metroPort,
|
|
94
|
+
peer: request.peer,
|
|
95
|
+
secret: request.secret
|
|
96
|
+
});
|
|
97
|
+
bridges.set(session, bridge);
|
|
98
|
+
try {
|
|
99
|
+
const saved = hostedMetroGateways(state)[session];
|
|
100
|
+
await new Promise((resolve, reject) => {
|
|
101
|
+
bridge.server.once("error", reject);
|
|
102
|
+
bridge.server.listen(saved?.id === request.id ? saved.port ?? 0 : 0, request.address, () => {
|
|
103
|
+
bridge.server.removeListener("error", reject);
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
const address = bridge.server.address();
|
|
108
|
+
if (!address || typeof address === "string") throw new Error("No gateway port.");
|
|
109
|
+
publish(session, {
|
|
110
|
+
id: request.id,
|
|
111
|
+
processToken,
|
|
112
|
+
port: address.port
|
|
113
|
+
});
|
|
114
|
+
} catch {
|
|
115
|
+
await bridge.close();
|
|
116
|
+
bridges.delete(session);
|
|
117
|
+
publish(session, {
|
|
118
|
+
id: request.id,
|
|
119
|
+
processToken,
|
|
120
|
+
error: `Could not bind the private Metro gateway for ${request.machine}. Check Tailscale, then restart Metro.`
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!probing && Date.now() >= probingAt) {
|
|
125
|
+
probingAt = Date.now() + 1e4;
|
|
126
|
+
probing = true;
|
|
127
|
+
Promise.all(placements.map(async (placement) => {
|
|
128
|
+
if ((await probeHostedSession(placement)).state === "stopped" && !closed) clearHostedMetro(root, placement.session);
|
|
129
|
+
})).catch(() => {}).finally(() => {
|
|
130
|
+
probing = false;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const tick = () => {
|
|
135
|
+
running = running.then(reconcile).catch(() => {});
|
|
136
|
+
};
|
|
137
|
+
const timer = setInterval(tick, 500);
|
|
138
|
+
timer.unref();
|
|
139
|
+
tick();
|
|
140
|
+
return async () => {
|
|
141
|
+
closed = true;
|
|
142
|
+
clearInterval(timer);
|
|
143
|
+
await running;
|
|
144
|
+
await Promise.all([...bridges.values()].map((bridge) => bridge.close()));
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
20
148
|
//#region src/supervisor/idle-stop.ts
|
|
21
149
|
const IDLE_CHECK_MS = 6e4;
|
|
22
150
|
const MINUTE_MS = 6e4;
|
|
@@ -80,13 +208,15 @@ function workspaceIdleProbe(root, { platform = process.platform } = {}) {
|
|
|
80
208
|
const used = Date.parse(String(readWorkspaceState$1(root)?.lastUsedAt ?? ""));
|
|
81
209
|
let clientLog = NaN;
|
|
82
210
|
try {
|
|
83
|
-
clientLog = statSync(join(workspaceLogsDir(root), "client.ndjson")).mtimeMs;
|
|
211
|
+
clientLog = statSync(join(workspaceLogsDir$1(root), "client.ndjson")).mtimeMs;
|
|
84
212
|
} catch {}
|
|
85
213
|
const times = [used, clientLog].filter(Number.isFinite);
|
|
86
214
|
return times.length ? Math.max(...times) : NaN;
|
|
87
215
|
},
|
|
88
216
|
blocker() {
|
|
89
217
|
if (workspaceBuildInProgress(root)) return "a build is in progress";
|
|
218
|
+
const hosted = Object.values(hostedIosPlacements(readWorkspaceState$1(root)))[0];
|
|
219
|
+
if (hosted) return `its iOS simulator runs on ${hosted.machine}`;
|
|
90
220
|
const lease = heldDeviceLease(root, Date.now());
|
|
91
221
|
if (lease) return lease;
|
|
92
222
|
const readActivity = createActivityReader();
|
|
@@ -126,15 +256,163 @@ function watchIdleDevServer({ idleStopMs, now, serverActivityAt, probe, onIdle,
|
|
|
126
256
|
timer.unref?.();
|
|
127
257
|
return () => clearInterval(timer);
|
|
128
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Checks each minute, once the workspace has gone `idleMs` without a Stim command, whether an owned device is due
|
|
261
|
+
* for idle shutdown, and runs `onDue` for it.
|
|
262
|
+
*/
|
|
263
|
+
function watchIdleDevices({ idleMs, now, lastUseAt, hasDue, onDue, checkMs = IDLE_CHECK_MS }) {
|
|
264
|
+
let deciding = false;
|
|
265
|
+
const timer = setInterval(() => {
|
|
266
|
+
if (deciding || now() - lastUseAt() < idleMs) return;
|
|
267
|
+
let due;
|
|
268
|
+
try {
|
|
269
|
+
due = hasDue();
|
|
270
|
+
} catch {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (!due) return;
|
|
274
|
+
deciding = true;
|
|
275
|
+
onDue().finally(() => {
|
|
276
|
+
deciding = false;
|
|
277
|
+
});
|
|
278
|
+
}, Math.min(checkMs, idleMs));
|
|
279
|
+
timer.unref?.();
|
|
280
|
+
return () => clearInterval(timer);
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/supervisor/watchman-roots.ts
|
|
284
|
+
const WATCHMAN_TIMEOUT_MS = 2e3;
|
|
285
|
+
const SHUTDOWN_BUDGET_MS = 3e3;
|
|
286
|
+
const PROBE_DELAYS_MS = [
|
|
287
|
+
3e3,
|
|
288
|
+
6e3,
|
|
289
|
+
1e4,
|
|
290
|
+
15e3,
|
|
291
|
+
2e4,
|
|
292
|
+
3e4,
|
|
293
|
+
45e3,
|
|
294
|
+
6e4,
|
|
295
|
+
12e4,
|
|
296
|
+
3e5
|
|
297
|
+
];
|
|
298
|
+
function canonical(path) {
|
|
299
|
+
try {
|
|
300
|
+
return realpathSync(path);
|
|
301
|
+
} catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function newRootsContaining(before, current, workspaceRoot) {
|
|
306
|
+
const seen = new Set(before.map((root) => canonical(root) ?? root));
|
|
307
|
+
return current.filter((root) => {
|
|
308
|
+
const resolved = canonical(root);
|
|
309
|
+
if (resolved === null || seen.has(resolved)) return false;
|
|
310
|
+
return workspaceRoot === resolved || workspaceRoot.startsWith(resolved.endsWith(sep) ? resolved : resolved + sep);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function metroSubscriptionPrefix(pid) {
|
|
314
|
+
return `metro-file-map-${pid}-`;
|
|
315
|
+
}
|
|
316
|
+
async function watchRoots(watchman) {
|
|
317
|
+
try {
|
|
318
|
+
return parseWatchRoots(await watchman(["watch-list"]));
|
|
319
|
+
} catch {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function subscriberNames(watchman, root) {
|
|
324
|
+
try {
|
|
325
|
+
return parseSubscriberNames(await watchman(["debug-get-subscriptions", root]));
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async function triggerCount(watchman, root) {
|
|
331
|
+
try {
|
|
332
|
+
return parseTriggerCount(await watchman(["trigger-list", root]));
|
|
333
|
+
} catch {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function trackMetroWatchRoots({ workspaceRoot, writer, watchman = runWatchman, probeDelaysMs = PROBE_DELAYS_MS }) {
|
|
338
|
+
let deadline = Infinity;
|
|
339
|
+
const call = async (args) => {
|
|
340
|
+
const left = deadline - Date.now();
|
|
341
|
+
if (left <= 0) throw new Error("the watchman cleanup ran out of time");
|
|
342
|
+
return watchman(args, Math.min(WATCHMAN_TIMEOUT_MS, left));
|
|
343
|
+
};
|
|
344
|
+
const before = watchRoots(call);
|
|
345
|
+
const owned = /* @__PURE__ */ new Set();
|
|
346
|
+
const timers = [];
|
|
347
|
+
let prefix = null;
|
|
348
|
+
const probe = async () => {
|
|
349
|
+
const earlier = await before;
|
|
350
|
+
if (prefix === null || earlier === null) return;
|
|
351
|
+
const current = await watchRoots(call);
|
|
352
|
+
if (current === null) return;
|
|
353
|
+
for (const root of newRootsContaining(earlier, current, workspaceRoot)) {
|
|
354
|
+
if (owned.has(root)) continue;
|
|
355
|
+
if ((await subscriberNames(call, root))?.some((name) => name.startsWith(prefix))) owned.add(root);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
return {
|
|
359
|
+
started(metroPid) {
|
|
360
|
+
prefix = metroSubscriptionPrefix(metroPid);
|
|
361
|
+
for (const delay of probeDelaysMs) {
|
|
362
|
+
const timer = setTimeout(() => void probe(), delay);
|
|
363
|
+
timer.unref?.();
|
|
364
|
+
timers.push(timer);
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
async beforeClose() {
|
|
368
|
+
for (const timer of timers) clearTimeout(timer);
|
|
369
|
+
deadline = Date.now() + SHUTDOWN_BUDGET_MS;
|
|
370
|
+
await probe();
|
|
371
|
+
},
|
|
372
|
+
async afterClose() {
|
|
373
|
+
for (const root of owned) {
|
|
374
|
+
const others = (await subscriberNames(call, root))?.filter((name) => !name.startsWith(prefix));
|
|
375
|
+
const triggers = others?.length === 0 ? await triggerCount(call, root) : null;
|
|
376
|
+
const reason = !others ? "could not list its subscriptions" : others.length > 0 ? `${others.length} other subscription(s) still use it` : triggers === null ? "could not list its triggers" : triggers > 0 ? `it has ${triggers} trigger(s)` : null;
|
|
377
|
+
if (reason) {
|
|
378
|
+
writer.write({
|
|
379
|
+
src: "metro",
|
|
380
|
+
level: "debug",
|
|
381
|
+
event: "watchman_root_kept",
|
|
382
|
+
msg: `kept the watchman root ${root}: ${reason}`
|
|
383
|
+
});
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
await call(["watch-del", root]);
|
|
388
|
+
writer.write({
|
|
389
|
+
src: "metro",
|
|
390
|
+
level: "info",
|
|
391
|
+
event: "watchman_root_removed",
|
|
392
|
+
msg: `removed the watchman root ${root} that this dev server registered`
|
|
393
|
+
});
|
|
394
|
+
} catch (err) {
|
|
395
|
+
writer.write({
|
|
396
|
+
src: "metro",
|
|
397
|
+
level: "warn",
|
|
398
|
+
event: "watchman_root_kept",
|
|
399
|
+
msg: `could not remove the watchman root ${root}: ${describeError(err)}`
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
129
406
|
//#endregion
|
|
130
407
|
//#region src/supervisor/run.ts
|
|
131
|
-
const USAGE = "Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache] [--idle-stop-minutes <n>]";
|
|
408
|
+
const USAGE = "Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache] [--idle-stop-minutes <n>] [--device-idle-minutes <n>]";
|
|
132
409
|
function parseArgs(argv) {
|
|
133
410
|
let root;
|
|
134
411
|
let port;
|
|
135
412
|
let tunnel = false;
|
|
136
413
|
let resetCache = false;
|
|
137
414
|
let idleStopMinutes = "0";
|
|
415
|
+
let deviceIdleMinutes = "0";
|
|
138
416
|
for (let i = 0; i < argv.length; i++) {
|
|
139
417
|
const arg = argv[i];
|
|
140
418
|
if (arg === "--root") {
|
|
@@ -157,24 +435,33 @@ function parseArgs(argv) {
|
|
|
157
435
|
idleStopMinutes = argv[++i] ?? "";
|
|
158
436
|
continue;
|
|
159
437
|
}
|
|
438
|
+
if (arg === "--device-idle-minutes") {
|
|
439
|
+
deviceIdleMinutes = argv[++i] ?? "";
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
160
442
|
return { error: `Unknown supervisor argument "${arg}". ${USAGE}` };
|
|
161
443
|
}
|
|
162
444
|
if (!root) return { error: `Missing --root. ${USAGE}` };
|
|
163
445
|
if (!isAbsolute(root)) return { error: `--root must be an absolute path, got "${root}".` };
|
|
164
446
|
const parsedPort = Number(port);
|
|
165
447
|
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) return { error: `--port must be a TCP port number, got "${port}".` };
|
|
166
|
-
if (!/^\d+$/.test(
|
|
448
|
+
for (const [flag, value] of [["--idle-stop-minutes", idleStopMinutes], ["--device-idle-minutes", deviceIdleMinutes]]) if (!/^\d+$/.test(value)) return { error: `${flag} must be a whole number of minutes, got "${value}".` };
|
|
167
449
|
return {
|
|
168
450
|
root: resolve(root),
|
|
169
451
|
port: parsedPort,
|
|
170
452
|
tunnel,
|
|
171
453
|
resetCache,
|
|
172
|
-
idleStopMinutes: Number(idleStopMinutes)
|
|
454
|
+
idleStopMinutes: Number(idleStopMinutes),
|
|
455
|
+
deviceIdleMinutes: Number(deviceIdleMinutes)
|
|
173
456
|
};
|
|
174
457
|
}
|
|
175
|
-
|
|
458
|
+
const DEVICE_IDLE_OPS = {
|
|
459
|
+
due: dueIdleDevices,
|
|
460
|
+
shutDown: shutDownIdleDevices
|
|
461
|
+
};
|
|
462
|
+
async function runSupervisor({ root, port, tunnel = false, resetCache = false, idleStopMinutes = 0, idleProbe, deviceIdleMinutes = 0, deviceIdle = DEVICE_IDLE_OPS, isExpo = detectIsExpo, startBare = null, startExpo = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line), watchman = runWatchman }) {
|
|
176
463
|
root = realpathSync(root);
|
|
177
|
-
const logsDir = workspaceLogsDir(root);
|
|
464
|
+
const logsDir = workspaceLogsDir$1(root);
|
|
178
465
|
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
179
466
|
const mode = isExpo(root) ? MODE_EXPO : MODE_BARE;
|
|
180
467
|
const startedAt = new Date(now()).toISOString();
|
|
@@ -222,12 +509,15 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
222
509
|
});
|
|
223
510
|
let stopping = false;
|
|
224
511
|
let stopWatchingIdle = null;
|
|
512
|
+
let stopWatchingDevices = null;
|
|
513
|
+
let closeHostedMetro = null;
|
|
225
514
|
const stopCause = (trigger) => {
|
|
226
515
|
const request = readDevServerStopRequest(readWorkspaceState$1(root));
|
|
227
516
|
return devServerStopRecord(trigger, request?.processToken === processToken ? request : null, new Date(now()).toISOString());
|
|
228
517
|
};
|
|
229
518
|
const finish = (code, event, level, msg, stop) => {
|
|
230
519
|
stopWatchingIdle?.();
|
|
520
|
+
stopWatchingDevices?.();
|
|
231
521
|
writer.write({
|
|
232
522
|
src: "metro",
|
|
233
523
|
level,
|
|
@@ -254,10 +544,18 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
254
544
|
onExit(code);
|
|
255
545
|
};
|
|
256
546
|
let server;
|
|
547
|
+
const watchRoots = trackMetroWatchRoots({
|
|
548
|
+
workspaceRoot: root,
|
|
549
|
+
writer,
|
|
550
|
+
watchman
|
|
551
|
+
});
|
|
257
552
|
const shutdown = async (code, event, msg, stop) => {
|
|
258
553
|
if (stopping || !server) return;
|
|
259
554
|
stopping = true;
|
|
260
555
|
stopWatchingIdle?.();
|
|
556
|
+
stopWatchingDevices?.();
|
|
557
|
+
await closeHostedMetro?.();
|
|
558
|
+
await watchRoots.beforeClose();
|
|
261
559
|
try {
|
|
262
560
|
await server.close();
|
|
263
561
|
} catch (err) {
|
|
@@ -268,6 +566,7 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
268
566
|
msg: describeError(err)
|
|
269
567
|
});
|
|
270
568
|
}
|
|
569
|
+
await watchRoots.afterClose();
|
|
271
570
|
finish(code, event, stop ? devServerStopLevel(stop) : code === 0 ? "info" : "error", msg, stop);
|
|
272
571
|
};
|
|
273
572
|
if (attachSignals) for (const signal of ["SIGTERM", "SIGINT"]) process.on(signal, () => {
|
|
@@ -293,7 +592,7 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
293
592
|
return writer.write(entry);
|
|
294
593
|
} });
|
|
295
594
|
try {
|
|
296
|
-
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-
|
|
595
|
+
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-CVqO2c35.mjs")).startExpoServer : startBare || (await import("./server-bare-CpPGmnmO.mjs")).startBareServer)({
|
|
297
596
|
root,
|
|
298
597
|
port,
|
|
299
598
|
logsDir,
|
|
@@ -342,12 +641,46 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
342
641
|
} });
|
|
343
642
|
});
|
|
344
643
|
}
|
|
644
|
+
watchRoots.started(serverPid ?? process.pid);
|
|
345
645
|
writer.write({
|
|
346
646
|
src: "metro",
|
|
347
647
|
level: "info",
|
|
348
648
|
event: "server_started",
|
|
349
649
|
msg: `${mode} dev server listening on port ${port}`
|
|
350
650
|
});
|
|
651
|
+
closeHostedMetro = watchHostedMetro(root, port, processToken);
|
|
652
|
+
const deviceIdleMs = deviceIdleMinutes * 6e4;
|
|
653
|
+
const workspaceProbe = workspaceIdleProbe(root);
|
|
654
|
+
const shutDownIdleDevices = (idleMs) => deviceIdle.shutDown(root, idleMs, (entry) => writer.write({
|
|
655
|
+
src: "metro",
|
|
656
|
+
...entry
|
|
657
|
+
}));
|
|
658
|
+
if (deviceIdleMinutes > 0) stopWatchingDevices = watchIdleDevices({
|
|
659
|
+
idleMs: deviceIdleMs,
|
|
660
|
+
now,
|
|
661
|
+
lastUseAt: () => {
|
|
662
|
+
let deviceLog = NaN;
|
|
663
|
+
try {
|
|
664
|
+
deviceLog = statSync(join(logsDir, "device.ndjson")).mtimeMs;
|
|
665
|
+
} catch {}
|
|
666
|
+
const times = [workspaceProbe.lastActivityAt(), deviceLog].filter(Number.isFinite);
|
|
667
|
+
return times.length ? Math.max(...times) : NaN;
|
|
668
|
+
},
|
|
669
|
+
hasDue: () => deviceIdle.due(root, deviceIdleMs).length > 0,
|
|
670
|
+
onDue: async () => {
|
|
671
|
+
try {
|
|
672
|
+
await withIdleWorkspace(root, () => {
|
|
673
|
+
if (!stopping) shutDownIdleDevices(deviceIdleMs);
|
|
674
|
+
}, {
|
|
675
|
+
purpose: "device idle shutdown",
|
|
676
|
+
supervisor: false,
|
|
677
|
+
managedLocks: false
|
|
678
|
+
});
|
|
679
|
+
} catch (err) {
|
|
680
|
+
stderr(`Stim supervisor: could not shut down idle devices: ${describeError(err)}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
});
|
|
351
684
|
if (idleStopMinutes > 0) stopWatchingIdle = watchIdleDevServer({
|
|
352
685
|
idleStopMs: idleStopMinutes * 6e4,
|
|
353
686
|
now,
|
|
@@ -357,6 +690,11 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
357
690
|
const stopIfStillIdle = async () => {
|
|
358
691
|
const idleMinutes = idleMinutesNow();
|
|
359
692
|
if (stopping || idleMinutes === null) return;
|
|
693
|
+
if (deviceIdleMinutes > 0) try {
|
|
694
|
+
shutDownIdleDevices(Math.min(deviceIdleMs, idleStopMinutes * 6e4));
|
|
695
|
+
} catch (err) {
|
|
696
|
+
stderr(`Stim supervisor: could not shut down idle devices: ${describeError(err)}`);
|
|
697
|
+
}
|
|
360
698
|
const stop = {
|
|
361
699
|
reason: "idle",
|
|
362
700
|
at: new Date(now()).toISOString(),
|
|
@@ -422,7 +760,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
422
760
|
port: parsed.port,
|
|
423
761
|
tunnel: parsed.tunnel ?? false,
|
|
424
762
|
resetCache: parsed.resetCache ?? false,
|
|
425
|
-
idleStopMinutes: parsed.idleStopMinutes ?? 0
|
|
763
|
+
idleStopMinutes: parsed.idleStopMinutes ?? 0,
|
|
764
|
+
deviceIdleMinutes: parsed.deviceIdleMinutes ?? 0
|
|
426
765
|
});
|
|
427
766
|
}
|
|
428
767
|
function invokedDirectly() {
|