stim 1.8.0 → 1.9.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-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as clearRemoteSession, i as clearManagedMetroTunnel, l as readRemoteSession, o as clearWorkspaceSupervisor, s as readMetroTunnel } from "./state-
|
|
5
|
-
import { a as
|
|
6
|
-
import { n as verifyCollectorOwnership } from "./ownership-
|
|
7
|
-
import { f as
|
|
8
|
-
import {
|
|
9
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
10
|
-
import { l as releaseWorkspaceLeases } from "./device-lease-
|
|
11
|
-
import { i as endRecordedSession } from "./device-remote-
|
|
12
|
-
import {
|
|
1
|
+
import { D as process_identity_exports, G as parseDeviceSlotOption, J as validateDeviceSlot, K as projectDeviceSlots, T as withConfigLock, U as deviceSlotPlatforms, W as parseDeviceSlotKey, a as clearSupervisor, f as getProject, w as upsertProject } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { _ as workspaceDir, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-DF2gCFhx.mjs";
|
|
3
|
+
import { o as findProjectRoot } from "./project-DS112DYB.mjs";
|
|
4
|
+
import { a as clearRemoteSession, i as clearManagedMetroTunnel, l as readRemoteSession, o as clearWorkspaceSupervisor, s as readMetroTunnel } from "./state-NcJzMEBF.mjs";
|
|
5
|
+
import { a as pidExists, c as resolveProjectMetro, l as signalProcessTree, n as killMetroTree } from "./metro-DrLHaMn2.mjs";
|
|
6
|
+
import { n as verifyCollectorOwnership } from "./ownership-D15Op8vN.mjs";
|
|
7
|
+
import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-gByVmIjy.mjs";
|
|
8
|
+
import { b as resolveEasCliBin } from "./sim-pool-KaIsp2Ft.mjs";
|
|
9
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-DWaiRD0e.mjs";
|
|
10
|
+
import { l as releaseWorkspaceLeases } from "./device-lease-Crs-HkJY.mjs";
|
|
11
|
+
import { E as teardownOwnedIosSim, T as teardownOwnedAvd, i as endRecordedSession } from "./device-remote-AQ5rQPqr.mjs";
|
|
12
|
+
import { i as stopTunnel, t as resolveSupervisorTarget } from "./ownership-DCQPuWEc.mjs";
|
|
13
13
|
import chalk from "chalk";
|
|
14
14
|
//#region src/commands/stop.ts
|
|
15
15
|
const DEFAULT_WAIT_MS = 1e4;
|
|
@@ -143,7 +143,7 @@ async function runStop(options) {
|
|
|
143
143
|
result.summary = summarize(root, result.outcomes, result.ok);
|
|
144
144
|
return result;
|
|
145
145
|
}
|
|
146
|
-
async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
|
|
146
|
+
async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid) => signalProcessTree(pid), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
|
|
147
147
|
const proj = project === void 0 ? getProject(root) : project;
|
|
148
148
|
const sup = state === void 0 ? readSupervisorState(root) : state;
|
|
149
149
|
const collectorRecords = collectors === void 0 ? readCollectorState(root) : collectors;
|
|
@@ -172,6 +172,7 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
172
172
|
};
|
|
173
173
|
let ok = true;
|
|
174
174
|
let stillHolding = null;
|
|
175
|
+
let keepPort = null;
|
|
175
176
|
const target = resolveSupervisorTarget({
|
|
176
177
|
state: sup,
|
|
177
178
|
record: proj?.supervisor ?? null,
|
|
@@ -232,10 +233,17 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
232
233
|
};
|
|
233
234
|
else if (reservedPort === null) report(chalk.dim(phaseLine("metro", "no port reserved")));
|
|
234
235
|
else {
|
|
235
|
-
|
|
236
|
+
const metro = await stopMetro(reservedPort, root, {
|
|
237
|
+
server: sup,
|
|
238
|
+
supervisorGone: target.status === "stale",
|
|
239
|
+
signalServer,
|
|
240
|
+
inspectIdentity,
|
|
241
|
+
waiter,
|
|
236
242
|
resolveMetro,
|
|
237
243
|
report
|
|
238
244
|
});
|
|
245
|
+
outcomes.metro = metro.outcome;
|
|
246
|
+
keepPort = metro.keepPort;
|
|
239
247
|
if (outcomes.metro.status === "refused" || outcomes.metro.status === "failed") {
|
|
240
248
|
ok = false;
|
|
241
249
|
stillHolding = outcomes.metro.reason;
|
|
@@ -254,6 +262,15 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
254
262
|
return;
|
|
255
263
|
}
|
|
256
264
|
if (reservedPort !== null) {
|
|
265
|
+
if (keepPort) {
|
|
266
|
+
outcomes.port = {
|
|
267
|
+
status: "kept",
|
|
268
|
+
port: reservedPort,
|
|
269
|
+
reason: keepPort
|
|
270
|
+
};
|
|
271
|
+
report(chalk.dim(phaseLine("port", `keeping reservation ${reservedPort} -- ${keepPort}`)));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
257
274
|
if (freePort(root, reservedPort) === false) {
|
|
258
275
|
ok = false;
|
|
259
276
|
outcomes.port = {
|
|
@@ -334,8 +351,12 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
|
|
|
334
351
|
reason: stillHolding
|
|
335
352
|
};
|
|
336
353
|
report(chalk.yellow(phaseLine("port", `keeping reservation ${reservedPort ?? "(none)"} -- ${stillHolding}`)));
|
|
337
|
-
const
|
|
338
|
-
|
|
354
|
+
const serverIsDown = [
|
|
355
|
+
"none",
|
|
356
|
+
"already-stopped",
|
|
357
|
+
"stopped"
|
|
358
|
+
].includes(outcomes.supervisor.status) && !["refused", "failed"].includes(outcomes.metro.status);
|
|
359
|
+
if (tunnelHolding && serverIsDown) {
|
|
339
360
|
clearState(root, sup);
|
|
340
361
|
await clearRegistration(root, proj?.supervisor ?? null);
|
|
341
362
|
}
|
|
@@ -476,21 +497,76 @@ async function stopSupervisor(target, { killGroup, waiter, report }) {
|
|
|
476
497
|
reason
|
|
477
498
|
};
|
|
478
499
|
}
|
|
479
|
-
async function stopMetro(port, root, { resolveMetro, report }) {
|
|
500
|
+
async function stopMetro(port, root, { server, supervisorGone, signalServer, inspectIdentity, waiter, resolveMetro, report }) {
|
|
501
|
+
const serverPid = numberOrNull(server?.serverPid);
|
|
502
|
+
const serverProcessToken = server?.serverProcessToken;
|
|
503
|
+
const serverRecord = {
|
|
504
|
+
pid: serverPid,
|
|
505
|
+
processToken: serverProcessToken
|
|
506
|
+
};
|
|
507
|
+
const identity = supervisorGone && serverPid && typeof serverProcessToken === "string" ? inspectIdentity(serverRecord) : null;
|
|
508
|
+
if (identity === "unknown") {
|
|
509
|
+
const reason = `the identity of dev server pid ${serverPid} left by the supervisor could not be verified`;
|
|
510
|
+
report(chalk.yellow(phaseLine("metro", `refusing to signal it: ${reason}`)));
|
|
511
|
+
return {
|
|
512
|
+
outcome: {
|
|
513
|
+
status: "refused",
|
|
514
|
+
port,
|
|
515
|
+
pid: serverPid,
|
|
516
|
+
reason
|
|
517
|
+
},
|
|
518
|
+
keepPort: null
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
if (identity === "same") {
|
|
522
|
+
report(chalk.dim(phaseLine("metro", `sending SIGTERM to dev server pid ${serverPid} left by the supervisor`)));
|
|
523
|
+
let signalled = false;
|
|
524
|
+
try {
|
|
525
|
+
signalled = signalServer(serverPid);
|
|
526
|
+
} catch {}
|
|
527
|
+
if (signalled ? await waiter(serverPid, serverProcessToken) : ["gone", "different"].includes(inspectIdentity(serverRecord))) {
|
|
528
|
+
report(chalk.green(phaseLine("metro", `dev server pid ${serverPid}`)));
|
|
529
|
+
return {
|
|
530
|
+
outcome: {
|
|
531
|
+
status: "stopped",
|
|
532
|
+
port,
|
|
533
|
+
pid: serverPid
|
|
534
|
+
},
|
|
535
|
+
keepPort: null
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
const reason = `dev server pid ${serverPid} left by the supervisor did not exit`;
|
|
539
|
+
report(chalk.red(phaseLine("metro", reason)));
|
|
540
|
+
return {
|
|
541
|
+
outcome: {
|
|
542
|
+
status: "failed",
|
|
543
|
+
port,
|
|
544
|
+
pid: serverPid,
|
|
545
|
+
reason
|
|
546
|
+
},
|
|
547
|
+
keepPort: null
|
|
548
|
+
};
|
|
549
|
+
}
|
|
480
550
|
const resolution = await resolveMetro(port, root);
|
|
481
551
|
if (resolution.missing) {
|
|
482
552
|
report(chalk.dim(phaseLine("metro", `nothing listening on port ${port}`)));
|
|
483
553
|
return {
|
|
484
|
-
|
|
485
|
-
|
|
554
|
+
outcome: {
|
|
555
|
+
status: "missing",
|
|
556
|
+
port
|
|
557
|
+
},
|
|
558
|
+
keepPort: null
|
|
486
559
|
};
|
|
487
560
|
}
|
|
488
561
|
const reason = resolution.notOurs || "no recorded Stim supervisor owns this server; stop it with the tool that started it";
|
|
489
562
|
report(chalk.yellow(phaseLine("metro", `leaving port ${port} alone: ${reason}`)));
|
|
490
563
|
return {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
564
|
+
outcome: {
|
|
565
|
+
status: "not-managed",
|
|
566
|
+
port,
|
|
567
|
+
reason
|
|
568
|
+
},
|
|
569
|
+
keepPort: resolution.metro ? `a dev server from this project still answers on port ${port}` : null
|
|
494
570
|
};
|
|
495
571
|
}
|
|
496
572
|
const OCCUPANCY_HINT = "often a UI-test runner or device tool still attached";
|
|
@@ -617,11 +693,11 @@ async function defaultClearRegistration(root, expected) {
|
|
|
617
693
|
}
|
|
618
694
|
}
|
|
619
695
|
function stopCommand(program) {
|
|
620
|
-
program.command("stop").description("The inverse of `start`: halt this workspace's supervisor, shut the owned device down (never deleted), and free the reserved port. Non-destructive -- the device stays assigned, so coming back costs a boot. Acts on the current workspace.").option("--slot <name>", "Stop only this device slot, keeping the shared server running",
|
|
696
|
+
program.command("stop").description("The inverse of `start`: halt this workspace's supervisor, shut the owned device down (never deleted), and free the reserved port. Non-destructive -- the device stays assigned, so coming back costs a boot. Acts on the current workspace.").option("--slot <name>", "Stop only this device slot, keeping the shared server running", parseDeviceSlotOption).option("--json", "print the per-step outcomes as JSON").action(async (opts) => {
|
|
621
697
|
const root = findProjectRoot(process.cwd());
|
|
622
698
|
if (!root) {
|
|
623
|
-
|
|
624
|
-
|
|
699
|
+
refuseNoProject({ json: Boolean(opts.json) });
|
|
700
|
+
return;
|
|
625
701
|
}
|
|
626
702
|
const { ok, outcomes, summary } = await withWorkspaceProcessLock(workspaceDir(root), "native-run", () => runStop({
|
|
627
703
|
root,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as resolveSupervisorTarget } from "./ownership-
|
|
2
|
-
import { a as resolveCollectorTargets, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-
|
|
1
|
+
import { t as resolveSupervisorTarget } from "./ownership-DCQPuWEc.mjs";
|
|
2
|
+
import { a as resolveCollectorTargets, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-BO28HGqF.mjs";
|
|
3
3
|
export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop };
|
package/dist/supervisor-run.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as createNdjsonWriter } from "./ndjson-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { C as setSupervisor, D as process_identity_exports, a as clearSupervisor } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { r as createNdjsonWriter } from "./ndjson-9uFNRwfe.mjs";
|
|
3
|
+
import { b as workspaceLogsDir, c as writeWorkspaceState, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-DF2gCFhx.mjs";
|
|
4
|
+
import { a as detectIsExpo } from "./project-DS112DYB.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-
|
|
6
|
+
import { t as relaunchWithLogFile } from "./detached-entry-KEu0_AXL.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-NcJzMEBF.mjs";
|
|
8
8
|
import { existsSync, realpathSync } from "node:fs";
|
|
9
|
+
import { LOG_ROTATE_BYTES } from "@stim-cli/core";
|
|
9
10
|
import { isAbsolute, join, resolve } from "node:path";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
11
12
|
//#region src/supervisor/run.ts
|
|
@@ -48,7 +49,7 @@ function parseArgs(argv) {
|
|
|
48
49
|
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) }) {
|
|
49
50
|
root = realpathSync(root);
|
|
50
51
|
const logsDir = workspaceLogsDir(root);
|
|
51
|
-
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"));
|
|
52
|
+
const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
|
|
52
53
|
const mode = isExpo(root) ? MODE_EXPO : MODE_BARE;
|
|
53
54
|
const startedAt = new Date(now()).toISOString();
|
|
54
55
|
const processToken = (0, process_identity_exports.captureProcessToken)(process.pid);
|
|
@@ -104,8 +105,32 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
104
105
|
onExit(code);
|
|
105
106
|
};
|
|
106
107
|
let server;
|
|
108
|
+
const shutdown = async (code, event, msg) => {
|
|
109
|
+
if (stopping || !server) return;
|
|
110
|
+
stopping = true;
|
|
111
|
+
try {
|
|
112
|
+
await server.close();
|
|
113
|
+
} catch (err) {
|
|
114
|
+
writer.write({
|
|
115
|
+
src: "metro",
|
|
116
|
+
level: "warn",
|
|
117
|
+
event: "server_close_failed",
|
|
118
|
+
msg: describeError(err)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
finish(code, event, code === 0 ? "info" : "error", msg);
|
|
122
|
+
};
|
|
123
|
+
if (attachSignals) for (const signal of ["SIGTERM", "SIGINT"]) process.on(signal, () => {
|
|
124
|
+
if (server) {
|
|
125
|
+
shutdown(0, "supervisor_stopped", `received ${signal}; stopping the ${mode} dev server`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (stopping) return;
|
|
129
|
+
stopping = true;
|
|
130
|
+
finish(signal === "SIGINT" ? 130 : 143, "supervisor_stopped", "warn", `received ${signal} before the ${mode} dev server started; stopping`);
|
|
131
|
+
});
|
|
107
132
|
try {
|
|
108
|
-
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-
|
|
133
|
+
server = await (mode === "expo-child" ? startExpo || (await import("./server-expo-CeILEu86.mjs")).startExpoServer : startBare || (await import("./server-bare-DWkkcIxV.mjs")).startBareServer)({
|
|
109
134
|
root,
|
|
110
135
|
port,
|
|
111
136
|
logsDir,
|
|
@@ -132,46 +157,39 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
|
|
|
132
157
|
}
|
|
133
158
|
});
|
|
134
159
|
} catch (err) {
|
|
160
|
+
if (stopping) return null;
|
|
135
161
|
stderr(`Stim supervisor: failed to start the ${mode} dev server: ${describeError(err)}`);
|
|
136
162
|
finish(1, "supervisor_failed", "fatal", `failed to start the ${mode} dev server: ${describeError(err)}`);
|
|
137
163
|
return null;
|
|
138
164
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
165
|
+
if (stopping) {
|
|
166
|
+
try {
|
|
167
|
+
await server.close();
|
|
168
|
+
} catch {}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const serverPid = server.serverPid;
|
|
172
|
+
if (serverPid) {
|
|
173
|
+
const serverProcessToken = (0, process_identity_exports.captureProcessToken)(serverPid);
|
|
174
|
+
withWorkspaceStateLock(root, () => {
|
|
175
|
+
if (readWorkspaceState(root)?.supervisor?.processToken === processToken) writeWorkspaceState(root, { supervisor: {
|
|
176
|
+
...record,
|
|
177
|
+
serverPid,
|
|
178
|
+
...serverProcessToken ? { serverProcessToken } : {}
|
|
179
|
+
} });
|
|
180
|
+
});
|
|
181
|
+
}
|
|
146
182
|
writer.write({
|
|
147
183
|
src: "metro",
|
|
148
184
|
level: "info",
|
|
149
185
|
event: "server_started",
|
|
150
186
|
msg: `${mode} dev server listening on port ${port}`
|
|
151
187
|
});
|
|
152
|
-
|
|
153
|
-
if (stopping) return;
|
|
154
|
-
stopping = true;
|
|
155
|
-
try {
|
|
156
|
-
await readyServer.close();
|
|
157
|
-
} catch (err) {
|
|
158
|
-
writer.write({
|
|
159
|
-
src: "metro",
|
|
160
|
-
level: "warn",
|
|
161
|
-
event: "server_close_failed",
|
|
162
|
-
msg: describeError(err)
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
finish(code, event, code === 0 ? "info" : "error", msg);
|
|
166
|
-
};
|
|
167
|
-
readyServer.onExit?.((info) => {
|
|
188
|
+
server.onExit?.((info) => {
|
|
168
189
|
if (stopping) return;
|
|
169
190
|
const detail = info?.signal ? `signal ${info.signal}` : `exit code ${info?.code ?? "unknown"}`;
|
|
170
191
|
shutdown(1, "supervisor_stopped", `the ${mode} dev server exited unexpectedly (${detail}); shutting the supervisor down`);
|
|
171
192
|
});
|
|
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
193
|
return {
|
|
176
194
|
mode,
|
|
177
195
|
server,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { k as ownership_claim_exports } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { r as stopDeclaringSpawnsOn, t as declareSpawnsOn } from "./spawn-claims-Dn3C_N6w.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 };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync, mkdirSync,
|
|
3
|
-
import {
|
|
4
|
-
import { join as join$1, resolve as resolve$1 } from "path";
|
|
1
|
+
import { A as withDirLock, N as readJsonObject, u as getConfigDir } from "./config-Cp9lM3wX.mjs";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join, resolve } from "path";
|
|
5
4
|
import { buildCacheRoot as sharedBuildCache, workspaceId, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
|
|
5
|
+
import { dirname as dirname$1, join as join$1 } from "node:path";
|
|
6
6
|
//#region src/workspace/paths.ts
|
|
7
7
|
const WORKSPACE_METADATA_FILE_NAME = "workspace.json";
|
|
8
8
|
function workspaceMetadataFile(projectRoot) {
|
|
9
|
-
return join
|
|
9
|
+
return join(workspaceDir(projectRoot), WORKSPACE_METADATA_FILE_NAME);
|
|
10
10
|
}
|
|
11
11
|
function ensureWorkspaceStorage(projectRoot) {
|
|
12
|
-
const canonicalRoot = resolve
|
|
12
|
+
const canonicalRoot = resolve(projectRoot);
|
|
13
13
|
const dir = workspaceDir(canonicalRoot);
|
|
14
14
|
const file = workspaceMetadataFile(canonicalRoot);
|
|
15
15
|
mkdirSync(dir, { recursive: true });
|
|
16
|
-
return withDirLock(join
|
|
16
|
+
return withDirLock(join(dir, "metadata.lock"), () => {
|
|
17
17
|
if (!existsSync(file)) {
|
|
18
18
|
const metadata = {
|
|
19
19
|
projectRoot: canonicalRoot,
|
|
@@ -30,57 +30,52 @@ function ensureWorkspaceStorage(projectRoot) {
|
|
|
30
30
|
}
|
|
31
31
|
return dir;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
if (JSON.parse(readFileSync(file, "utf-8")).projectRoot === canonicalRoot) return dir;
|
|
35
|
-
} catch {}
|
|
33
|
+
if (readJsonObject(file)?.projectRoot === canonicalRoot) return dir;
|
|
36
34
|
const error = /* @__PURE__ */ new Error(`Stim workspace collision at ${dir}: its workspace.json does not belong to ${canonicalRoot}.`);
|
|
37
35
|
error.code = "STIM_WORKSPACE_COLLISION";
|
|
38
36
|
throw error;
|
|
39
37
|
});
|
|
40
38
|
}
|
|
41
39
|
function workspaceLogsDir(projectRoot) {
|
|
42
|
-
return join
|
|
40
|
+
return join(workspaceDir(projectRoot), "logs");
|
|
41
|
+
}
|
|
42
|
+
function workspaceLogErrorIndex(projectRoot) {
|
|
43
|
+
return join(workspaceDir(projectRoot), "log-error-index.json");
|
|
43
44
|
}
|
|
44
45
|
function workspaceDerivedData(projectRoot) {
|
|
45
|
-
return join
|
|
46
|
+
return join(workspaceDir(projectRoot), "derived-data");
|
|
46
47
|
}
|
|
47
48
|
function supervisorPidFile(projectRoot) {
|
|
48
|
-
return join
|
|
49
|
+
return join(workspaceDir(projectRoot), "supervisor.pid");
|
|
49
50
|
}
|
|
50
51
|
function workspaceStateFile(projectRoot) {
|
|
51
|
-
return join
|
|
52
|
+
return join(workspaceDir(projectRoot), "state.json");
|
|
52
53
|
}
|
|
53
54
|
function workspaceStateLock(projectRoot) {
|
|
54
|
-
return join
|
|
55
|
+
return join(workspaceDir(projectRoot), "state.lock");
|
|
55
56
|
}
|
|
56
57
|
function supervisorLogFile(projectRoot) {
|
|
57
|
-
return join
|
|
58
|
+
return join(workspaceLogsDir(projectRoot), "supervisor.log");
|
|
58
59
|
}
|
|
59
60
|
function emulatorLogFile(projectRoot) {
|
|
60
|
-
return join
|
|
61
|
+
return join(workspaceLogsDir(projectRoot), "emulator.log");
|
|
61
62
|
}
|
|
62
63
|
function sharedCompilationCache() {
|
|
63
|
-
return join
|
|
64
|
+
return join(getConfigDir(), "compilation-cache");
|
|
64
65
|
}
|
|
65
66
|
function sharedCcache() {
|
|
66
|
-
return join
|
|
67
|
+
return join(getConfigDir(), "ccache");
|
|
67
68
|
}
|
|
68
69
|
//#endregion
|
|
69
70
|
//#region src/workspace/workspace-state.ts
|
|
70
71
|
function readWorkspaceState(root) {
|
|
71
|
-
|
|
72
|
-
const parsed = JSON.parse(readFileSync(workspaceStateFile(root), "utf-8"));
|
|
73
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
74
|
-
return parsed;
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
72
|
+
return readJsonObject(workspaceStateFile(root));
|
|
78
73
|
}
|
|
79
74
|
function withWorkspaceStateLock(root, fn) {
|
|
80
75
|
const file = workspaceStateFile(root);
|
|
81
76
|
return withDirLock(workspaceStateLock(root), fn, { ensureParent: () => {
|
|
82
77
|
ensureWorkspaceStorage(root);
|
|
83
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
78
|
+
mkdirSync(dirname$1(file), { recursive: true });
|
|
84
79
|
} });
|
|
85
80
|
}
|
|
86
81
|
function writeWorkspaceState(root, patch) {
|
|
@@ -94,7 +89,7 @@ function updateWorkspaceState(root, update) {
|
|
|
94
89
|
}
|
|
95
90
|
function replaceWorkspaceState(root, state) {
|
|
96
91
|
const file = workspaceStateFile(root);
|
|
97
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
92
|
+
mkdirSync(dirname$1(file), { recursive: true });
|
|
98
93
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
99
94
|
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`);
|
|
100
95
|
renameSync(tmp, file);
|
|
@@ -142,5 +137,33 @@ function clearWorkspaceStateKey(root, key, shouldClear) {
|
|
|
142
137
|
return true;
|
|
143
138
|
});
|
|
144
139
|
}
|
|
140
|
+
function recordWorkspaceUse(root, now = /* @__PURE__ */ new Date()) {
|
|
141
|
+
try {
|
|
142
|
+
writeWorkspaceState(root, { lastUsedAt: now.toISOString() });
|
|
143
|
+
} catch {}
|
|
144
|
+
}
|
|
145
|
+
function lastUseFrom(state, logMtimes) {
|
|
146
|
+
const candidates = [
|
|
147
|
+
Date.parse(String(state?.lastUsedAt ?? "")),
|
|
148
|
+
Date.parse(String(state?.lastBuild?.startedAt ?? "")),
|
|
149
|
+
Date.parse(String(state?.supervisor?.startedAt ?? "")),
|
|
150
|
+
...logMtimes
|
|
151
|
+
].filter(Number.isFinite);
|
|
152
|
+
return candidates.length ? Math.max(...candidates) : NaN;
|
|
153
|
+
}
|
|
154
|
+
function workspaceLastUsed(root) {
|
|
155
|
+
const logs = workspaceLogsDir(root);
|
|
156
|
+
let mtimes = [];
|
|
157
|
+
try {
|
|
158
|
+
mtimes = readdirSync(logs).flatMap((name) => {
|
|
159
|
+
try {
|
|
160
|
+
return [statSync(join$1(logs, name)).mtimeMs];
|
|
161
|
+
} catch {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
} catch {}
|
|
166
|
+
return lastUseFrom(readWorkspaceState(root), mtimes);
|
|
167
|
+
}
|
|
145
168
|
//#endregion
|
|
146
|
-
export {
|
|
169
|
+
export { workspaceStateFile as S, workspaceDir as _, updateWorkspaceState as a, workspaceLogsDir as b, writeWorkspaceState as c, sharedBuildCache as d, sharedCcache as f, workspaceDerivedData as g, supervisorPidFile as h, recordWorkspaceUse as i, emulatorLogFile as l, supervisorLogFile as m, clearWorkspaceStateKeys as n, withWorkspaceStateLock as o, sharedCompilationCache as p, readWorkspaceState as r, workspaceLastUsed as s, clearWorkspaceStateKey as t, ensureWorkspaceStorage as u, workspaceId as v, workspaceName$1 as x, workspaceLogErrorIndex as y };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as reclaimKeys, c as removalBlockers, d as removeWorktreeTarget, f as worktreeCommand, i as porcelainPath, l as removalPath, n as excludePodChurn, o as registerRemove, r as matchWorktreeEntry, s as registerWarm, t as dependencyInstallCommand, u as removalRemedy } from "./worktree-LGB-UwgG.mjs";
|
|
2
|
+
export { worktreeCommand as default, dependencyInstallCommand, excludePodChurn, matchWorktreeEntry, porcelainPath, reclaimKeys, registerRemove, registerWarm, removalBlockers, removalPath, removalRemedy, removeWorktreeTarget };
|