stim 1.13.0 → 1.15.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-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
- package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
- package/dist/android-cas-PnKfAdB2.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
- package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
- package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
- package/dist/cli-0cX5s4NM.mjs +45 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-C2IS36Qf.mjs +1333 -0
- package/dist/collector-run.mjs +8 -7
- package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
- package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CjzLoNs0.mjs +80 -0
- package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
- package/dist/device-capacity-DMuKC7nx.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +769 -0
- package/dist/device-ios-DMQBUPus.mjs +381 -0
- package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
- package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
- package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
- package/dist/hosted-macos-DwowNU7W.mjs +447 -0
- package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
- package/dist/in-use-CndPMilN.mjs +110 -0
- package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
- package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
- package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
- package/dist/machine-usage-D_YYMzfR.mjs +283 -0
- package/dist/machines-CYtOCqcj.mjs +259 -0
- package/dist/macos-BwtbUtTN.mjs +468 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
- package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
- 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-GEXp4iBT.mjs +37 -0
- package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
- package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/slot-launch-BY0BrOLh.mjs +65 -0
- package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-DncpJvWL.mjs +16 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CPO4wRg7.mjs +2 -0
- package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
- package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
- 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-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +44 -12
- package/dist/supervisor-run.mjs +276 -33
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
- package/dist/web-run.mjs +326 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-CL2V2Ons.mjs +371 -0
- package/dist/worktree-BT_uULFx.mjs +2 -0
- package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
- package/package.json +10 -5
- package/shim/bundle-response.cjs +55 -10
- package/shim/bundle-response.d.cts +1 -0
- package/shim/expo-metro-config.cjs +10 -2
- package/dist/build-progress-l7d-X-ZP.mjs +0 -247
- package/dist/in-use-wYEaKQM9.mjs +0 -249
- package/dist/ownership-PUP4Dwai.mjs +0 -1138
- package/dist/server-expo-BeYwP_Xy.mjs +0 -2
- package/dist/slot-launch-BIWEW-wI.mjs +0 -19
- package/dist/start-Rw2GD3nV.mjs +0 -2
- package/dist/stats-CaSwmsSZ.mjs +0 -62
- package/dist/stats-D8rUTPHd.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/worktree-3cBa-bQt.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
import { t as NdjsonWriter } from "./ndjson-Du3j0AQ9.mjs";
|
|
2
|
-
import "
|
|
2
|
+
import { a as readPidFile, i as clearWorkspaceSupervisor, n as MODE_EXPO, o as writePidFile, r as clearExpoMetroTunnel, t as MODE_BARE } from "./state-B4PQFXMW.mjs";
|
|
3
|
+
import { DevServerStopRecord, DeviceActivity, IOS_SIMULATOR_APPS } from "@stim-cli/core/state";
|
|
3
4
|
//#region src/supervisor/idle-stop.d.ts
|
|
4
5
|
interface IdleProbe {
|
|
5
6
|
lastActivityAt(): number;
|
|
6
7
|
blocker(): string | null;
|
|
7
8
|
}
|
|
8
|
-
import * as import__stim_cli_core_process_identity from "@stim-cli/core/process-identity";
|
|
9
9
|
//#endregion
|
|
10
|
-
//#region src/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
//#region src/commands/gc/idle.d.ts
|
|
11
|
+
interface OwnedDeviceActivity {
|
|
12
|
+
kind: "ios" | "android";
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
project: string;
|
|
16
|
+
slot: string;
|
|
17
|
+
activity: DeviceActivity;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/devices/idle-shutdown.d.ts
|
|
21
|
+
interface DueDevice {
|
|
22
|
+
device: OwnedDeviceActivity;
|
|
23
|
+
idleForMs: number;
|
|
24
|
+
}
|
|
25
|
+
/** The workspace's booted owned simulators and emulators that have been idle for `idleMs` or more. */
|
|
26
|
+
declare function dueIdleDevices(root: string, idleMs: number, now?: number): DueDevice[];
|
|
27
|
+
interface IdleShutdownEvent {
|
|
28
|
+
level: "info" | "warn";
|
|
29
|
+
event: "device_idle_shutdown" | "device_idle_shutdown_failed";
|
|
30
|
+
msg: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Shuts down, through centralized teardown, each of the workspace's owned devices that is still idle for `idleMs`,
|
|
34
|
+
* and records why. The caller holds the workspace's native-run lock, so no `ios` or `android` run is booting or
|
|
35
|
+
* installing on them.
|
|
36
|
+
*/
|
|
37
|
+
declare function shutDownIdleDevices(root: string, idleMs: number, log: (event: IdleShutdownEvent) => void, now?: number): number;
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/watchman.d.ts
|
|
40
|
+
type WatchmanCommand = (args: string[], timeoutMs: number) => Promise<unknown>;
|
|
17
41
|
//#endregion
|
|
18
42
|
//#region src/supervisor/run.d.ts
|
|
19
43
|
interface ParsedSupervisorArgs {
|
|
@@ -22,6 +46,7 @@ interface ParsedSupervisorArgs {
|
|
|
22
46
|
tunnel?: boolean;
|
|
23
47
|
resetCache?: boolean;
|
|
24
48
|
idleStopMinutes?: number;
|
|
49
|
+
deviceIdleMinutes?: number;
|
|
25
50
|
error?: string;
|
|
26
51
|
}
|
|
27
52
|
declare function parseArgs(argv: string[]): ParsedSupervisorArgs;
|
|
@@ -45,6 +70,10 @@ type ServerStarter = (opts: {
|
|
|
45
70
|
resetCache?: boolean;
|
|
46
71
|
onTunnelUrl?: ((url: string) => void) | null;
|
|
47
72
|
}) => Promise<ServerHandle>;
|
|
73
|
+
interface DeviceIdleOps {
|
|
74
|
+
due: typeof dueIdleDevices;
|
|
75
|
+
shutDown: typeof shutDownIdleDevices;
|
|
76
|
+
}
|
|
48
77
|
interface RunSupervisorOptions {
|
|
49
78
|
root: string;
|
|
50
79
|
port: number;
|
|
@@ -52,6 +81,8 @@ interface RunSupervisorOptions {
|
|
|
52
81
|
resetCache?: boolean;
|
|
53
82
|
idleStopMinutes?: number;
|
|
54
83
|
idleProbe?: IdleProbe;
|
|
84
|
+
deviceIdleMinutes?: number;
|
|
85
|
+
deviceIdle?: DeviceIdleOps;
|
|
55
86
|
isExpo?: (projectRoot: string) => boolean;
|
|
56
87
|
startBare?: ServerStarter | null;
|
|
57
88
|
startExpo?: ServerStarter | null;
|
|
@@ -59,13 +90,14 @@ interface RunSupervisorOptions {
|
|
|
59
90
|
onExit?: (code: number) => void;
|
|
60
91
|
attachSignals?: boolean;
|
|
61
92
|
stderr?: (line: string) => void;
|
|
93
|
+
watchman?: WatchmanCommand;
|
|
62
94
|
}
|
|
63
|
-
declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, isExpo, startBare, startExpo, now, onExit, attachSignals, stderr }: RunSupervisorOptions): Promise<{
|
|
95
|
+
declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, deviceIdleMinutes, deviceIdle, isExpo, startBare, startExpo, now, onExit, attachSignals, stderr, watchman }: RunSupervisorOptions): Promise<{
|
|
64
96
|
mode: string;
|
|
65
97
|
server: ServerHandle | undefined;
|
|
66
|
-
shutdown: (code: number, event: string, msg: string) => Promise<void>;
|
|
98
|
+
shutdown: (code: number, event: string, msg: string, stop?: DevServerStopRecord) => Promise<void>;
|
|
67
99
|
startedAt: string;
|
|
68
100
|
} | null>;
|
|
69
101
|
declare function main(argv?: string[]): Promise<void>;
|
|
70
102
|
//#endregion
|
|
71
|
-
export { MODE_BARE, MODE_EXPO, RunSupervisorOptions, ServerExitInfo, ServerHandle, clearExpoMetroTunnel, clearWorkspaceSupervisor, main, parseArgs, readPidFile, runSupervisor, writePidFile };
|
|
103
|
+
export { DeviceIdleOps, MODE_BARE, MODE_EXPO, RunSupervisorOptions, ServerExitInfo, ServerHandle, clearExpoMetroTunnel, clearWorkspaceSupervisor, main, parseArgs, readPidFile, runSupervisor, writePidFile };
|
package/dist/supervisor-run.mjs
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import {
|
|
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";
|
|
2
3
|
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { r as detectIsExpo } from "./project-
|
|
4
|
+
import { C as workspaceLogsDir, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
|
|
5
|
+
import { r as detectIsExpo } from "./project-CV3tDFHl.mjs";
|
|
5
6
|
import { t as describeError } from "./errors-B6W7FkxQ.mjs";
|
|
6
|
-
import { t as relaunchWithLogFile } from "./detached-entry-
|
|
7
|
-
import { l as readPidFile, n as MODE_EXPO, p as writePidFile, r as clearExpoMetroTunnel, s as clearWorkspaceSupervisor, t as MODE_BARE } from "./state-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { n as withIdleWorkspace } from "./in-use-
|
|
7
|
+
import { t as relaunchWithLogFile } from "./detached-entry-CiTEgMR1.mjs";
|
|
8
|
+
import { l as readPidFile, n as MODE_EXPO, p as writePidFile, r as clearExpoMetroTunnel, s as clearWorkspaceSupervisor, t as MODE_BARE } from "./state-CaeaHbDA.mjs";
|
|
9
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
|
|
10
|
+
import { n as createActivityReader } from "./activity-B2-kb7k0.mjs";
|
|
11
|
+
import { a as parseLease, r as leaseIsExpired, s as parseWorkspaceLeases, t as deviceLeasePath } from "./device-lease-W5Pi1q38.mjs";
|
|
12
|
+
import { z as ownedAvdSerialResolver } from "./android-Db2eEMaf.mjs";
|
|
13
|
+
import { n as parseTriggerCount, o as runWatchman, p as workspaceBuildInProgress, r as parseWatchRoots, t as parseSubscriberNames } from "./watchman-Bx0wceoF.mjs";
|
|
14
|
+
import { n as withIdleWorkspace } from "./in-use-CndPMilN.mjs";
|
|
15
|
+
import { n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-B5LPaNyY.mjs";
|
|
16
|
+
import { c as vanishedSupervisorMessage, i as devServerStopRecord, r as devServerStopLevel, t as describeDevServerStop } from "./stop-cause-CZ_Mr-v9.mjs";
|
|
14
17
|
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
18
|
+
import { dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
15
19
|
import { LOG_ROTATE_BYTES } from "@stim-cli/core";
|
|
16
|
-
import { IDLE_STOP_KEY } from "@stim-cli/core/state";
|
|
17
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
20
|
+
import { DEV_SERVER_STOP_REQUEST_KEY, IDLE_STOP_KEY, readDevServerStopRequest } from "@stim-cli/core/state";
|
|
18
21
|
import { fileURLToPath } from "node:url";
|
|
19
22
|
//#region src/supervisor/idle-stop.ts
|
|
20
23
|
const IDLE_CHECK_MS = 6e4;
|
|
@@ -125,15 +128,163 @@ function watchIdleDevServer({ idleStopMs, now, serverActivityAt, probe, onIdle,
|
|
|
125
128
|
timer.unref?.();
|
|
126
129
|
return () => clearInterval(timer);
|
|
127
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Checks each minute, once the workspace has gone `idleMs` without a Stim command, whether an owned device is due
|
|
133
|
+
* for idle shutdown, and runs `onDue` for it.
|
|
134
|
+
*/
|
|
135
|
+
function watchIdleDevices({ idleMs, now, lastUseAt, hasDue, onDue, checkMs = IDLE_CHECK_MS }) {
|
|
136
|
+
let deciding = false;
|
|
137
|
+
const timer = setInterval(() => {
|
|
138
|
+
if (deciding || now() - lastUseAt() < idleMs) return;
|
|
139
|
+
let due;
|
|
140
|
+
try {
|
|
141
|
+
due = hasDue();
|
|
142
|
+
} catch {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!due) return;
|
|
146
|
+
deciding = true;
|
|
147
|
+
onDue().finally(() => {
|
|
148
|
+
deciding = false;
|
|
149
|
+
});
|
|
150
|
+
}, Math.min(checkMs, idleMs));
|
|
151
|
+
timer.unref?.();
|
|
152
|
+
return () => clearInterval(timer);
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/supervisor/watchman-roots.ts
|
|
156
|
+
const WATCHMAN_TIMEOUT_MS = 2e3;
|
|
157
|
+
const SHUTDOWN_BUDGET_MS = 3e3;
|
|
158
|
+
const PROBE_DELAYS_MS = [
|
|
159
|
+
3e3,
|
|
160
|
+
6e3,
|
|
161
|
+
1e4,
|
|
162
|
+
15e3,
|
|
163
|
+
2e4,
|
|
164
|
+
3e4,
|
|
165
|
+
45e3,
|
|
166
|
+
6e4,
|
|
167
|
+
12e4,
|
|
168
|
+
3e5
|
|
169
|
+
];
|
|
170
|
+
function canonical(path) {
|
|
171
|
+
try {
|
|
172
|
+
return realpathSync(path);
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function newRootsContaining(before, current, workspaceRoot) {
|
|
178
|
+
const seen = new Set(before.map((root) => canonical(root) ?? root));
|
|
179
|
+
return current.filter((root) => {
|
|
180
|
+
const resolved = canonical(root);
|
|
181
|
+
if (resolved === null || seen.has(resolved)) return false;
|
|
182
|
+
return workspaceRoot === resolved || workspaceRoot.startsWith(resolved.endsWith(sep) ? resolved : resolved + sep);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function metroSubscriptionPrefix(pid) {
|
|
186
|
+
return `metro-file-map-${pid}-`;
|
|
187
|
+
}
|
|
188
|
+
async function watchRoots(watchman) {
|
|
189
|
+
try {
|
|
190
|
+
return parseWatchRoots(await watchman(["watch-list"]));
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function subscriberNames(watchman, root) {
|
|
196
|
+
try {
|
|
197
|
+
return parseSubscriberNames(await watchman(["debug-get-subscriptions", root]));
|
|
198
|
+
} catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function triggerCount(watchman, root) {
|
|
203
|
+
try {
|
|
204
|
+
return parseTriggerCount(await watchman(["trigger-list", root]));
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function trackMetroWatchRoots({ workspaceRoot, writer, watchman = runWatchman, probeDelaysMs = PROBE_DELAYS_MS }) {
|
|
210
|
+
let deadline = Infinity;
|
|
211
|
+
const call = async (args) => {
|
|
212
|
+
const left = deadline - Date.now();
|
|
213
|
+
if (left <= 0) throw new Error("the watchman cleanup ran out of time");
|
|
214
|
+
return watchman(args, Math.min(WATCHMAN_TIMEOUT_MS, left));
|
|
215
|
+
};
|
|
216
|
+
const before = watchRoots(call);
|
|
217
|
+
const owned = /* @__PURE__ */ new Set();
|
|
218
|
+
const timers = [];
|
|
219
|
+
let prefix = null;
|
|
220
|
+
const probe = async () => {
|
|
221
|
+
const earlier = await before;
|
|
222
|
+
if (prefix === null || earlier === null) return;
|
|
223
|
+
const current = await watchRoots(call);
|
|
224
|
+
if (current === null) return;
|
|
225
|
+
for (const root of newRootsContaining(earlier, current, workspaceRoot)) {
|
|
226
|
+
if (owned.has(root)) continue;
|
|
227
|
+
if ((await subscriberNames(call, root))?.some((name) => name.startsWith(prefix))) owned.add(root);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
return {
|
|
231
|
+
started(metroPid) {
|
|
232
|
+
prefix = metroSubscriptionPrefix(metroPid);
|
|
233
|
+
for (const delay of probeDelaysMs) {
|
|
234
|
+
const timer = setTimeout(() => void probe(), delay);
|
|
235
|
+
timer.unref?.();
|
|
236
|
+
timers.push(timer);
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
async beforeClose() {
|
|
240
|
+
for (const timer of timers) clearTimeout(timer);
|
|
241
|
+
deadline = Date.now() + SHUTDOWN_BUDGET_MS;
|
|
242
|
+
await probe();
|
|
243
|
+
},
|
|
244
|
+
async afterClose() {
|
|
245
|
+
for (const root of owned) {
|
|
246
|
+
const others = (await subscriberNames(call, root))?.filter((name) => !name.startsWith(prefix));
|
|
247
|
+
const triggers = others?.length === 0 ? await triggerCount(call, root) : null;
|
|
248
|
+
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;
|
|
249
|
+
if (reason) {
|
|
250
|
+
writer.write({
|
|
251
|
+
src: "metro",
|
|
252
|
+
level: "debug",
|
|
253
|
+
event: "watchman_root_kept",
|
|
254
|
+
msg: `kept the watchman root ${root}: ${reason}`
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
await call(["watch-del", root]);
|
|
260
|
+
writer.write({
|
|
261
|
+
src: "metro",
|
|
262
|
+
level: "info",
|
|
263
|
+
event: "watchman_root_removed",
|
|
264
|
+
msg: `removed the watchman root ${root} that this dev server registered`
|
|
265
|
+
});
|
|
266
|
+
} catch (err) {
|
|
267
|
+
writer.write({
|
|
268
|
+
src: "metro",
|
|
269
|
+
level: "warn",
|
|
270
|
+
event: "watchman_root_kept",
|
|
271
|
+
msg: `could not remove the watchman root ${root}: ${describeError(err)}`
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
128
278
|
//#endregion
|
|
129
279
|
//#region src/supervisor/run.ts
|
|
130
|
-
const USAGE = "Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache] [--idle-stop-minutes <n>]";
|
|
280
|
+
const USAGE = "Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache] [--idle-stop-minutes <n>] [--device-idle-minutes <n>]";
|
|
131
281
|
function parseArgs(argv) {
|
|
132
282
|
let root;
|
|
133
283
|
let port;
|
|
134
284
|
let tunnel = false;
|
|
135
285
|
let resetCache = false;
|
|
136
286
|
let idleStopMinutes = "0";
|
|
287
|
+
let deviceIdleMinutes = "0";
|
|
137
288
|
for (let i = 0; i < argv.length; i++) {
|
|
138
289
|
const arg = argv[i];
|
|
139
290
|
if (arg === "--root") {
|
|
@@ -156,22 +307,31 @@ function parseArgs(argv) {
|
|
|
156
307
|
idleStopMinutes = argv[++i] ?? "";
|
|
157
308
|
continue;
|
|
158
309
|
}
|
|
310
|
+
if (arg === "--device-idle-minutes") {
|
|
311
|
+
deviceIdleMinutes = argv[++i] ?? "";
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
159
314
|
return { error: `Unknown supervisor argument "${arg}". ${USAGE}` };
|
|
160
315
|
}
|
|
161
316
|
if (!root) return { error: `Missing --root. ${USAGE}` };
|
|
162
317
|
if (!isAbsolute(root)) return { error: `--root must be an absolute path, got "${root}".` };
|
|
163
318
|
const parsedPort = Number(port);
|
|
164
319
|
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) return { error: `--port must be a TCP port number, got "${port}".` };
|
|
165
|
-
if (!/^\d+$/.test(
|
|
320
|
+
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}".` };
|
|
166
321
|
return {
|
|
167
322
|
root: resolve(root),
|
|
168
323
|
port: parsedPort,
|
|
169
324
|
tunnel,
|
|
170
325
|
resetCache,
|
|
171
|
-
idleStopMinutes: Number(idleStopMinutes)
|
|
326
|
+
idleStopMinutes: Number(idleStopMinutes),
|
|
327
|
+
deviceIdleMinutes: Number(deviceIdleMinutes)
|
|
172
328
|
};
|
|
173
329
|
}
|
|
174
|
-
|
|
330
|
+
const DEVICE_IDLE_OPS = {
|
|
331
|
+
due: dueIdleDevices,
|
|
332
|
+
shutDown: shutDownIdleDevices
|
|
333
|
+
};
|
|
334
|
+
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 }) {
|
|
175
335
|
root = realpathSync(root);
|
|
176
336
|
const logsDir = workspaceLogsDir(root);
|
|
177
337
|
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
@@ -191,6 +351,13 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
191
351
|
mode,
|
|
192
352
|
startedAt
|
|
193
353
|
};
|
|
354
|
+
const vanished = vanishedSupervisorMessage(readWorkspaceState$1(root)?.supervisor);
|
|
355
|
+
if (vanished) writer.write({
|
|
356
|
+
src: "metro",
|
|
357
|
+
level: "warn",
|
|
358
|
+
event: "supervisor_vanished",
|
|
359
|
+
msg: vanished
|
|
360
|
+
});
|
|
194
361
|
clearExpoMetroTunnel(root);
|
|
195
362
|
writePidFile(root, process.pid);
|
|
196
363
|
writeWorkspaceState(root, { supervisor: record });
|
|
@@ -214,14 +381,29 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
214
381
|
});
|
|
215
382
|
let stopping = false;
|
|
216
383
|
let stopWatchingIdle = null;
|
|
217
|
-
|
|
384
|
+
let stopWatchingDevices = null;
|
|
385
|
+
const stopCause = (trigger) => {
|
|
386
|
+
const request = readDevServerStopRequest(readWorkspaceState$1(root));
|
|
387
|
+
return devServerStopRecord(trigger, request?.processToken === processToken ? request : null, new Date(now()).toISOString());
|
|
388
|
+
};
|
|
389
|
+
const finish = (code, event, level, msg, stop) => {
|
|
218
390
|
stopWatchingIdle?.();
|
|
391
|
+
stopWatchingDevices?.();
|
|
219
392
|
writer.write({
|
|
220
393
|
src: "metro",
|
|
221
394
|
level,
|
|
222
395
|
event,
|
|
223
|
-
msg
|
|
396
|
+
msg,
|
|
397
|
+
...stop ? { stop } : {}
|
|
224
398
|
});
|
|
399
|
+
try {
|
|
400
|
+
withWorkspaceStateLock(root, () => {
|
|
401
|
+
const current = readWorkspaceState$1(root)?.supervisor;
|
|
402
|
+
if (current && current.processToken !== processToken) return;
|
|
403
|
+
if (stop) writeWorkspaceState(root, { [IDLE_STOP_KEY]: stop });
|
|
404
|
+
clearWorkspaceStateKeys(root, [DEV_SERVER_STOP_REQUEST_KEY]);
|
|
405
|
+
});
|
|
406
|
+
} catch {}
|
|
225
407
|
try {
|
|
226
408
|
clearSupervisor(root, record);
|
|
227
409
|
} catch {}
|
|
@@ -233,10 +415,17 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
233
415
|
onExit(code);
|
|
234
416
|
};
|
|
235
417
|
let server;
|
|
236
|
-
const
|
|
418
|
+
const watchRoots = trackMetroWatchRoots({
|
|
419
|
+
workspaceRoot: root,
|
|
420
|
+
writer,
|
|
421
|
+
watchman
|
|
422
|
+
});
|
|
423
|
+
const shutdown = async (code, event, msg, stop) => {
|
|
237
424
|
if (stopping || !server) return;
|
|
238
425
|
stopping = true;
|
|
239
426
|
stopWatchingIdle?.();
|
|
427
|
+
stopWatchingDevices?.();
|
|
428
|
+
await watchRoots.beforeClose();
|
|
240
429
|
try {
|
|
241
430
|
await server.close();
|
|
242
431
|
} catch (err) {
|
|
@@ -247,16 +436,25 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
247
436
|
msg: describeError(err)
|
|
248
437
|
});
|
|
249
438
|
}
|
|
250
|
-
|
|
439
|
+
await watchRoots.afterClose();
|
|
440
|
+
finish(code, event, stop ? devServerStopLevel(stop) : code === 0 ? "info" : "error", msg, stop);
|
|
251
441
|
};
|
|
252
442
|
if (attachSignals) for (const signal of ["SIGTERM", "SIGINT"]) process.on(signal, () => {
|
|
253
443
|
if (server) {
|
|
254
|
-
|
|
444
|
+
const stop = stopCause({
|
|
445
|
+
kind: "signal",
|
|
446
|
+
signal
|
|
447
|
+
});
|
|
448
|
+
shutdown(0, "supervisor_stopped", `stopping the ${mode} dev server: ${describeDevServerStop(stop)}`, stop);
|
|
255
449
|
return;
|
|
256
450
|
}
|
|
257
451
|
if (stopping) return;
|
|
258
452
|
stopping = true;
|
|
259
|
-
|
|
453
|
+
const stop = stopCause({
|
|
454
|
+
kind: "signal",
|
|
455
|
+
signal
|
|
456
|
+
});
|
|
457
|
+
finish(signal === "SIGINT" ? 130 : 143, "supervisor_stopped", "warn", `stopping before the ${mode} dev server started: ${describeDevServerStop(stop)}`, stop);
|
|
260
458
|
});
|
|
261
459
|
const serverActivity = trackDevServerActivity(now);
|
|
262
460
|
const serverWriter = Object.assign(Object.create(writer), { write(entry) {
|
|
@@ -264,7 +462,7 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
264
462
|
return writer.write(entry);
|
|
265
463
|
} });
|
|
266
464
|
try {
|
|
267
|
-
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-
|
|
465
|
+
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-KJeD109I.mjs")).startExpoServer : startBare || (await import("./server-bare-X7PUgizL.mjs")).startBareServer)({
|
|
268
466
|
root,
|
|
269
467
|
port,
|
|
270
468
|
logsDir,
|
|
@@ -313,12 +511,45 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
313
511
|
} });
|
|
314
512
|
});
|
|
315
513
|
}
|
|
514
|
+
watchRoots.started(serverPid ?? process.pid);
|
|
316
515
|
writer.write({
|
|
317
516
|
src: "metro",
|
|
318
517
|
level: "info",
|
|
319
518
|
event: "server_started",
|
|
320
519
|
msg: `${mode} dev server listening on port ${port}`
|
|
321
520
|
});
|
|
521
|
+
const deviceIdleMs = deviceIdleMinutes * 6e4;
|
|
522
|
+
const workspaceProbe = workspaceIdleProbe(root);
|
|
523
|
+
const shutDownIdleDevices = (idleMs) => deviceIdle.shutDown(root, idleMs, (entry) => writer.write({
|
|
524
|
+
src: "metro",
|
|
525
|
+
...entry
|
|
526
|
+
}));
|
|
527
|
+
if (deviceIdleMinutes > 0) stopWatchingDevices = watchIdleDevices({
|
|
528
|
+
idleMs: deviceIdleMs,
|
|
529
|
+
now,
|
|
530
|
+
lastUseAt: () => {
|
|
531
|
+
let deviceLog = NaN;
|
|
532
|
+
try {
|
|
533
|
+
deviceLog = statSync(join(logsDir, "device.ndjson")).mtimeMs;
|
|
534
|
+
} catch {}
|
|
535
|
+
const times = [workspaceProbe.lastActivityAt(), deviceLog].filter(Number.isFinite);
|
|
536
|
+
return times.length ? Math.max(...times) : NaN;
|
|
537
|
+
},
|
|
538
|
+
hasDue: () => deviceIdle.due(root, deviceIdleMs).length > 0,
|
|
539
|
+
onDue: async () => {
|
|
540
|
+
try {
|
|
541
|
+
await withIdleWorkspace(root, () => {
|
|
542
|
+
if (!stopping) shutDownIdleDevices(deviceIdleMs);
|
|
543
|
+
}, {
|
|
544
|
+
purpose: "device idle shutdown",
|
|
545
|
+
supervisor: false,
|
|
546
|
+
managedLocks: false
|
|
547
|
+
});
|
|
548
|
+
} catch (err) {
|
|
549
|
+
stderr(`Stim supervisor: could not shut down idle devices: ${describeError(err)}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
});
|
|
322
553
|
if (idleStopMinutes > 0) stopWatchingIdle = watchIdleDevServer({
|
|
323
554
|
idleStopMs: idleStopMinutes * 6e4,
|
|
324
555
|
now,
|
|
@@ -328,14 +559,20 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
328
559
|
const stopIfStillIdle = async () => {
|
|
329
560
|
const idleMinutes = idleMinutesNow();
|
|
330
561
|
if (stopping || idleMinutes === null) return;
|
|
562
|
+
if (deviceIdleMinutes > 0) try {
|
|
563
|
+
shutDownIdleDevices(Math.min(deviceIdleMs, idleStopMinutes * 6e4));
|
|
564
|
+
} catch (err) {
|
|
565
|
+
stderr(`Stim supervisor: could not shut down idle devices: ${describeError(err)}`);
|
|
566
|
+
}
|
|
567
|
+
const stop = {
|
|
568
|
+
reason: "idle",
|
|
569
|
+
at: new Date(now()).toISOString(),
|
|
570
|
+
idleMinutes
|
|
571
|
+
};
|
|
331
572
|
withWorkspaceStateLock(root, () => {
|
|
332
|
-
if (readWorkspaceState$1(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { [IDLE_STOP_KEY]:
|
|
333
|
-
reason: "idle",
|
|
334
|
-
at: new Date(now()).toISOString(),
|
|
335
|
-
idleMinutes
|
|
336
|
-
} });
|
|
573
|
+
if (readWorkspaceState$1(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { [IDLE_STOP_KEY]: stop });
|
|
337
574
|
});
|
|
338
|
-
await shutdown(0, "supervisor_idle_stopped", `no bundle request, client log or Stim command for ${idleMinutes} minutes (metro.idleStopMinutes is ${idleStopMinutes}); stopped the ${mode} dev server
|
|
575
|
+
await shutdown(0, "supervisor_idle_stopped", `no bundle request, client log or Stim command for ${idleMinutes} minutes (metro.idleStopMinutes is ${idleStopMinutes}); stopped the ${mode} dev server`, stop);
|
|
339
576
|
};
|
|
340
577
|
try {
|
|
341
578
|
await withIdleWorkspace(root, () => withWorkspaceProcessLock(dirname(logsDir), "metro-start", stopIfStillIdle, {
|
|
@@ -354,8 +591,13 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
354
591
|
});
|
|
355
592
|
server.onExit?.((info) => {
|
|
356
593
|
if (stopping) return;
|
|
357
|
-
const
|
|
358
|
-
|
|
594
|
+
const stop = stopCause({
|
|
595
|
+
kind: "server-exit",
|
|
596
|
+
mode,
|
|
597
|
+
code: info?.code ?? null,
|
|
598
|
+
signal: info?.signal ?? null
|
|
599
|
+
});
|
|
600
|
+
shutdown(stop.reason === "requested" ? 0 : 1, "supervisor_stopped", stop.reason === "requested" ? `the ${mode} dev server exited; ${describeDevServerStop(stop)}` : `${describeDevServerStop(stop)}; shutting the supervisor down`, stop);
|
|
359
601
|
});
|
|
360
602
|
return {
|
|
361
603
|
mode,
|
|
@@ -387,7 +629,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
387
629
|
port: parsed.port,
|
|
388
630
|
tunnel: parsed.tunnel ?? false,
|
|
389
631
|
resetCache: parsed.resetCache ?? false,
|
|
390
|
-
idleStopMinutes: parsed.idleStopMinutes ?? 0
|
|
632
|
+
idleStopMinutes: parsed.idleStopMinutes ?? 0,
|
|
633
|
+
deviceIdleMinutes: parsed.deviceIdleMinutes ?? 0
|
|
391
634
|
});
|
|
392
635
|
}
|
|
393
636
|
function invokedDirectly() {
|