stim 1.19.0 → 1.20.1

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.
Files changed (172) hide show
  1. package/README.md +20 -3
  2. package/dist/{activity-BSw0x84R.mjs → activity-BaMpUQ4-.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-Bjxu_VmX.mjs → agent-device-usage-output-VPaOgGaF.mjs} +7 -7
  4. package/dist/android-CLbBJ2ve.mjs +1258 -0
  5. package/dist/{android-DE5g_5gv.mjs → android-CZh6ElG5.mjs} +2 -2
  6. package/dist/{android-BdQC6zs1.mjs → android-DE8-JfGW.mjs} +105 -47
  7. package/dist/{android-cas-C87geAg-.mjs → android-cas-BFpS84v2.mjs} +9 -5
  8. package/dist/android-cas-compiler.mjs +1 -1
  9. package/dist/android-eXfIjKJr.mjs +6 -0
  10. package/dist/api-run.mjs +159 -8
  11. package/dist/{api-DIf_s86s.mjs → api-zuX3ynYN.mjs} +5 -1
  12. package/dist/api.d.mts +98 -4
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-CFI4ptUL.mjs → app-install-Cg9YJy3x.mjs} +9 -8
  15. package/dist/artifact-Ctb2jpw6.mjs +807 -0
  16. package/dist/artifact-DXk_Fle_.mjs +772 -0
  17. package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
  18. package/dist/{browser-web-CDhqQxhv.mjs → browser-web-xQWC2RWl.mjs} +19 -19
  19. package/dist/{budget-Dz-kyXLv.mjs → budget-RFbwFpG5.mjs} +3101 -3062
  20. package/dist/build-COBA1tBc.mjs +462 -0
  21. package/dist/{build-facts-B87vo-Im.d.mts → build-facts-DcLv2HSd.d.mts} +1 -32
  22. package/dist/build-plan-CRjAA6Qi.mjs +553 -0
  23. package/dist/{cache-manifest-DiwKSyv9.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
  24. package/dist/cache-manifest.mjs +1 -1
  25. package/dist/{manifest-CX0d1IkZ.mjs → ccache-CtbqWxIC.mjs} +13 -19
  26. package/dist/{chrome-BTUOo8p2.mjs → chrome-Dp2lMLBe.mjs} +1 -1
  27. package/dist/{cli-C9Zvgbdc.mjs → cli-sGqlPu1n.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-CuUo8Nvg.mjs → client-zqjFd79D.mjs} +89 -307
  30. package/dist/collector-run.d.mts +4 -0
  31. package/dist/collector-run.mjs +7 -7
  32. package/dist/{command-output-Bt8ygHE7.mjs → command-output-CPDq_90S.mjs} +2 -2
  33. package/dist/{config-DC5jEtd1.mjs → config-D0LhTY3S.mjs} +8 -12
  34. package/dist/{created-devices-D0s26Hx5.mjs → created-devices-CXBMtoj5.mjs} +7 -6
  35. package/dist/{dependency-state-DKaS1OM9.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
  36. package/dist/{detached-entry-pB_IPfV4.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
  37. package/dist/{dev-client-CDY_zAmD.mjs → dev-client-BqYjMIaC.mjs} +2 -2
  38. package/dist/{device-BHw0WlHl.mjs → device-BgNj-qVj.mjs} +8 -8
  39. package/dist/device-D4DqjSZZ.mjs +727 -0
  40. package/dist/{device-capacity-BoN1jQkO.mjs → device-capacity-DrwHwR97.mjs} +13 -14
  41. package/dist/device-host-worker.mjs +38 -18
  42. package/dist/device-ios-DE8KJd3b.mjs +413 -0
  43. package/dist/{device-lease-Cu7PtQpZ.mjs → device-lease-C309csaB.mjs} +138 -24
  44. package/dist/{device-lease-run-D38SnZtt.mjs → device-lease-run-Baelt3nc.mjs} +4 -4
  45. package/dist/{device-pool-CP4rAsHx.mjs → device-pool-DtK9S6AD.mjs} +3 -3
  46. package/dist/{device-remote-B5GiUifk.mjs → device-remote-DjsNw8DD.mjs} +17 -68
  47. package/dist/doctor-DiP9HsIP.mjs +515 -0
  48. package/dist/{doctor-PRJH94v6.mjs → doctor-Dunu3Nv1.mjs} +333 -744
  49. package/dist/{doctor-watchman-wZhyTdp4.mjs → doctor-watchman-XJzT8tK-.mjs} +15 -13
  50. package/dist/{simslim-D9LkJxIO.mjs → eas-build-0gadvrca.mjs} +6 -152
  51. package/dist/{stim-installations-DbmUjsLv.mjs → eas-session-ledger-DJDeL4Uq.mjs} +57 -4
  52. package/dist/{error-diagnostics--v5HGOU0.mjs → error-diagnostics-BhQtoLrZ.mjs} +17 -12
  53. package/dist/errors-DzkMYh8Q.mjs +205 -0
  54. package/dist/{exec-i8GDPwq9.mjs → exec-B81Qodjn.mjs} +40 -10
  55. package/dist/{gc-CyHMcKcn.mjs → gc-D5cz5G0k.mjs} +22 -21
  56. package/dist/{device-ios-B2ruohE-.mjs → gradle-CZZo1TSA.mjs} +21 -650
  57. package/dist/{guide-dRaQJJk9.mjs → guide-DakjcoUt.mjs} +503 -251
  58. package/dist/{hosted-android-Bs7fytj7.mjs → hosted-android-C-D8Dj0_.mjs} +5 -5
  59. package/dist/{hosted-client-C5G4h_OJ.mjs → hosted-client--hNFgixu.mjs} +9 -3
  60. package/dist/{hosted-ios-Bik035eL.mjs → hosted-ios-Chx9XQyI.mjs} +3 -3
  61. package/dist/{hosted-logs-CI9Az9a4.mjs → hosted-logs-Bkz0Hxzh.mjs} +8 -8
  62. package/dist/{hosted-macos-DABm3ScO.mjs → hosted-macos-ckTjN-0V.mjs} +7 -6
  63. package/dist/{hosted-native-DbV2aUVw.mjs → hosted-native-3KXZ5-qn.mjs} +17 -14
  64. package/dist/{idle-shutdown-DYiMBn34.mjs → idle-shutdown-DhAUyf5s.mjs} +7 -7
  65. package/dist/{ios-DYUr9LGc.mjs → ios-BDBN-xpf.mjs} +8 -7
  66. package/dist/ios-CQ8bHQXB.mjs +1112 -0
  67. package/dist/{ios-DCrkgXEM.mjs → ios-VGvNdsv2.mjs} +1 -1
  68. package/dist/{ios-device-CrW8aMb5.mjs → ios-device-B1B14xND.mjs} +1 -1
  69. package/dist/{ios-device-CJ_ZOGky.mjs → ios-device-BWHKGaJq.mjs} +3 -3
  70. package/dist/{ios-BWbHFZVz.mjs → ios-o896T9PE.mjs} +195 -35
  71. package/dist/ios-project-BeOXKPt2.mjs +197 -0
  72. package/dist/{ios-state-By0XuLTQ.mjs → ios-state-BsXMwo5y.mjs} +1 -1
  73. package/dist/js-swap-Z_mSuRrx.mjs +432 -0
  74. package/dist/{react-native-ios-CSpIxexZ.mjs → launch-BootbMk4.mjs} +59 -612
  75. package/dist/launch-V1zqiOYn.mjs +745 -0
  76. package/dist/{launch-verify-DCveSE6d.mjs → launch-verify-Dl78EVgR.mjs} +26 -7
  77. package/dist/{logs-Bao1HOMy.mjs → logs-Bh4eqCCc.mjs} +11 -11
  78. package/dist/{macos-ciyBdTY5.mjs → macos-D7irBW3A.mjs} +42 -50
  79. package/dist/macos-kivF8qKz.mjs +2 -0
  80. package/dist/macos-run.mjs +1 -1
  81. package/dist/maintenance-run.mjs +13 -10
  82. package/dist/{metro-DI2AjPF_.mjs → metro-_ZIE3Axg.mjs} +18 -5
  83. package/dist/{metro-gateway-BxpJLIwh.mjs → metro-gateway-BzlQZQmU.mjs} +2 -2
  84. package/dist/miss-reason-SuTptY-I.mjs +238 -0
  85. package/dist/{named-ports-B4iWH4E-.mjs → named-ports-O1TIl7tx.mjs} +3 -3
  86. package/dist/native-android-D94RlJ-X.mjs +226 -0
  87. package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
  88. package/dist/{native-runtime-BGxsbfny.mjs → native-runtime-D024BAvm.mjs} +9 -8
  89. package/dist/native-xcode-inputs-UElfGs59.mjs +306 -0
  90. package/dist/native-xcode-ios-CjS-nDVY.mjs +434 -0
  91. package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
  92. package/dist/offload-worker.d.mts +41 -7
  93. package/dist/offload-worker.mjs +409 -74
  94. package/dist/{ownership-EB0ySdGK.mjs → ownership-BrjepDiv.mjs} +2 -2
  95. package/dist/{placement-log-Dxe34rJm.mjs → placement-log-BItXET1x.mjs} +1 -1
  96. package/dist/plan-Jwu_vr-F.mjs +260 -0
  97. package/dist/plan-placement-B466UYMU.mjs +73 -0
  98. package/dist/{ports-ByPc0_97.mjs → ports-BFRL6JTj.mjs} +3 -3
  99. package/dist/{prebuild-BKJ3wJI1.mjs → prebuild-DB_zLOLc.mjs} +4 -4
  100. package/dist/{preview-BbSottmO.mjs → preview-BRLFRhTz.mjs} +50 -32
  101. package/dist/project-DX8fXyw_.mjs +1131 -0
  102. package/dist/project-plan-BPwbLwQu.mjs +10 -0
  103. package/dist/{pull-request-IHNdMnG8.mjs → pull-request-vOhLNmIb.mjs} +1 -1
  104. package/dist/pull-requests.mjs +1 -1
  105. package/dist/react-native-android-CuXM3QS8.mjs +921 -0
  106. package/dist/react-native-build-JUF31S8U.mjs +239 -0
  107. package/dist/react-native-doctor-BQHqiXaQ.mjs +78 -0
  108. package/dist/react-native-ios-DtVO4qf2.mjs +595 -0
  109. package/dist/{recordings-Bv8McZN4.mjs → recordings-Bk-VivUV.mjs} +1 -1
  110. package/dist/{reload-rAPdqeRR.mjs → reload-D9V7D8gP.mjs} +17 -13
  111. package/dist/remote-CZiTijxG.mjs +192 -0
  112. package/dist/{remote-cache-N3hAEaAL.mjs → remote-cache-fxcl5C-L.mjs} +5 -5
  113. package/dist/result-BrfgXtdO.mjs +186 -0
  114. package/dist/{run-lAkle1-c.mjs → run-ClC8UVB5.mjs} +3 -3
  115. package/dist/{server-bare-CkIjnegq.mjs → server-bare-dWjAarki.mjs} +5 -5
  116. package/dist/server-command-DnJYLnr4.mjs +69 -0
  117. package/dist/{server-expo-n3tUi3Em.mjs → server-expo-CUuzP9Mp.mjs} +107 -82
  118. package/dist/server-expo-Dvkd7JcF.mjs +2 -0
  119. package/dist/{settings-CxgngUZk.mjs → settings-Bbztm4oV.mjs} +179 -129
  120. package/dist/{settings-2am7TSxp.mjs → settings-BuKMOANA.mjs} +6 -6
  121. package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
  122. package/dist/settings.schema.json +84 -0
  123. package/dist/simslim-ChMfe8rg.mjs +149 -0
  124. package/dist/{slot-launch-HV_KtPIw.mjs → slot-launch-CeCRr6MK.mjs} +6 -6
  125. package/dist/{stage-BgaZJVZY.mjs → stage-BNKKdDNc.mjs} +6 -3
  126. package/dist/{start-DtxthMfI.mjs → start-CRkG-mZ7.mjs} +97 -68
  127. package/dist/start-mh6bS27z.mjs +2 -0
  128. package/dist/{state-Tp4uImDS.mjs → state-BUpAmt2r.mjs} +1 -1
  129. package/dist/{state-D2KtnALG.mjs → state-lqxdOH_g.mjs} +32 -12
  130. package/dist/{stats-8EJ5ivFT.mjs → stats-CaB1MxMi.mjs} +5 -5
  131. package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
  132. package/dist/{status-BOyp0CUl.mjs → status-C7vzkInu.mjs} +81 -293
  133. package/dist/status-watch-ZaVqRdtW.mjs +296 -0
  134. package/dist/{stim-desktop-C65jk_q2.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
  135. package/dist/{stop-zDlknFoz.mjs → stop-BO80KJoT.mjs} +21 -20
  136. package/dist/{stop-DRipAg-e.mjs → stop-BU7JaFCg.mjs} +2 -2
  137. package/dist/{stop-D0UIpZuh.mjs → stop-Cftw_sXJ.mjs} +5 -5
  138. package/dist/supervisor-run.d.mts +7 -2
  139. package/dist/supervisor-run.mjs +32 -20
  140. package/dist/{support-DsNaFg6D.mjs → support-Ca6PZbpr.mjs} +17 -7
  141. package/dist/{support-CNqYkV0y.mjs → support-Co0wk8Cv.mjs} +61 -8
  142. package/dist/{swiftpm-macos-aJzPAj1t.mjs → swiftpm-macos-siFSkmCO.mjs} +5 -5
  143. package/dist/tailnet-D7-tE_ug.mjs +265 -0
  144. package/dist/toolchain-B12psPA2.mjs +2 -0
  145. package/dist/{toolchain-C3xSoyUl.mjs → toolchain-SqehyPLw.mjs} +206 -53
  146. package/dist/{trigger-CAhmG-4s.mjs → trigger-C0MWBi8O.mjs} +2 -2
  147. package/dist/trigger-SHLOWJ4O.mjs +2 -0
  148. package/dist/{warm-progress-pFLB2e6P.mjs → warm-progress-5FAXkXIg.mjs} +6 -6
  149. package/dist/{watchman-BL1IdOtq.mjs → watchman-CqmaGcIb.mjs} +6 -6
  150. package/dist/{web-DbbrPUn0.mjs → web-BTjzE8mc.mjs} +9 -13
  151. package/dist/web-CHN5gh34.mjs +2 -0
  152. package/dist/web-run.mjs +10 -10
  153. package/dist/{workspace-state-CR9X86xJ.mjs → workspace-state-CvgTFe-h.mjs} +36 -36
  154. package/dist/{workspaces-Djb2gfi9.mjs → workspaces-C4kqIOlx.mjs} +1260 -1258
  155. package/dist/worktree-Cgnm6vZt.mjs +2 -0
  156. package/dist/{worktree-BL4M1rhB.mjs → worktree-DtRsh6go.mjs} +86 -50
  157. package/package.json +6 -5
  158. package/shim/native-android.gradle +101 -0
  159. package/dist/android-BXc6BmEi.mjs +0 -3732
  160. package/dist/android-BvV1gGdN.mjs +0 -4
  161. package/dist/ios-ITYno9rO.mjs +0 -2241
  162. package/dist/macos-nIOATJmR.mjs +0 -2
  163. package/dist/metro-store-BAHFcJm6.mjs +0 -106
  164. package/dist/miss-reason-CjQCOKqq.mjs +0 -1743
  165. package/dist/plan-placement-BVY59qa8.mjs +0 -290
  166. package/dist/project-B5eQ1USs.mjs +0 -612
  167. package/dist/react-native-ios-BMh2i25I.mjs +0 -2
  168. package/dist/server-expo-DGsdUGX2.mjs +0 -2
  169. package/dist/start-D8NbxNBb.mjs +0 -2
  170. package/dist/trigger-CoalsMTV.mjs +0 -2
  171. package/dist/web-DFpFeZu5.mjs +0 -2
  172. package/dist/worktree-DV-A0LNL.mjs +0 -2
@@ -0,0 +1,296 @@
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { d as androidToolPath } from "./android-DE8-JfGW.mjs";
3
+ import { b as parseSimctlList } from "./ios-o896T9PE.mjs";
4
+ import { n as easMachineStateRoot } from "./eas-session-ledger-DJDeL4Uq.mjs";
5
+ import { readdirSync, watch } from "node:fs";
6
+ import { join } from "node:path";
7
+ //#region src/status-watch.ts
8
+ const WATCH_FALLBACK_MS = 3e4;
9
+ const WATCH_LIGHT_INTERVAL_MS = 15e3;
10
+ const WATCH_SIMCTL_INTERVAL_MS = 5e3;
11
+ const ADB_RESTART_MIN_MS = 1e3;
12
+ const ADB_RESTART_MAX_MS = 6e4;
13
+ const SIMCTL_TIMEOUT_MS = 1e4;
14
+ /**
15
+ * Coalesces change signals into refreshes: a burst of full triggers runs `run('full')` once after `debounceMs` of
16
+ * quiet, at most one run is in flight, and a trigger that arrives during a run causes exactly one more run after it.
17
+ * A `light` trigger runs `run('light')` no sooner than `debounceMs` from the trigger and `lightIntervalMs` from the
18
+ * start of the previous run, unless a queued full run covers it; later light triggers do not postpone it.
19
+ */
20
+ function createRefreshScheduler({ debounceMs, lightIntervalMs = 0, run }) {
21
+ let timer = null;
22
+ let queued = "full";
23
+ let running = false;
24
+ let pending = null;
25
+ let stopped = false;
26
+ let lastRunAt = -Infinity;
27
+ const fire = async () => {
28
+ timer = null;
29
+ running = true;
30
+ lastRunAt = Date.now();
31
+ try {
32
+ await run(queued);
33
+ } finally {
34
+ running = false;
35
+ if (pending) {
36
+ const next = pending;
37
+ pending = null;
38
+ trigger(next);
39
+ }
40
+ }
41
+ };
42
+ function trigger(kind = "full", delayMs = debounceMs) {
43
+ if (stopped) return;
44
+ if (running) {
45
+ pending = pending === "full" ? "full" : kind;
46
+ return;
47
+ }
48
+ if (kind === "light") {
49
+ if (timer) return;
50
+ queued = "light";
51
+ timer = setTimeout(() => void fire(), Math.max(delayMs, lastRunAt + lightIntervalMs - Date.now()));
52
+ return;
53
+ }
54
+ if (timer) clearTimeout(timer);
55
+ queued = "full";
56
+ timer = setTimeout(() => void fire(), delayMs);
57
+ }
58
+ return {
59
+ trigger,
60
+ stop() {
61
+ stopped = true;
62
+ if (timer) clearTimeout(timer);
63
+ timer = null;
64
+ }
65
+ };
66
+ }
67
+ /**
68
+ * Which refresh a change to `name` in a watched `$STIM_HOME` directory needs: `light` for a log append or a running
69
+ * build's detail, which can change only the log-derived fields, `full` for anything else that can change the payload,
70
+ * null for none. A null name means the platform did not report one.
71
+ */
72
+ function statusChange(dir, name) {
73
+ if (dir === "archive" && (name?.startsWith(".incoming-") || name?.startsWith(".removing-") || name?.startsWith(".lock"))) return null;
74
+ if (name?.includes(".lock")) return null;
75
+ if (dir === "logs") return "light";
76
+ if (name === null) return "full";
77
+ switch (dir) {
78
+ case "home":
79
+ if (name === "maintenance") return "light";
80
+ return name.startsWith("config.json") || name === "archive" || name === "workspaces" || name === "device-locks" ? "full" : null;
81
+ case "workspace":
82
+ if (name.startsWith("build-detail.json")) return "light";
83
+ return name.startsWith("state.json") || name.startsWith("ended-agents.json") || name === "logs" ? "full" : null;
84
+ case "maintenance": return name === "state.json" ? "light" : null;
85
+ case "eas": return name.startsWith("sessions.json") ? "full" : null;
86
+ default: return "full";
87
+ }
88
+ }
89
+ /** A stable summary of every simulator's state, or null when the listing is unreadable. */
90
+ function simulatorSignature(simctlJson) {
91
+ try {
92
+ return parseSimctlList(simctlJson, { includeUnavailable: true }).map((sim) => `${sim.udid}:${sim.state}`).toSorted().join(",");
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Calls `onChange` when anything `stim status` reports may have changed:
99
+ * `$STIM_HOME` files, adb device arrivals and departures, and simulator
100
+ * state. simctl has no push API reachable from Node, so it is polled.
101
+ */
102
+ function watchStatusSources({ home, onChange, platform = process.platform, simctlIntervalMs = WATCH_SIMCTL_INTERVAL_MS }) {
103
+ let stopped = false;
104
+ const watchers = /* @__PURE__ */ new Map();
105
+ const desiredDirs = () => {
106
+ const dirs = /* @__PURE__ */ new Map([
107
+ [home, "home"],
108
+ [join(home, "archive"), "archive"],
109
+ [join(home, "workspaces"), "workspaces"],
110
+ [join(home, "maintenance"), "maintenance"],
111
+ [join(home, "device-locks"), "leases"],
112
+ [easMachineStateRoot(), "eas"]
113
+ ]);
114
+ let names = [];
115
+ try {
116
+ names = readdirSync(join(home, "workspaces"));
117
+ } catch {}
118
+ for (const name of names) {
119
+ const dir = join(home, "workspaces", name);
120
+ dirs.set(dir, "workspace");
121
+ dirs.set(join(dir, "logs"), "logs");
122
+ }
123
+ return dirs;
124
+ };
125
+ const reconcile = () => {
126
+ if (stopped) return;
127
+ const desired = desiredDirs();
128
+ for (const [dir, watcher] of watchers) if (!desired.has(dir)) {
129
+ watcher.close();
130
+ watchers.delete(dir);
131
+ }
132
+ for (const [dir, kind] of desired) {
133
+ if (watchers.has(dir)) continue;
134
+ try {
135
+ const watcher = watch(dir, (_event, name) => {
136
+ const change = statusChange(kind, name === null ? null : String(name));
137
+ if (!change) return;
138
+ if (kind === "home" || kind === "workspaces" || kind === "workspace") {
139
+ listingStaleBefore = Date.now();
140
+ reconcile();
141
+ }
142
+ onChange(change);
143
+ });
144
+ watcher.on("error", () => {
145
+ watcher.close();
146
+ watchers.delete(dir);
147
+ });
148
+ watchers.set(dir, watcher);
149
+ } catch {}
150
+ }
151
+ };
152
+ const adb = trackAdbDevices(() => onChange("full"));
153
+ let simctl = null;
154
+ let listing = null;
155
+ let listingStaleBefore = 0;
156
+ let simTimer = null;
157
+ if (platform === "darwin") {
158
+ let last = null;
159
+ const check = () => {
160
+ if (simctl || stopped) return;
161
+ const startedAt = Date.now();
162
+ let out = "";
163
+ const child = getExecutor().spawn("xcrun", [
164
+ "simctl",
165
+ "list",
166
+ "devices",
167
+ "--json"
168
+ ], {
169
+ stdio: [
170
+ "ignore",
171
+ "pipe",
172
+ "ignore"
173
+ ],
174
+ timeout: SIMCTL_TIMEOUT_MS,
175
+ killSignal: "SIGKILL"
176
+ });
177
+ simctl = child;
178
+ child.stdout?.on("data", (chunk) => out += chunk.toString());
179
+ child.on("error", () => {
180
+ simctl = null;
181
+ });
182
+ child.on("close", () => {
183
+ simctl = null;
184
+ const signature = simulatorSignature(out);
185
+ if (signature === null || stopped) return;
186
+ listing = {
187
+ at: startedAt,
188
+ json: out
189
+ };
190
+ if (last !== null && signature !== last) onChange("full");
191
+ last = signature;
192
+ });
193
+ };
194
+ check();
195
+ simTimer = setInterval(check, simctlIntervalMs);
196
+ }
197
+ reconcile();
198
+ return {
199
+ reconcile,
200
+ simulatorListing: () => listing && listing.at > listingStaleBefore && Date.now() - listing.at <= 2 * simctlIntervalMs ? listing.json : null,
201
+ stop() {
202
+ stopped = true;
203
+ for (const watcher of watchers.values()) watcher.close();
204
+ watchers.clear();
205
+ if (simTimer) clearInterval(simTimer);
206
+ simctl?.kill("SIGKILL");
207
+ adb.stop();
208
+ }
209
+ };
210
+ }
211
+ /**
212
+ * Runs `adb track-devices` and calls `onChange` on every device list it
213
+ * reports. adb exits when its server restarts, so the tracker restarts with a
214
+ * doubling delay that resets once a run lasts a minute.
215
+ */
216
+ function trackAdbDevices(onChange) {
217
+ const exec = getExecutor();
218
+ const resolved = androidToolPath("adb");
219
+ const adb = resolved === "adb" ? exec.findExecutable("adb") : resolved;
220
+ if (!adb) return { stop() {} };
221
+ let child = null;
222
+ let restart = null;
223
+ let delay = ADB_RESTART_MIN_MS;
224
+ let stopped = false;
225
+ const start = () => {
226
+ restart = null;
227
+ if (stopped) return;
228
+ const startedAt = Date.now();
229
+ const current = exec.spawn(adb, ["track-devices"], { stdio: [
230
+ "ignore",
231
+ "pipe",
232
+ "ignore"
233
+ ] });
234
+ child = current;
235
+ current.stdout?.on("data", () => onChange());
236
+ current.on("error", () => {});
237
+ current.on("close", () => {
238
+ if (child === current) child = null;
239
+ if (stopped) return;
240
+ if (Date.now() - startedAt >= ADB_RESTART_MAX_MS) delay = ADB_RESTART_MIN_MS;
241
+ restart = setTimeout(start, delay);
242
+ delay = Math.min(delay * 2, ADB_RESTART_MAX_MS);
243
+ });
244
+ };
245
+ start();
246
+ return { stop() {
247
+ stopped = true;
248
+ if (restart) clearTimeout(restart);
249
+ child?.kill("SIGTERM");
250
+ } };
251
+ }
252
+ function ownerKey(owner) {
253
+ return JSON.stringify([
254
+ owner.kind,
255
+ owner.name,
256
+ owner.workspace,
257
+ owner.slot ?? null,
258
+ owner.id,
259
+ owner.owned
260
+ ]);
261
+ }
262
+ function ownerSteady(before, after) {
263
+ return Math.abs(after.cpuPercent - before.cpuPercent) < 5 && Math.abs(after.memoryMb - before.memoryMb) < 16;
264
+ }
265
+ /**
266
+ * The payload `status --watch --json` prints. A usage figure keeps its value from the `previous` printed payload until it moves by a step: an owner's `cpuPercent`
267
+ * and `memoryMb`, an environment's `memoryMb` and `capacity.committedMb`. An owner's row is kept whole, `residentMb`
268
+ * and `processes` included, until one of its two figures moves, so a Mac whose processes only jitter prints no new line.
269
+ */
270
+ function watchPayload(previous, next) {
271
+ const payload = { ...next };
272
+ if (!previous) return payload;
273
+ if (previous.machine && next.machine && previous.machine.memorySource === next.machine.memorySource) {
274
+ const before = new Map(previous.machine.owners.map((owner) => [ownerKey(owner), owner]));
275
+ payload.machine = {
276
+ ...next.machine,
277
+ owners: next.machine.owners.map((owner) => {
278
+ const old = before.get(ownerKey(owner));
279
+ return old && ownerSteady(old, owner) ? old : owner;
280
+ })
281
+ };
282
+ }
283
+ const memory = new Map(previous.environments.map((env) => [env.path, env]));
284
+ payload.environments = payload.environments.map((env) => {
285
+ const old = memory.get(env.path);
286
+ return old && old.memorySource === env.memorySource && Math.abs(env.memoryMb - old.memoryMb) < 16 ? {
287
+ ...env,
288
+ memoryMb: old.memoryMb
289
+ } : env;
290
+ });
291
+ const { capacity } = previous;
292
+ if (capacity.overCapacity === next.capacity.overCapacity && capacity.liveCount === next.capacity.liveCount && capacity.totalMemoryMb === next.capacity.totalMemoryMb && Math.abs(next.capacity.committedMb - capacity.committedMb) < 16) payload.capacity = capacity;
293
+ return payload;
294
+ }
295
+ //#endregion
296
+ export { watchStatusSources as a, watchPayload as i, WATCH_LIGHT_INTERVAL_MS as n, createRefreshScheduler as r, WATCH_FALLBACK_MS as t };
@@ -1,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
2
  //#region src/devices/stim-desktop.ts
3
3
  const LAUNCH_SERVICES_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationWithBundleIdentifier('dev.stim.desktop'); url.isNil() ? '' : url.path.js`;
4
4
  const SCHEME_HANDLER_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationToOpenURL($.NSURL.URLWithString('stim-desktop://workspace')); url.isNil() ? '' : url.path.js`;
@@ -1,22 +1,22 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { n as debugLog } from "./exec-i8GDPwq9.mjs";
3
- import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-Bt8ygHE7.mjs";
4
- import { B as parseDeviceSlotKey, D as withConfigLock$1, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
5
- import { a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-CR9X86xJ.mjs";
6
- import { C as clearRemoteSession, E as readMetroTunnel, O as readRemoteSession, S as clearManagedMetroTunnel, T as clearWorkspaceSupervisor, n as findCommandWorkspace, w as clearWorkspaceLaunches } from "./project-B5eQ1USs.mjs";
7
- import { d as signalProcessTree, r as killMetroTree, s as pidExists, u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
8
- import { b as withdrawDevServerStopRequest, g as logVanishedSupervisor, v as requestDevServerStop } from "./budget-Dz-kyXLv.mjs";
9
- import { D as teardownOwnedAvd, O as teardownOwnedBrowser, g as stopTunnel, k as teardownOwnedIosSim, m as resolveSupervisorTarget } from "./workspaces-Djb2gfi9.mjs";
10
- import { n as fileLeaseIo, u as releaseWorkspaceLeases } from "./device-lease-Cu7PtQpZ.mjs";
11
- import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
12
- import { t as macosAppPresent } from "./state-Tp4uImDS.mjs";
13
- import { _ as nativeRunHolder, d as NATIVE_RUN_LOCK, f as NATIVE_RUN_WAIT_MS, g as describeNativeRunHolder, h as decideStopAction, m as clearNativeRunCancel, v as nativeRunWaitNotice, y as requestNativeRunCancel } from "./client-CuUo8Nvg.mjs";
14
- import { i as stopHostedAndroid } from "./hosted-android-Bs7fytj7.mjs";
15
- import { f as resolveEasCliBin } from "./remote-cache-N3hAEaAL.mjs";
16
- import { i as endRecordedSession } from "./device-remote-B5GiUifk.mjs";
17
- import { n as verifyCollectorOwnership } from "./ownership-EB0ySdGK.mjs";
18
- import { r as stopHostedIos } from "./hosted-ios-Bik035eL.mjs";
19
- import { n as stopMacosApp } from "./stop-D0UIpZuh.mjs";
2
+ import { n as debugLog } from "./exec-B81Qodjn.mjs";
3
+ import { B as parseDeviceSlotKey, D as withConfigLock$1, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-D0LhTY3S.mjs";
4
+ import { n as fileLeaseIo, u as releaseWorkspaceLeases } from "./device-lease-C309csaB.mjs";
5
+ import { a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, x as workspaceDir } from "./workspace-state-CvgTFe-h.mjs";
6
+ import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CPDq_90S.mjs";
7
+ import { A as clearWorkspaceSupervisor, D as clearManagedMetroTunnel, N as readRemoteSession, O as clearRemoteSession, j as readMetroTunnel, k as clearWorkspaceLaunches, n as findCommandWorkspace, w as MODE_COMMAND } from "./project-DX8fXyw_.mjs";
8
+ import { d as signalProcessTree, r as killMetroTree, s as pidExists, u as resolveProjectMetro } from "./metro-_ZIE3Axg.mjs";
9
+ import { D as stopTunnel, P as resolveSupervisorTarget, b as teardownOwnedIosSim, v as teardownOwnedAvd, y as teardownOwnedBrowser } from "./workspaces-C4kqIOlx.mjs";
10
+ import { _t as withdrawDevServerStopRequest, ht as requestDevServerStop, pt as logVanishedSupervisor } from "./budget-RFbwFpG5.mjs";
11
+ import { a as withWorkspaceProcessLock } from "./named-ports-O1TIl7tx.mjs";
12
+ import { _ as nativeRunHolder, d as NATIVE_RUN_LOCK, f as NATIVE_RUN_WAIT_MS, g as describeNativeRunHolder, h as decideStopAction, m as clearNativeRunCancel, v as nativeRunWaitNotice, y as requestNativeRunCancel } from "./tailnet-D7-tE_ug.mjs";
13
+ import { f as resolveEasCliBin } from "./remote-cache-fxcl5C-L.mjs";
14
+ import { t as macosAppPresent } from "./state-BUpAmt2r.mjs";
15
+ import { i as stopHostedAndroid } from "./hosted-android-C-D8Dj0_.mjs";
16
+ import { i as endRecordedSession } from "./device-remote-DjsNw8DD.mjs";
17
+ import { n as verifyCollectorOwnership } from "./ownership-BrjepDiv.mjs";
18
+ import { r as stopHostedIos } from "./hosted-ios-Chx9XQyI.mjs";
19
+ import { n as stopMacosApp } from "./stop-Cftw_sXJ.mjs";
20
20
  import { hostedAndroidDeviceName, hostedAndroidRecords, hostedIosRecords, hostedNativeRecords, isJsonObject, parseHostedNativePlacement } from "@stim-cli/core/state";
21
21
  import chalk from "chalk";
22
22
  //#region src/commands/stop.ts
@@ -263,7 +263,7 @@ async function stopWorkspaceMacos(root, failed, enabled) {
263
263
  };
264
264
  }
265
265
  }
266
- async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid) => signalProcessTree(pid), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, hostedSlot, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
266
+ async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid, group) => signalProcessTree(pid, "SIGTERM", { group }), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, hostedSlot, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
267
267
  const proj = project === void 0 ? getProject(root) : project;
268
268
  const sup = state === void 0 ? readSupervisorState(root) : state;
269
269
  const collectorRecords = collectors === void 0 ? readCollectorState(root) : collectors;
@@ -646,6 +646,7 @@ async function stopSupervisor(target, { root, killGroup, waiter, report }) {
646
646
  const reason = `supervisor pid ${target.pid} did not exit within ${Math.round(DEFAULT_WAIT_MS / 1e3)}s of SIGTERM`;
647
647
  report(chalk.red(phaseLine("stop", reason)));
648
648
  report(chalk.dim(phaseLine("", `inspect it with \`ps -p ${target.pid}\`, or signal it yourself: kill -9 -${target.pid}`)));
649
+ if (target.mode === "command-child") report(chalk.dim(phaseLine("", "metro.command runs in its own process group: once the supervisor is gone, run stim stop again to stop it")));
649
650
  return {
650
651
  status: "timeout",
651
652
  pid: target.pid,
@@ -678,7 +679,7 @@ async function stopMetro(port, root, { server, supervisorGone, signalServer, ins
678
679
  report(chalk.dim(phaseLine("metro", `sending SIGTERM to dev server pid ${serverPid} left by the supervisor`)));
679
680
  let signalled = false;
680
681
  try {
681
- signalled = signalServer(serverPid);
682
+ signalled = signalServer(serverPid, server?.mode === MODE_COMMAND);
682
683
  } catch {}
683
684
  if (signalled ? await waiter(serverPid, serverProcessToken) : ["gone", "different"].includes(inspectIdentity(serverRecord))) {
684
685
  report(chalk.green(phaseLine("metro", `dev server pid ${serverPid}`)));
@@ -1,3 +1,3 @@
1
- import { m as resolveSupervisorTarget } from "./workspaces-Djb2gfi9.mjs";
2
- import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-zDlknFoz.mjs";
1
+ import { P as resolveSupervisorTarget } from "./workspaces-C4kqIOlx.mjs";
2
+ import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-BO80KJoT.mjs";
3
3
  export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop, stopWorkspaceNow };
@@ -1,9 +1,9 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { c as writeWorkspaceState, v as workspaceDir } from "./workspace-state-CR9X86xJ.mjs";
3
- import { C as runningBundleInstances } from "./workspaces-Djb2gfi9.mjs";
4
- import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
5
- import { a as macosRuntimeClaim, o as requiredMacosRecord } from "./state-Tp4uImDS.mjs";
6
- import { n as stopHostedMacos } from "./hosted-macos-DABm3ScO.mjs";
2
+ import { c as writeWorkspaceState, x as workspaceDir } from "./workspace-state-CvgTFe-h.mjs";
3
+ import { m as runningBundleInstances } from "./workspaces-C4kqIOlx.mjs";
4
+ import { a as withWorkspaceProcessLock } from "./named-ports-O1TIl7tx.mjs";
5
+ import { a as macosRuntimeClaim, o as requiredMacosRecord } from "./state-BUpAmt2r.mjs";
6
+ import { n as stopHostedMacos } from "./hosted-macos-ckTjN-0V.mjs";
7
7
  import { readMacosRecord } from "@stim-cli/core/state";
8
8
  //#region src/macos/stop.ts
9
9
  const APP_EXIT_MS = 5e3;
@@ -1,4 +1,4 @@
1
- import { a as readPidFile, i as clearWorkspaceSupervisor, n as MODE_EXPO, o as writePidFile, r as clearExpoMetroTunnel, t as MODE_BARE } from "./state-lKh8shBp.mjs";
1
+ import { a as clearWorkspaceSupervisor, i as clearExpoMetroTunnel, n as MODE_BARE, o as readPidFile, r as MODE_EXPO, s as writePidFile, t as SettingsObject } from "./settings-vk3mJGSm.mjs";
2
2
  import { t as NdjsonWriter } from "./ndjson-Du3j0AQ9.mjs";
3
3
  import { DevServerStopRecord, DeviceActivity, DeviceIdleShutdownRecord, IOS_SIMULATOR_APPS } from "@stim-cli/core/state";
4
4
  //#region src/supervisor/types.d.ts
@@ -21,6 +21,7 @@ type ServerStarter = (opts: {
21
21
  tunnel?: boolean;
22
22
  resetCache?: boolean;
23
23
  onTunnelUrl?: ((url: string) => void) | null;
24
+ settings?: SettingsObject;
24
25
  }) => Promise<ServerHandle>;
25
26
  //#endregion
26
27
  //#region src/supervisor/idle-stop.d.ts
@@ -91,13 +92,17 @@ interface RunSupervisorOptions {
91
92
  isExpo?: (projectRoot: string) => boolean;
92
93
  startBare?: ServerStarter | null;
93
94
  startExpo?: ServerStarter | null;
95
+ startCommand?: ((opts: Parameters<ServerStarter>[0] & {
96
+ command: readonly string[];
97
+ }) => Promise<ServerHandle>) | null;
98
+ settings?: SettingsObject | null;
94
99
  now?: () => number;
95
100
  onExit?: (code: number) => void;
96
101
  attachSignals?: boolean;
97
102
  stderr?: (line: string) => void;
98
103
  watchman?: WatchmanCommand;
99
104
  }
100
- declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, deviceIdleMinutes, deviceIdle, isExpo, startBare, startExpo, now, onExit, attachSignals, stderr, watchman }: RunSupervisorOptions): Promise<{
105
+ declare function runSupervisor({ root, port, tunnel, resetCache, idleStopMinutes, idleProbe, deviceIdleMinutes, deviceIdle, isExpo, startBare, startExpo, startCommand, settings: settingsOverride, now, onExit, attachSignals, stderr, watchman }: RunSupervisorOptions): Promise<{
101
106
  mode: string;
102
107
  server: ServerHandle | undefined;
103
108
  shutdown: (code: number, event: string, msg: string, stop?: DevServerStopRecord) => Promise<void>;
@@ -1,20 +1,21 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { B as parseDeviceSlotKey, H as projectDeviceSlots, T as setSupervisor, o as clearSupervisor, p as getProject } from "./config-DC5jEtd1.mjs";
3
- import { C as workspaceStateFile, a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, x as workspaceLogsDir$1 } from "./workspace-state-CR9X86xJ.mjs";
4
- import { D as readPidFile, T as clearWorkspaceSupervisor, b as MODE_EXPO, j as writePidFile, p as detectIsExpo, u as nativeProjectIntegration, x as clearExpoMetroTunnel, y as MODE_BARE } from "./project-B5eQ1USs.mjs";
5
- import { n as parseTriggerCount, o as runWatchman, r as parseWatchRoots, t as parseSubscriberNames } from "./watchman-BL1IdOtq.mjs";
6
- import { E as workspaceBuildInProgress, f as describeDevServerStop, h as devServerStopRecord, m as devServerStopLevel, y as vanishedSupervisorMessage } from "./budget-Dz-kyXLv.mjs";
7
- import { f as withIdleWorkspace } from "./workspaces-Djb2gfi9.mjs";
8
- import { m as workspaceDeviceLastUseAt, r as createActivityReader } from "./activity-BSw0x84R.mjs";
9
- import { a as parseLease, r as leaseIsExpired, s as parseWorkspaceLeases, t as deviceLeasePath } from "./device-lease-Cu7PtQpZ.mjs";
10
- import { z as ownedAvdSerialResolver } from "./android-BdQC6zs1.mjs";
11
- import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
12
- import { s as describeError } from "./metro-store-BAHFcJm6.mjs";
13
- import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
14
- import { n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-DYiMBn34.mjs";
15
- import { l as probeHostedSession } from "./hosted-client-C5G4h_OJ.mjs";
16
- import { t as clearHostedMetro } from "./metro-gateway-BxpJLIwh.mjs";
17
- import { t as relaunchWithLogFile } from "./detached-entry-pB_IPfV4.mjs";
2
+ import { B as parseDeviceSlotKey, H as projectDeviceSlots, T as setSupervisor, o as clearSupervisor, p as getProject } from "./config-D0LhTY3S.mjs";
3
+ import { J as runnableMetroCommand, K as resolveProjectSettings } from "./settings-Bbztm4oV.mjs";
4
+ import { a as parseLease, r as leaseIsExpired, s as parseWorkspaceLeases, t as deviceLeasePath } from "./device-lease-C309csaB.mjs";
5
+ import { E as workspaceStateFile, a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, w as workspaceLogsDir$1 } from "./workspace-state-CvgTFe-h.mjs";
6
+ import { A as clearWorkspaceSupervisor, C as MODE_BARE, E as clearExpoMetroTunnel, L as writePidFile, M as readPidFile, T as MODE_EXPO, _ as detectIsExpo, u as nativeProjectIntegration, w as MODE_COMMAND } from "./project-DX8fXyw_.mjs";
7
+ import { z as ownedAvdSerialResolver } from "./android-DE8-JfGW.mjs";
8
+ import { f as withIdleWorkspace } from "./workspaces-C4kqIOlx.mjs";
9
+ import { dt as devServerStopLevel, ft as devServerStopRecord, g as workspaceBuildInProgress, gt as vanishedSupervisorMessage, lt as describeDevServerStop } from "./budget-RFbwFpG5.mjs";
10
+ import { a as withWorkspaceProcessLock } from "./named-ports-O1TIl7tx.mjs";
11
+ import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
12
+ import { t as describeError } from "./errors-DzkMYh8Q.mjs";
13
+ import { t as relaunchWithLogFile } from "./detached-entry-BXq4fIl-.mjs";
14
+ import { n as parseTriggerCount, o as runWatchman, r as parseWatchRoots, t as parseSubscriberNames } from "./watchman-CqmaGcIb.mjs";
15
+ import { m as workspaceDeviceLastUseAt, r as createActivityReader } from "./activity-BaMpUQ4-.mjs";
16
+ import { n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-DhAUyf5s.mjs";
17
+ import { u as probeHostedSession } from "./hosted-client--hNFgixu.mjs";
18
+ import { t as clearHostedMetro } from "./metro-gateway-BzlQZQmU.mjs";
18
19
  import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
19
20
  import { dirname, isAbsolute, join, resolve, sep } from "node:path";
20
21
  import { DEV_SERVER_STOP_REQUEST_KEY, HOSTED_METRO_GATEWAYS_KEY, HOSTED_METRO_REQUESTS_KEY, IDLE_STOP_KEY, hostedAndroidPlacements, hostedIosPlacements, hostedMetroGateways, hostedMetroRequests, hostedNativeRecords, parseHostedNativePlacement, readDevServerStopRequest } from "@stim-cli/core/state";
@@ -157,7 +158,7 @@ function trackDevServerActivity(now) {
157
158
  if (typeof requestId === "string") open.add(requestId);
158
159
  } else if (event === "bundle_response_finished" || event === "bundle_response_failed") {
159
160
  if (typeof requestId === "string") open.delete(requestId);
160
- } else if (event !== "expo_stdout") return;
161
+ } else if (event !== "expo_stdout" && event !== "command_stdout") return;
161
162
  last = now();
162
163
  },
163
164
  lastActivityAt: () => open.size > 0 ? now() : last
@@ -463,12 +464,14 @@ const DEVICE_IDLE_OPS = {
463
464
  due: dueIdleDevices,
464
465
  shutDown: shutDownIdleDevices
465
466
  };
466
- 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 }) {
467
+ async function runSupervisor({ root, port, tunnel = false, resetCache = false, idleStopMinutes = 0, idleProbe, deviceIdleMinutes = 0, deviceIdle = DEVICE_IDLE_OPS, isExpo = detectIsExpo, startBare = null, startExpo = null, startCommand = null, settings: settingsOverride = null, now = Date.now, onExit = (code) => process.exit(code), attachSignals = true, stderr = (line) => console.error(line), watchman = runWatchman }) {
467
468
  root = realpathSync(root);
468
469
  const logsDir = workspaceLogsDir$1(root);
469
470
  const writer = createNdjsonWriter(join(logsDir, "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
470
471
  const integration = nativeProjectIntegration(root, isExpo);
471
- const mode = integration.mode;
472
+ const settings = settingsOverride ?? resolveProjectSettings(root).settings;
473
+ const command = runnableMetroCommand(settings);
474
+ const mode = command ? MODE_COMMAND : integration.mode;
472
475
  const startedAt = new Date(now()).toISOString();
473
476
  const processToken = (0, process_identity_exports.captureProcessToken)(process.pid);
474
477
  if (!processToken) {
@@ -597,13 +600,22 @@ async function runSupervisor({ root, port, tunnel = false, resetCache = false, i
597
600
  return writer.write(entry);
598
601
  } });
599
602
  try {
600
- server = await ((mode === "expo-child" ? startExpo : startBare) ?? await integration.loadDevServer())({
603
+ let start;
604
+ if (command) {
605
+ const startServer = startCommand ?? (await import("./server-command-DnJYLnr4.mjs")).startCommandServer;
606
+ start = (opts) => startServer({
607
+ ...opts,
608
+ command
609
+ });
610
+ } else start = (mode === "expo-child" ? startExpo : startBare) ?? await integration.loadDevServer();
611
+ server = await start({
601
612
  root,
602
613
  port,
603
614
  logsDir,
604
615
  writer: serverWriter,
605
616
  tunnel,
606
617
  resetCache,
618
+ settings,
607
619
  onTunnelUrl: (url) => {
608
620
  try {
609
621
  withWorkspaceStateLock(root, () => {
@@ -1,8 +1,8 @@
1
- import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
- import { C as emulatorFailureRemedy, D as hostSystemImageArch, K as profileNeedsFoldFeature, N as memoizeEmulatorProbe, S as emulatorDiskSpaceRemedy, T as findBuildTool, W as pickDefaultSystemImage, c as androidPoolNoCandidatesRefusal, l as androidSystemImageAbi, o as androidHome, s as androidPoolCandidates, w as extractEmulatorFailure } from "./android-BdQC6zs1.mjs";
3
- import { l as unknownAndroidDeviceProfileRefusal, o as layerNote, u as unknownAndroidSystemImageRefusal } from "./device-capacity-BoN1jQkO.mjs";
4
- import { T as pickDevClientScheme } from "./app-install-CFI4ptUL.mjs";
5
- import { t as devClientScheme } from "./dev-client-CDY_zAmD.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { C as emulatorFailureRemedy, D as hostSystemImageArch, K as profileNeedsFoldFeature, N as memoizeEmulatorProbe, S as emulatorDiskSpaceRemedy, T as findBuildTool, W as pickDefaultSystemImage, c as androidPoolNoCandidatesRefusal, l as androidSystemImageAbi, o as androidHome, s as androidPoolCandidates, w as extractEmulatorFailure } from "./android-DE8-JfGW.mjs";
3
+ import { T as pickDevClientScheme } from "./app-install-Cg9YJy3x.mjs";
4
+ import { l as unknownAndroidDeviceProfileRefusal, o as layerNote, u as unknownAndroidSystemImageRefusal } from "./device-capacity-DrwHwR97.mjs";
5
+ import { t as devClientScheme } from "./dev-client-BqYjMIaC.mjs";
6
6
  import { existsSync, readFileSync, readdirSync } from "node:fs";
7
7
  import { relative } from "node:path";
8
8
  //#region src/commands/android/support.ts
@@ -297,12 +297,22 @@ async function pooledAndroidDevice({ root, selectPool, listDevices, isEmulatorDe
297
297
  owned: false
298
298
  } };
299
299
  }
300
- function androidBuildOptions({ release, physical, device, variant, deviceAbi, compiler, buildProfile, targetAbiOnly = true, hostedAbi = null }) {
300
+ function androidGradleProject(layout) {
301
+ return layout.custom ? `${layout.gradleRootRelative} ${layout.module}` : null;
302
+ }
303
+ function androidJobLayout(layout) {
304
+ return layout.custom ? {
305
+ gradleRoot: layout.gradleRootRelative,
306
+ module: layout.module
307
+ } : {};
308
+ }
309
+ function androidBuildOptions({ release, physical, device, variant, deviceAbi, compiler, buildProfile, targetAbiOnly = true, hostedAbi = null, gradleProject = null }) {
301
310
  let abi = targetAbiOnly ? hostedAbi : null;
302
311
  if (targetAbiOnly && !release && physical && device.serial) abi = deviceAbi(device.serial);
303
312
  if (targetAbiOnly && !release && !physical) abi = androidSystemImageAbi(device.systemImage);
304
313
  const runOptions = {};
305
314
  if (variant) runOptions.variant = variant;
315
+ if (gradleProject) runOptions.gradleProject = gradleProject;
306
316
  if (abi) runOptions.abi = abi;
307
317
  if (compiler) runOptions.compiler = compiler;
308
318
  if (buildProfile) runOptions.buildProfile = buildProfile;
@@ -313,4 +323,4 @@ function androidBuildOptions({ release, physical, device, variant, deviceAbi, co
313
323
  };
314
324
  }
315
325
  //#endregion
316
- export { resolveSystemImage as C, resolveDeviceProfile as S, systemImageRefusal as T, isReleaseVariant as _, PLATFORM as a, pooledAndroidDevice as b, androidSystemImageSetting as c, apkPackage as d, deviceProfileRefusal as f, foldableImageRefusal as g, findAapt as h, NO_FINGERPRINT as i, androidVariantSetting as l, dumpApkManifest as m, LAUNCH_FAILED as n, androidBuildOptions as o, displayPath as p, NO_DEVICE as r, androidDevClientScheme as s, INSTALL_FAILED as t, apkDevClientFacts as u, noDeviceDiagnostic as v, resolveVariant as w, remoteAvdFlagRefusal as x, parseXmltree as y };
326
+ export { remoteAvdFlagRefusal as C, systemImageRefusal as D, resolveVariant as E, pooledAndroidDevice as S, resolveSystemImage as T, findAapt as _, PLATFORM as a, noDeviceDiagnostic as b, androidGradleProject as c, androidVariantSetting as d, apkDevClientFacts as f, dumpApkManifest as g, displayPath as h, NO_FINGERPRINT as i, androidJobLayout as l, deviceProfileRefusal as m, LAUNCH_FAILED as n, androidBuildOptions as o, apkPackage as p, NO_DEVICE as r, androidDevClientScheme as s, INSTALL_FAILED as t, androidSystemImageSetting as u, foldableImageRefusal as v, resolveDeviceProfile as w, parseXmltree as x, isReleaseVariant as y };