stim 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -155
- package/dist/{android-DWssqHQ8.mjs → android-787HhP5w.mjs} +168 -39
- package/dist/{android-BRgBYzU0.mjs → android-DBkeHwpm.mjs} +250 -200
- package/dist/{android-DeYdjjBP.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-CITmIeWY.mjs} +22 -14
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/app-install-CrJ6t_bv.mjs +819 -0
- package/dist/budget-BP4jZZL4.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Pubfp8wV.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +7 -1
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-D5z2_bcF.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-BEq0Qw_a.mjs} +134 -121
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-DP4eWqea.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-92U593KT.mjs} +1090 -660
- package/dist/{device-RdujjHLB.mjs → device-DhTZe7L4.mjs} +13 -20
- package/dist/{build-lock-CgtsB6TV.mjs → device-lease-CbEaIk7b.mjs} +481 -27
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-Di8Q-9Ro.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-Dy1jGj3U.mjs} +645 -119
- package/dist/{doctor-BMt156qe.mjs → doctor-B-inAJmt.mjs} +137 -113
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-xxWKNO3-.mjs} +22 -17
- package/dist/exec-DK8KaVHK.mjs +133 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-ChPFZMRC.mjs} +836 -813
- package/dist/{guide-BTAlD1_y.mjs → guide-DwmaD_Wa.mjs} +953 -209
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle-DpRLp5lj.mjs +157 -0
- package/dist/{build-slots-C-oAHRT1.mjs → in-use-CjUluqIX.mjs} +102 -8
- package/dist/{ios-BcCiI4TS.mjs → ios-B2Fpqvlb.mjs} +60 -71
- package/dist/{ios-BP04pY5f.mjs → ios-Dd-hYJBh.mjs} +241 -234
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-BiOsSVzd.mjs} +3 -2
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-CtRdEVjx.mjs} +149 -52
- package/dist/launch-verify-CQS_Kg-C.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-MARIy6m9.mjs} +20 -15
- package/dist/metro-BWLOJ_Wr.mjs +409 -0
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-CDY9IkVC.mjs} +23 -43
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/{teardown-BJqEzPo_.mjs → ownership-DZjdx8Gq.mjs} +664 -612
- package/dist/{ports-BIbJaKNW.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-BXZzOABt.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-DoETJ3rl.mjs} +11 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DVbb7kXH.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-BvOCeakp.mjs} +8 -7
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-BXXorVM2.mjs → settings-DOugPlPz.mjs} +59 -159
- package/dist/settings-EWYNwe72.mjs +378 -0
- package/dist/settings.schema.json +1064 -0
- package/dist/simslim-Ca3487H6.mjs +436 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
- package/dist/spawn-claims-CUleC2cM.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-F9gv5dcC.mjs} +159 -114
- package/dist/start-VoFsPSes.mjs +2 -0
- package/dist/{state-DZobzxLW.mjs → state-WGdIbi_d.mjs} +5 -3
- package/dist/{stats-BYcZ6n1h.mjs → stats-BAgJaLA4.mjs} +66 -5
- package/dist/{stats-CLg5RuDS.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/status-DLCD-o3s.mjs +764 -0
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{guide-status-Craq9z0t.mjs → stim-installations-CINXy_su.mjs} +3 -122
- package/dist/{stop-C8JW6kKp.mjs → stop-Dj4pfmyv.mjs} +111 -31
- package/dist/{stop-B1kOpYei.mjs → stop-ZvOeTmKb.mjs} +2 -2
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +228 -42
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-BXA96myD.mjs} +14 -9
- package/dist/workspaces-BTUyFfkv.mjs +1003 -0
- package/dist/worktree-4aZg2NnI.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-BMS7GeqB.mjs} +523 -61
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-BlizKDpZ.mjs} +200 -54
- package/dist/{xcode-B6YaWeg0.mjs → xcode-B2tBkf0m.mjs} +66 -57
- package/package.json +6 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/device-lease-Ffz_M5t0.mjs +0 -359
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/logs-query-BGL-Pl12.mjs +0 -290
- package/dist/metro-C7bcJ0uo.mjs +0 -233
- package/dist/ownership-wolE-0Do.mjs +0 -470
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/workspace-state-BT5E3SA2.mjs +0 -146
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
package/dist/supervisor-run.mjs
CHANGED
|
@@ -1,19 +1,139 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
3
|
-
import { _ as workspaceLogsDir,
|
|
4
|
-
import {
|
|
1
|
+
import { B as parseDeviceSlotKey, C as setSupervisor, D as process_identity_exports, H as projectDeviceSlots, a as clearSupervisor, f as getProject } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
3
|
+
import { _ as withWorkspaceStateLock, j as workspaceLogsDir, m as readWorkspaceState$1, p as clearWorkspaceStateKeys, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
|
|
4
|
+
import { a as detectIsExpo } from "./project-BXZzOABt.mjs";
|
|
5
5
|
import { t as describeError } from "./errors-B6W7FkxQ.mjs";
|
|
6
|
-
import { t as relaunchWithLogFile } from "./detached-entry-
|
|
7
|
-
import { c as readPidFile, f as writePidFile, n as MODE_EXPO, o as clearWorkspaceSupervisor, r as clearExpoMetroTunnel, t as MODE_BARE } from "./state-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { t as relaunchWithLogFile } from "./detached-entry-DJHoca49.mjs";
|
|
7
|
+
import { c as readPidFile, f as writePidFile, n as MODE_EXPO, o as clearWorkspaceSupervisor, r as clearExpoMetroTunnel, t as MODE_BARE } from "./state-WGdIbi_d.mjs";
|
|
8
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
|
|
9
|
+
import { a as parseLease, r as leaseIsExpired, s as parseWorkspaceLeases, t as deviceLeasePath } from "./device-lease-CbEaIk7b.mjs";
|
|
10
|
+
import { c as createActivityReader } from "./build-progress-BXx-ZBe4.mjs";
|
|
11
|
+
import { N as ownedAvdSerialResolver } from "./android-787HhP5w.mjs";
|
|
12
|
+
import { s as workspaceBuildInProgress } from "./idle-DpRLp5lj.mjs";
|
|
13
|
+
import { n as withIdleWorkspace } from "./in-use-CjUluqIX.mjs";
|
|
14
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
15
|
+
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";
|
|
10
18
|
import { fileURLToPath } from "node:url";
|
|
19
|
+
//#region src/supervisor/idle-stop.ts
|
|
20
|
+
const IDLE_CHECK_MS = 6e4;
|
|
21
|
+
const MINUTE_MS = 6e4;
|
|
22
|
+
function trackDevServerActivity(now) {
|
|
23
|
+
let last = now();
|
|
24
|
+
const open = /* @__PURE__ */ new Set();
|
|
25
|
+
return {
|
|
26
|
+
record(entry) {
|
|
27
|
+
const { event, requestId } = entry ?? {};
|
|
28
|
+
if (event === "bundle_response_started") {
|
|
29
|
+
if (typeof requestId === "string") open.add(requestId);
|
|
30
|
+
} else if (event === "bundle_response_finished" || event === "bundle_response_failed") {
|
|
31
|
+
if (typeof requestId === "string") open.delete(requestId);
|
|
32
|
+
} else if (event !== "expo_stdout") return;
|
|
33
|
+
last = now();
|
|
34
|
+
},
|
|
35
|
+
lastActivityAt: () => open.size > 0 ? now() : last
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function deviceTargets(root) {
|
|
39
|
+
const serialOf = ownedAvdSerialResolver({ timeoutMs: 5e3 });
|
|
40
|
+
return projectDeviceSlots(getProject(root)).flatMap(({ slot, platforms }) => {
|
|
41
|
+
const targets = [];
|
|
42
|
+
if (platforms.ios?.deviceUdid) targets.push({
|
|
43
|
+
platform: "ios",
|
|
44
|
+
id: platforms.ios.deviceUdid,
|
|
45
|
+
slot
|
|
46
|
+
});
|
|
47
|
+
const android = platforms.android;
|
|
48
|
+
const serial = android?.avdName ? serialOf(android.avdName).serial : android?.serial;
|
|
49
|
+
if (serial) targets.push({
|
|
50
|
+
platform: "android",
|
|
51
|
+
id: serial,
|
|
52
|
+
slot
|
|
53
|
+
});
|
|
54
|
+
return targets;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function heldDeviceLease(root, now) {
|
|
58
|
+
for (const [key, record] of Object.entries(parseWorkspaceLeases(readWorkspaceState$1(root)?.deviceLeases))) {
|
|
59
|
+
const platform = parseDeviceSlotKey(key)?.platform;
|
|
60
|
+
if (!platform) continue;
|
|
61
|
+
let raw;
|
|
62
|
+
try {
|
|
63
|
+
raw = readFileSync(deviceLeasePath(platform, record.id), "utf8");
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error.code === "ENOENT") continue;
|
|
66
|
+
return `${platform} device ${record.id} has a lease that cannot be read (${describeError(error)})`;
|
|
67
|
+
}
|
|
68
|
+
const lease = parseLease(raw);
|
|
69
|
+
if (!lease) return `${platform} device ${record.id} has a lease that cannot be read`;
|
|
70
|
+
if (lease.token !== record.token || leaseIsExpired(lease, now)) continue;
|
|
71
|
+
const by = record.kind === "declared" ? "stim device lock" : "a stim ios or android run";
|
|
72
|
+
return `${platform} device ${record.id} is leased by ${by} until ${lease.expiresAt}`;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function workspaceIdleProbe(root, { platform = process.platform } = {}) {
|
|
77
|
+
return {
|
|
78
|
+
lastActivityAt() {
|
|
79
|
+
const used = Date.parse(String(readWorkspaceState$1(root)?.lastUsedAt ?? ""));
|
|
80
|
+
let clientLog = NaN;
|
|
81
|
+
try {
|
|
82
|
+
clientLog = statSync(join(workspaceLogsDir(root), "client.ndjson")).mtimeMs;
|
|
83
|
+
} catch {}
|
|
84
|
+
const times = [used, clientLog].filter(Number.isFinite);
|
|
85
|
+
return times.length ? Math.max(...times) : NaN;
|
|
86
|
+
},
|
|
87
|
+
blocker() {
|
|
88
|
+
if (workspaceBuildInProgress(root)) return "a build is in progress";
|
|
89
|
+
const lease = heldDeviceLease(root, Date.now());
|
|
90
|
+
if (lease) return lease;
|
|
91
|
+
const readActivity = createActivityReader();
|
|
92
|
+
for (const target of deviceTargets(root)) {
|
|
93
|
+
const activity = readActivity({
|
|
94
|
+
...target,
|
|
95
|
+
workspace: root
|
|
96
|
+
});
|
|
97
|
+
if (activity.state === "driven") return `${target.platform} device ${target.id} is driven by ${activity.driver?.tool ?? "an unknown tool"}`;
|
|
98
|
+
const unknown = platform === "win32" ? activity.basis.filter((basis) => basis !== "driver-process") : activity.basis;
|
|
99
|
+
if (activity.state === "unknown" && unknown.length > 0) return `${target.platform} device ${target.id} has unknown activity (${unknown.join(", ")})`;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function watchIdleDevServer({ idleStopMs, now, serverActivityAt, probe, onIdle, checkMs = IDLE_CHECK_MS }) {
|
|
106
|
+
const idleMinutes = () => {
|
|
107
|
+
const last = Math.max(serverActivityAt(), ...[probe.lastActivityAt()].filter(Number.isFinite));
|
|
108
|
+
if (now() - last < idleStopMs) return null;
|
|
109
|
+
let blocker;
|
|
110
|
+
try {
|
|
111
|
+
blocker = probe.blocker();
|
|
112
|
+
} catch (error) {
|
|
113
|
+
blocker = describeError(error);
|
|
114
|
+
}
|
|
115
|
+
return blocker ? null : Math.floor((now() - last) / MINUTE_MS);
|
|
116
|
+
};
|
|
117
|
+
let deciding = false;
|
|
118
|
+
const timer = setInterval(() => {
|
|
119
|
+
if (deciding || idleMinutes() === null) return;
|
|
120
|
+
deciding = true;
|
|
121
|
+
onIdle(idleMinutes).finally(() => {
|
|
122
|
+
deciding = false;
|
|
123
|
+
});
|
|
124
|
+
}, Math.min(checkMs, idleStopMs));
|
|
125
|
+
timer.unref?.();
|
|
126
|
+
return () => clearInterval(timer);
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
11
129
|
//#region src/supervisor/run.ts
|
|
130
|
+
const USAGE = "Usage: run.js --root <path> --port <n> [--tunnel] [--reset-cache] [--idle-stop-minutes <n>]";
|
|
12
131
|
function parseArgs(argv) {
|
|
13
132
|
let root;
|
|
14
133
|
let port;
|
|
15
134
|
let tunnel = false;
|
|
16
135
|
let resetCache = false;
|
|
136
|
+
let idleStopMinutes = "0";
|
|
17
137
|
for (let i = 0; i < argv.length; i++) {
|
|
18
138
|
const arg = argv[i];
|
|
19
139
|
if (arg === "--root") {
|
|
@@ -32,23 +152,29 @@ function parseArgs(argv) {
|
|
|
32
152
|
resetCache = true;
|
|
33
153
|
continue;
|
|
34
154
|
}
|
|
35
|
-
|
|
155
|
+
if (arg === "--idle-stop-minutes") {
|
|
156
|
+
idleStopMinutes = argv[++i] ?? "";
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
return { error: `Unknown supervisor argument "${arg}". ${USAGE}` };
|
|
36
160
|
}
|
|
37
|
-
if (!root) return { error:
|
|
161
|
+
if (!root) return { error: `Missing --root. ${USAGE}` };
|
|
38
162
|
if (!isAbsolute(root)) return { error: `--root must be an absolute path, got "${root}".` };
|
|
39
163
|
const parsedPort = Number(port);
|
|
40
164
|
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) return { error: `--port must be a TCP port number, got "${port}".` };
|
|
165
|
+
if (!/^\d+$/.test(idleStopMinutes)) return { error: `--idle-stop-minutes must be a whole number of minutes, got "${idleStopMinutes}".` };
|
|
41
166
|
return {
|
|
42
167
|
root: resolve(root),
|
|
43
168
|
port: parsedPort,
|
|
44
169
|
tunnel,
|
|
45
|
-
resetCache
|
|
170
|
+
resetCache,
|
|
171
|
+
idleStopMinutes: Number(idleStopMinutes)
|
|
46
172
|
};
|
|
47
173
|
}
|
|
48
|
-
async function runSupervisor({ root, port, tunnel = false, resetCache = false, isExpo = detectIsExpo, startBare = null, startExpo = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line) }) {
|
|
174
|
+
async function runSupervisor({ root, port, tunnel = false, resetCache = false, idleStopMinutes = 0, idleProbe, isExpo = detectIsExpo, startBare = null, startExpo = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line) }) {
|
|
49
175
|
root = realpathSync(root);
|
|
50
176
|
const logsDir = workspaceLogsDir(root);
|
|
51
|
-
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"));
|
|
177
|
+
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
52
178
|
const mode = isExpo(root) ? MODE_EXPO : MODE_BARE;
|
|
53
179
|
const startedAt = new Date(now()).toISOString();
|
|
54
180
|
const processToken = (0, process_identity_exports.captureProcessToken)(process.pid);
|
|
@@ -68,6 +194,7 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
68
194
|
clearExpoMetroTunnel(root);
|
|
69
195
|
writePidFile(root, process.pid);
|
|
70
196
|
writeWorkspaceState(root, { supervisor: record });
|
|
197
|
+
clearWorkspaceStateKeys(root, [IDLE_STOP_KEY]);
|
|
71
198
|
try {
|
|
72
199
|
setSupervisor(root, record);
|
|
73
200
|
} catch (err) {
|
|
@@ -86,7 +213,9 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
86
213
|
msg: `supervisor pid ${process.pid} starting the ${mode} dev server on port ${port} for ${root}`
|
|
87
214
|
});
|
|
88
215
|
let stopping = false;
|
|
216
|
+
let stopWatchingIdle = null;
|
|
89
217
|
const finish = (code, event, level, msg) => {
|
|
218
|
+
stopWatchingIdle?.();
|
|
90
219
|
writer.write({
|
|
91
220
|
src: "metro",
|
|
92
221
|
level,
|
|
@@ -104,18 +233,48 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
104
233
|
onExit(code);
|
|
105
234
|
};
|
|
106
235
|
let server;
|
|
236
|
+
const shutdown = async (code, event, msg) => {
|
|
237
|
+
if (stopping || !server) return;
|
|
238
|
+
stopping = true;
|
|
239
|
+
stopWatchingIdle?.();
|
|
240
|
+
try {
|
|
241
|
+
await server.close();
|
|
242
|
+
} catch (err) {
|
|
243
|
+
writer.write({
|
|
244
|
+
src: "metro",
|
|
245
|
+
level: "warn",
|
|
246
|
+
event: "server_close_failed",
|
|
247
|
+
msg: describeError(err)
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
finish(code, event, code === 0 ? "info" : "error", msg);
|
|
251
|
+
};
|
|
252
|
+
if (attachSignals) for (const signal of ["SIGTERM", "SIGINT"]) process.on(signal, () => {
|
|
253
|
+
if (server) {
|
|
254
|
+
shutdown(0, "supervisor_stopped", `received ${signal}; stopping the ${mode} dev server`);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (stopping) return;
|
|
258
|
+
stopping = true;
|
|
259
|
+
finish(signal === "SIGINT" ? 130 : 143, "supervisor_stopped", "warn", `received ${signal} before the ${mode} dev server started; stopping`);
|
|
260
|
+
});
|
|
261
|
+
const serverActivity = trackDevServerActivity(now);
|
|
262
|
+
const serverWriter = Object.assign(Object.create(writer), { write(entry) {
|
|
263
|
+
serverActivity.record(entry);
|
|
264
|
+
return writer.write(entry);
|
|
265
|
+
} });
|
|
107
266
|
try {
|
|
108
|
-
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-
|
|
267
|
+
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-DBVTdult.mjs")).startExpoServer : startBare || (await import("./server-bare-DVbb7kXH.mjs")).startBareServer)({
|
|
109
268
|
root,
|
|
110
269
|
port,
|
|
111
270
|
logsDir,
|
|
112
|
-
writer,
|
|
271
|
+
writer: serverWriter,
|
|
113
272
|
tunnel,
|
|
114
273
|
resetCache,
|
|
115
274
|
onTunnelUrl: (url) => {
|
|
116
275
|
try {
|
|
117
276
|
withWorkspaceStateLock(root, () => {
|
|
118
|
-
if (readWorkspaceState(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { metroTunnel: {
|
|
277
|
+
if (readWorkspaceState$1(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { metroTunnel: {
|
|
119
278
|
kind: "expo",
|
|
120
279
|
url
|
|
121
280
|
} });
|
|
@@ -132,46 +291,72 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
132
291
|
}
|
|
133
292
|
});
|
|
134
293
|
} catch (err) {
|
|
294
|
+
if (stopping) return null;
|
|
135
295
|
stderr(`Stim supervisor: failed to start the ${mode} dev server: ${describeError(err)}`);
|
|
136
296
|
finish(1, "supervisor_failed", "fatal", `failed to start the ${mode} dev server: ${describeError(err)}`);
|
|
137
297
|
return null;
|
|
138
298
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
299
|
+
if (stopping) {
|
|
300
|
+
try {
|
|
301
|
+
await server.close();
|
|
302
|
+
} catch {}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const serverPid = server.serverPid;
|
|
306
|
+
if (serverPid) {
|
|
307
|
+
const serverProcessToken = (0, process_identity_exports.captureProcessToken)(serverPid);
|
|
308
|
+
withWorkspaceStateLock(root, () => {
|
|
309
|
+
if (readWorkspaceState$1(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { supervisor: {
|
|
310
|
+
...record,
|
|
311
|
+
serverPid,
|
|
312
|
+
...serverProcessToken ? { serverProcessToken } : {}
|
|
313
|
+
} });
|
|
314
|
+
});
|
|
315
|
+
}
|
|
146
316
|
writer.write({
|
|
147
317
|
src: "metro",
|
|
148
318
|
level: "info",
|
|
149
319
|
event: "server_started",
|
|
150
320
|
msg: `${mode} dev server listening on port ${port}`
|
|
151
321
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
322
|
+
if (idleStopMinutes > 0) stopWatchingIdle = watchIdleDevServer({
|
|
323
|
+
idleStopMs: idleStopMinutes * 6e4,
|
|
324
|
+
now,
|
|
325
|
+
serverActivityAt: serverActivity.lastActivityAt,
|
|
326
|
+
probe: idleProbe ?? workspaceIdleProbe(root),
|
|
327
|
+
onIdle: async (idleMinutesNow) => {
|
|
328
|
+
const stopIfStillIdle = async () => {
|
|
329
|
+
const idleMinutes = idleMinutesNow();
|
|
330
|
+
if (stopping || idleMinutes === null) return;
|
|
331
|
+
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
|
+
} });
|
|
337
|
+
});
|
|
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`);
|
|
339
|
+
};
|
|
340
|
+
try {
|
|
341
|
+
await withIdleWorkspace(root, () => withWorkspaceProcessLock(dirname(logsDir), "metro-start", stopIfStillIdle, {
|
|
342
|
+
external: true,
|
|
343
|
+
waitMs: 0,
|
|
344
|
+
ownerPurpose: "idle stop"
|
|
345
|
+
}), {
|
|
346
|
+
purpose: "idle stop",
|
|
347
|
+
supervisor: false,
|
|
348
|
+
managedLocks: false
|
|
349
|
+
});
|
|
350
|
+
} catch (err) {
|
|
351
|
+
stderr(`Stim supervisor: could not stop the idle dev server: ${describeError(err)}`);
|
|
352
|
+
}
|
|
164
353
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
readyServer.onExit?.((info) => {
|
|
354
|
+
});
|
|
355
|
+
server.onExit?.((info) => {
|
|
168
356
|
if (stopping) return;
|
|
169
357
|
const detail = info?.signal ? `signal ${info.signal}` : `exit code ${info?.code ?? "unknown"}`;
|
|
170
358
|
shutdown(1, "supervisor_stopped", `the ${mode} dev server exited unexpectedly (${detail}); shutting the supervisor down`);
|
|
171
359
|
});
|
|
172
|
-
if (attachSignals) for (const signal of ["SIGTERM", "SIGINT"]) process.on(signal, () => {
|
|
173
|
-
shutdown(0, "supervisor_stopped", `received ${signal}; stopping the ${mode} dev server`);
|
|
174
|
-
});
|
|
175
360
|
return {
|
|
176
361
|
mode,
|
|
177
362
|
server,
|
|
@@ -201,7 +386,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
201
386
|
root,
|
|
202
387
|
port: parsed.port,
|
|
203
388
|
tunnel: parsed.tunnel ?? false,
|
|
204
|
-
resetCache: parsed.resetCache ?? false
|
|
389
|
+
resetCache: parsed.resetCache ?? false,
|
|
390
|
+
idleStopMinutes: parsed.idleStopMinutes ?? 0
|
|
205
391
|
});
|
|
206
392
|
}
|
|
207
393
|
function invokedDirectly() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as ownership_claim_exports } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { r as stopDeclaringSpawnsOn, t as declareSpawnsOn } from "./spawn-claims-CUleC2cM.mjs";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
//#region src/engine/workspace-process-lock.ts
|
|
4
5
|
const DEFAULT_WAIT_MS = 6e4;
|
|
@@ -10,11 +11,11 @@ function workspaceProcessLockError(err) {
|
|
|
10
11
|
if (code === "STIM_LOCK_TIMEOUT") return "timeout";
|
|
11
12
|
return null;
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
+
function workspaceProcessLockPath(root, name, external) {
|
|
14
15
|
return external ? join(root, `${name}.lock`) : join(root, ".stim", `${name}.lock`);
|
|
15
16
|
}
|
|
16
|
-
async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep = defaultSleep, waitMs = DEFAULT_WAIT_MS, ownerPurpose, rejectOwnerPurposes = [], external = false } = {}) {
|
|
17
|
-
const path =
|
|
17
|
+
async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep = defaultSleep, waitMs = DEFAULT_WAIT_MS, ownerPurpose, rejectOwnerPurposes = [], external = false, declareSpawns = false } = {}) {
|
|
18
|
+
const path = workspaceProcessLockPath(root, name, external);
|
|
18
19
|
const deadline = now() + waitMs;
|
|
19
20
|
for (;;) {
|
|
20
21
|
const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
|
|
@@ -24,10 +25,14 @@ async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep
|
|
|
24
25
|
details: ownerPurpose ? { purpose: ownerPurpose } : {}
|
|
25
26
|
});
|
|
26
27
|
if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
|
|
27
|
-
if (attempt.acquired)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if (attempt.acquired) {
|
|
29
|
+
if (declareSpawns) declareSpawnsOn(attempt.acquired);
|
|
30
|
+
try {
|
|
31
|
+
return await fn(attempt.acquired);
|
|
32
|
+
} finally {
|
|
33
|
+
stopDeclaringSpawnsOn(attempt.acquired);
|
|
34
|
+
(0, ownership_claim_exports.releaseClaim)(attempt.acquired);
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
37
|
const purpose = (attempt.held ?? attempt.waitingFor?.[0])?.details.purpose;
|
|
33
38
|
if (typeof purpose === "string" && rejectOwnerPurposes.includes(purpose)) {
|
|
@@ -44,4 +49,4 @@ async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep
|
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
//#endregion
|
|
47
|
-
export { workspaceProcessLockError as n, withWorkspaceProcessLock as t };
|
|
52
|
+
export { workspaceProcessLockError as n, workspaceProcessLockPath as r, withWorkspaceProcessLock as t };
|