stim 1.9.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.
Files changed (83) hide show
  1. package/dist/{android-_y4Ohi5z.mjs → android-787HhP5w.mjs} +119 -29
  2. package/dist/{android-BPGizezh.mjs → android-DBkeHwpm.mjs} +168 -95
  3. package/dist/{android-DEgo4oCo.mjs → android-DPov-fv2.mjs} +2 -2
  4. package/dist/{android-cas-eiExNLf7.mjs → android-cas-CITmIeWY.mjs} +9 -8
  5. package/dist/android-cas-compiler.mjs +1 -1
  6. package/dist/{app-install-Uf3a83Tv.mjs → app-install-CrJ6t_bv.mjs} +2 -2
  7. package/dist/budget-BP4jZZL4.mjs +620 -0
  8. package/dist/build-progress-BXx-ZBe4.mjs +512 -0
  9. package/dist/{cache-manifest-Dg7OnMrp.mjs → cache-manifest-Pubfp8wV.mjs} +1 -1
  10. package/dist/cache-manifest.mjs +1 -1
  11. package/dist/cli.mjs +16 -16
  12. package/dist/collector-run.d.mts +5 -1
  13. package/dist/collector-run.mjs +7 -7
  14. package/dist/{command-output-gByVmIjy.mjs → command-output-D5z2_bcF.mjs} +1 -1
  15. package/dist/{config-Cp9lM3wX.mjs → config-BEq0Qw_a.mjs} +14 -131
  16. package/dist/{dependency-state-Bq5DcLGn.mjs → dependency-state-r9UesA9a.mjs} +2 -2
  17. package/dist/{deps-Cip5vUm1.mjs → deps-DP4eWqea.mjs} +3 -3
  18. package/dist/{detached-entry-KEu0_AXL.mjs → detached-entry-DJHoca49.mjs} +1 -1
  19. package/dist/{dev-client-HyqISM0h.mjs → dev-client-92U593KT.mjs} +137 -250
  20. package/dist/{device-D4U-xLty.mjs → device-DhTZe7L4.mjs} +7 -7
  21. package/dist/{build-lock-DPXPLgTc.mjs → device-lease-CbEaIk7b.mjs} +370 -12
  22. package/dist/{device-pool-CnTAz8X1.mjs → device-pool-Di8Q-9Ro.mjs} +4 -4
  23. package/dist/{device-remote-AQ5rQPqr.mjs → device-remote-Dy1jGj3U.mjs} +547 -468
  24. package/dist/{doctor-B_Ei3bZu.mjs → doctor-B-inAJmt.mjs} +58 -22
  25. package/dist/{error-diagnostics-Vfz83GCF.mjs → error-diagnostics-xxWKNO3-.mjs} +11 -12
  26. package/dist/{exec-jIAlgilk.mjs → exec-DK8KaVHK.mjs} +3 -2
  27. package/dist/{gc-Ckw8RQHi.mjs → gc-ChPFZMRC.mjs} +500 -1114
  28. package/dist/{guide-BiAbhs1J.mjs → guide-DwmaD_Wa.mjs} +882 -528
  29. package/dist/guide-status-CWvti2Lg.mjs +125 -0
  30. package/dist/idle-DpRLp5lj.mjs +157 -0
  31. package/dist/in-use-CjUluqIX.mjs +245 -0
  32. package/dist/{ios-BL2NFckr.mjs → ios-B2Fpqvlb.mjs} +25 -59
  33. package/dist/{ios-BzUJWk1K.mjs → ios-Dd-hYJBh.mjs} +130 -89
  34. package/dist/{ios-device-DPsSm0v_.mjs → ios-device-BiOsSVzd.mjs} +1 -1
  35. package/dist/{ios-device-D972i9wf.mjs → ios-device-CtRdEVjx.mjs} +3 -3
  36. package/dist/{launch-verify-Q_OtW1Rf.mjs → launch-verify-CQS_Kg-C.mjs} +5 -5
  37. package/dist/{logs-CI9NQSK7.mjs → logs-MARIy6m9.mjs} +9 -9
  38. package/dist/{metro-DrLHaMn2.mjs → metro-BWLOJ_Wr.mjs} +116 -10
  39. package/dist/{named-ports-CmLQSIRj.mjs → named-ports-DiTfSz6p.mjs} +4 -4
  40. package/dist/{ndjson-9uFNRwfe.mjs → ndjson-CDY9IkVC.mjs} +3 -56
  41. package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
  42. package/dist/{ownership-D15Op8vN.mjs → ownership-D2xbLVoz.mjs} +2 -3
  43. package/dist/ownership-DZjdx8Gq.mjs +1180 -0
  44. package/dist/{ports-BNKoWVWZ.mjs → ports-CLSSFOuz.mjs} +3 -3
  45. package/dist/{project-DS112DYB.mjs → project-BXZzOABt.mjs} +2 -2
  46. package/dist/{reload-ZNJUo1pl.mjs → reload-DoETJ3rl.mjs} +9 -10
  47. package/dist/{server-bare-DWkkcIxV.mjs → server-bare-DVbb7kXH.mjs} +1 -1
  48. package/dist/{server-expo-B_lctBR3.mjs → server-expo-BvOCeakp.mjs} +4 -4
  49. package/dist/server-expo-DBVTdult.mjs +2 -0
  50. package/dist/{settings-D030k0t4.mjs → settings-DOugPlPz.mjs} +16 -428
  51. package/dist/{settings-BKNh5rl4.mjs → settings-EWYNwe72.mjs} +16 -14
  52. package/dist/settings.schema.json +75 -0
  53. package/dist/{simslim-B_LsGLuJ.mjs → simslim-Ca3487H6.mjs} +182 -5
  54. package/dist/{slot-launch-DU9A-gYw.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
  55. package/dist/{spawn-claims-Dn3C_N6w.mjs → spawn-claims-CUleC2cM.mjs} +1 -1
  56. package/dist/{start-DYkkKF0s.mjs → start-F9gv5dcC.mjs} +147 -98
  57. package/dist/start-VoFsPSes.mjs +2 -0
  58. package/dist/{state-NcJzMEBF.mjs → state-WGdIbi_d.mjs} +2 -2
  59. package/dist/{stats-DG9e66Rz.mjs → stats-BAgJaLA4.mjs} +1 -1
  60. package/dist/{stats-B63-JVAY.mjs → stats-DBYJ5bxL.mjs} +4 -4
  61. package/dist/{status-S6ehL4Ui.mjs → status-DLCD-o3s.mjs} +63 -231
  62. package/dist/status-Dr4fRkym.mjs +216 -0
  63. package/dist/{guide-status-BAMVU0ZA.mjs → stim-installations-CINXy_su.mjs} +3 -124
  64. package/dist/{stop-BO28HGqF.mjs → stop-Dj4pfmyv.mjs} +22 -18
  65. package/dist/{stop-T1R-cZRz.mjs → stop-ZvOeTmKb.mjs} +2 -2
  66. package/dist/supervisor-run.d.mts +11 -2
  67. package/dist/supervisor-run.mjs +185 -17
  68. package/dist/{workspace-process-lock-DWaiRD0e.mjs → workspace-process-lock-BXA96myD.mjs} +2 -2
  69. package/dist/workspaces-BTUyFfkv.mjs +1003 -0
  70. package/dist/{worktree-DKhSF0UX.mjs → worktree-4aZg2NnI.mjs} +1 -1
  71. package/dist/{worktree-LGB-UwgG.mjs → worktree-BMS7GeqB.mjs} +40 -122
  72. package/dist/{worktree-R_cUlE7s.mjs → worktree-BlizKDpZ.mjs} +143 -18
  73. package/dist/{xcode-BZqyxh3e.mjs → xcode-B2tBkf0m.mjs} +9 -158
  74. package/package.json +6 -5
  75. package/dist/build-progress-CVqkfPC6.mjs +0 -188
  76. package/dist/device-lease-Crs-HkJY.mjs +0 -366
  77. package/dist/logs-query-Cqma3WIu.mjs +0 -298
  78. package/dist/ownership-DCQPuWEc.mjs +0 -489
  79. package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
  80. package/dist/server-expo-CeILEu86.mjs +0 -2
  81. package/dist/sim-pool-KaIsp2Ft.mjs +0 -723
  82. package/dist/spawn-entry-nCE6m770.mjs +0 -14
  83. package/dist/workspace-state-DF2gCFhx.mjs +0 -169
@@ -1,45 +1,32 @@
1
- import { D as process_identity_exports, a as clearSupervisor, f as getProject, w as upsertProject } from "./config-Cp9lM3wX.mjs";
2
- import { t as getExecutor } from "./exec-jIAlgilk.mjs";
3
- import { i as levelRank } from "./ndjson-9uFNRwfe.mjs";
4
- import { b as workspaceLogsDir, c as writeWorkspaceState, i as recordWorkspaceUse, m as supervisorLogFile, r as readWorkspaceState, u as ensureWorkspaceStorage } from "./workspace-state-DF2gCFhx.mjs";
5
- import { _ as repoRoot, s as gitCommonDir } from "./worktree-R_cUlE7s.mjs";
6
- import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, r as detectAndroidPackage, t as NO_PROJECT_REFUSAL } from "./project-DS112DYB.mjs";
7
- import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
8
- import { n as windowsLauncherArgs } from "./detached-entry-KEu0_AXL.mjs";
9
- import { i as clearManagedMetroTunnel, o as clearWorkspaceSupervisor, s as readMetroTunnel } from "./state-NcJzMEBF.mjs";
10
- import { a as pidExists, c as resolveProjectMetro, f as reserveMetroPort, l as signalProcessTree, n as killMetroTree } from "./metro-DrLHaMn2.mjs";
11
- import { D as remoteIosSetting, E as remoteAndroidSetting, F as unknownSettingKeys, G as planMetroReach, M as settingShapeErrors, O as resolveCacheProviderConfig, P as tunnelModeSetting, U as PUBLIC_METRO_ENV, W as detectProviders, i as SETTING_SHAPE_REMEDY, k as resolveSettings, u as cacheProviderSettingError, w as publicUrlSetting, x as ngrokUrlSetting, y as metroTunnelSettingError } from "./settings-D030k0t4.mjs";
12
- import { _ as stepTimer, l as phaseLine } from "./command-output-gByVmIjy.mjs";
13
- import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-DWaiRD0e.mjs";
14
- import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
15
- import { l as queryLogs } from "./logs-query-Cqma3WIu.mjs";
16
- import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-DCQPuWEc.mjs";
1
+ import { D as process_identity_exports, f as getProject, w as upsertProject } from "./config-BEq0Qw_a.mjs";
2
+ import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
+ import { i as levelRank } from "./ndjson-CDY9IkVC.mjs";
4
+ import { T as supervisorLogFile, c as signalProcessTree, d as reserveMetroPort, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, p as clearWorkspaceStateKeys, s as resolveProjectMetro, x as ensureWorkspaceStorage, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
5
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
6
+ import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, r as detectAndroidPackage, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
7
+ import { n as windowsLauncherArgs } from "./detached-entry-DJHoca49.mjs";
8
+ import { i as clearManagedMetroTunnel, s as readMetroTunnel } from "./state-WGdIbi_d.mjs";
9
+ import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
10
+ import { _ as stepTimer, l as phaseLine } from "./command-output-D5z2_bcF.mjs";
11
+ import { A as resolveCacheProviderConfig, B as planMetroReach, C as ngrokUrlSetting, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, O as remoteAndroidSetting, P as settingShapeErrors, R as PUBLIC_METRO_ENV, a as SETTING_SHAPE_REMEDY, b as metroIdleStopMinutesSetting, d as cacheProviderSettingError, j as resolveSettings, k as remoteIosSetting, x as metroTunnelSettingError, z as detectProviders } from "./settings-DOugPlPz.mjs";
12
+ import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-DZjdx8Gq.mjs";
13
+ import { i as stopOwnedMetroForReset, t as budgetGate } from "./budget-BP4jZZL4.mjs";
17
14
  import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
18
- import { dirname } from "node:path";
15
+ import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
16
+ import { basename, dirname, join } from "node:path";
19
17
  import { EventEmitter } from "node:events";
18
+ import { fileURLToPath } from "node:url";
20
19
  import chalk from "chalk";
21
20
  import { CACHE_PROVIDER_ENV, cacheProviderEnv } from "@stim-cli/cache";
22
- //#region src/supervisor/cache-reset.ts
23
- async function stopOwnedMetroForReset(root) {
24
- const project = getProject(root);
25
- const port = project?.metroPort;
26
- const target = resolveSupervisorTarget({
27
- state: readWorkspaceState(root)?.supervisor,
28
- record: project?.supervisor,
29
- reservedPort: port
30
- });
31
- if (target.status === "unverified") throw supervisorError("STIM_SUPERVISOR_EXITED", `Cannot reset Metro: ${target.reason}.`, "Stop it with the tool that started it, then retry. Stim leaves unverified processes alone.");
32
- if (port && target.status !== "ours" && !(await resolveProjectMetro(port, root)).missing) throw supervisorError("STIM_SUPERVISOR_EXITED", "Cannot reset an externally started dev server.", "Stop it with the tool that started it, then retry `stim start --reset-cache`.");
33
- if (target.status === "ours") {
34
- const expected = {
35
- pid: target.pid,
36
- processToken: target.processToken
37
- };
38
- if (!killMetroTree(target.pid, target.processToken) || !await (0, process_identity_exports.waitForProcessExit)(expected, 1e4)) throw supervisorError("STIM_SUPERVISOR_EXITED", "The owned Metro supervisor could not be stopped for a cache reset.", "Inspect `stim status` and `stim logs`, then retry. No cache reset was recorded.");
39
- if (port && !(await resolveProjectMetro(port, root)).missing) throw supervisorError("STIM_SUPERVISOR_EXITED", `Port ${port} is still occupied after stopping Metro.`, "Inspect the listener before retrying. Stim does not terminate unrecorded processes.");
40
- clearWorkspaceSupervisor(root, expected);
41
- clearSupervisor(root, expected);
42
- }
21
+ //#region src/spawn-entry.ts
22
+ const DEV_ENTRIES = {
23
+ "supervisor-run": "./supervisor/run.ts",
24
+ "collector-run": "./collector/run.ts"
25
+ };
26
+ function spawnEntry(name) {
27
+ const here = fileURLToPath(import.meta.url);
28
+ if (basename(dirname(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
29
+ return join(dirname(here), `${name}.mjs`);
43
30
  }
44
31
  //#endregion
45
32
  //#region src/commands/start.ts
@@ -142,6 +129,7 @@ const DEFAULT_START_DEPS = {
142
129
  withWorktreeLock: withManagedRemoteWorktreeLock,
143
130
  withTunnelLock: withManagedTunnelLock,
144
131
  clearTunnelRecord: clearManagedMetroTunnel,
132
+ budgetGate,
145
133
  platform: process.platform
146
134
  };
147
135
  function normalizeManagedTunnelUrl(url) {
@@ -154,22 +142,24 @@ function registerStart(program, overrides = {}) {
154
142
  };
155
143
  program.command("start").description("Start this workspace's dev server under a detached supervisor and wait until it verifies as this project's. Idempotent: a healthy dev server on the reserved port is a no-op. Structured logs land in the global workspace logs directory.").option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--wait <seconds>", `How long to wait for the dev server to answer (default ${DEFAULT_WAIT_SECONDS})`).option("--remote", "Prepare the dev server for a remote device").option("--reset-cache", "Restart owned Metro and clear this app's Metro caches").action(async (opts) => {
156
144
  const json = Boolean(opts.json);
157
- const waitTimer = stepTimer();
158
145
  const out = (line) => {
159
146
  if (json) console.error(line);
160
147
  else console.log(line);
161
148
  };
162
149
  const note = writeNote;
163
- const fail = ({ code, message, remedy = null, lines = [] }) => {
150
+ const fail = ({ code, message, remedy = null, lines = [], reclaimed = [] }) => {
164
151
  note(chalk.red(message));
165
152
  for (const line of lines) note(chalk.dim(` ${line}`));
166
153
  if (remedy) note(chalk.dim(remedy));
167
154
  note(chalk.red(`failed: ${code}`));
168
- if (json) console.log(JSON.stringify(startError({
169
- code,
170
- message,
171
- remedy
172
- })));
155
+ if (json) console.log(JSON.stringify({
156
+ ...startError({
157
+ code,
158
+ message,
159
+ remedy
160
+ }),
161
+ ...reclaimed.length ? { reclaimed } : {}
162
+ }));
173
163
  process.exit(1);
174
164
  };
175
165
  const wait = parseWait(opts.wait);
@@ -197,12 +187,10 @@ function registerStart(program, overrides = {}) {
197
187
  });
198
188
  }
199
189
  recordWorkspaceUse(root);
200
- const isExpo = detectIsExpo(root);
201
- const worktreeRoot = repoRoot(root) ?? root;
202
190
  const settingsContext = {
203
191
  projectPath: root,
204
192
  gitCommonDir: gitCommonDir(root),
205
- repoRoot: worktreeRoot
193
+ repoRoot: repoRoot(root) ?? root
206
194
  };
207
195
  const settings = resolveSettings(settingsContext);
208
196
  const [shapeError, ...moreShapeErrors] = settingShapeErrors(settings);
@@ -212,17 +200,64 @@ function registerStart(program, overrides = {}) {
212
200
  lines: moreShapeErrors,
213
201
  remedy: SETTING_SHAPE_REMEDY
214
202
  });
215
- const cacheProvider = resolveCacheProviderConfig(settingsContext);
216
203
  for (const key of unknownSettingKeys(settings)) note(chalk.yellow(`Warning: setting "${key}" is not read by Stim and will be ignored.`));
217
204
  const cacheProviderError = cacheProviderSettingError(settings);
218
205
  if (cacheProviderError) note(chalk.yellow(`Warning: ${cacheProviderError} No cache provider is used.`));
206
+ const result = await startDevServer({
207
+ root,
208
+ settings,
209
+ waitSeconds,
210
+ remote: Boolean(opts.remote),
211
+ resetCache: Boolean(opts.resetCache),
212
+ out,
213
+ note
214
+ }, d);
215
+ if (!result.ok) return fail({
216
+ ...result.error,
217
+ lines: result.lines,
218
+ reclaimed: result.reclaimed
219
+ });
220
+ report({
221
+ json,
222
+ out,
223
+ facts: result.facts,
224
+ waited: result.waited,
225
+ reclaimed: result.reclaimed
226
+ });
227
+ });
228
+ }
229
+ var StartRefusal = class extends Error {
230
+ refusal;
231
+ constructor(refusal) {
232
+ super(refusal.message);
233
+ this.refusal = refusal;
234
+ }
235
+ };
236
+ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECONDS, remote: remoteFlag = false, resetCache = false, out, note }, overrides = {}) {
237
+ const d = {
238
+ ...DEFAULT_START_DEPS,
239
+ ...overrides
240
+ };
241
+ const waitTimer = stepTimer();
242
+ let reclaimed = [];
243
+ const fail = (refusal) => {
244
+ throw new StartRefusal(refusal);
245
+ };
246
+ const isExpo = detectIsExpo(root);
247
+ const worktreeRoot = repoRoot(root) ?? root;
248
+ const cacheProvider = resolveCacheProviderConfig({
249
+ projectPath: root,
250
+ gitCommonDir: gitCommonDir(root),
251
+ repoRoot: worktreeRoot
252
+ });
253
+ const run = async () => {
219
254
  const settingError = metroTunnelSettingError(settings);
220
255
  if (settingError) return fail({
221
256
  code: "STIM_BAD_ARG",
222
257
  message: settingError,
223
258
  remedy: "Set metro.tunnel to \"ngrok\" and metro.ngrokUrl to an HTTPS URL, or remove metro.ngrokUrl."
224
259
  });
225
- const remote = Boolean(opts.remote) || remoteIosSetting(settings) !== null || remoteAndroidSetting(settings) !== null;
260
+ const remote = remoteFlag || remoteIosSetting(settings) !== null || remoteAndroidSetting(settings) !== null;
226
261
  const tunnelMode = tunnelModeSetting(settings) ?? "auto";
227
262
  const publicUrl = publicUrlSetting(settings);
228
263
  const tunnel = wantsExpoOwnTunnel({
@@ -239,7 +274,16 @@ function registerStart(program, overrides = {}) {
239
274
  androidPackage: detectAndroidPackage(root) ?? void 0,
240
275
  isExpo
241
276
  });
242
- if (opts.resetCache) {
277
+ const gateBudget = async () => {
278
+ const budget = await d.budgetGate({
279
+ root,
280
+ note
281
+ });
282
+ reclaimed = budget.reclaimed;
283
+ if (budget.refusal) return fail(budget.refusal);
284
+ };
285
+ if (resetCache) {
286
+ await gateBudget();
243
287
  try {
244
288
  await stopOwnedMetroForReset(root);
245
289
  } catch (error) {
@@ -258,12 +302,12 @@ function registerStart(program, overrides = {}) {
258
302
  let publicOrigin = remote ? publicUrl : null;
259
303
  let resolution = await resolveProjectMetro(port, root);
260
304
  let supervisor = liveSupervisor({
261
- state: readWorkspaceState(root),
305
+ state: readWorkspaceState$1(root),
262
306
  project: getProject(root),
263
307
  port
264
308
  });
265
309
  const recordedTarget = resolveSupervisorTarget({
266
- state: readWorkspaceState(root)?.supervisor,
310
+ state: readWorkspaceState$1(root)?.supervisor,
267
311
  record: getProject(root)?.supervisor,
268
312
  reservedPort: port
269
313
  });
@@ -272,6 +316,7 @@ function registerStart(program, overrides = {}) {
272
316
  message: `Cannot reuse or replace the recorded supervisor: ${recordedTarget.reason}.`,
273
317
  remedy: "Stop it with the tool that started it, then retry `stim start`. Stim leaves unverified processes alone."
274
318
  });
319
+ if (!resetCache && !resolution.metro && !supervisor) await gateBudget();
275
320
  let managedTunnel = null;
276
321
  let spawnedChild = null;
277
322
  let spawnedTs = null;
@@ -307,7 +352,7 @@ function registerStart(program, overrides = {}) {
307
352
  const recordedSupervisorPid = async (since) => {
308
353
  const deadline = Date.now() + RECORDED_SUPERVISOR_WAIT_MS;
309
354
  while (Date.now() < deadline) {
310
- const record = readWorkspaceState(root)?.supervisor;
355
+ const record = readWorkspaceState$1(root)?.supervisor;
311
356
  if (record?.pid && record.port === port && Date.parse(String(record.startedAt)) >= since && pidExists(record.pid)) return record.pid;
312
357
  await sleep(25);
313
358
  }
@@ -371,7 +416,9 @@ function registerStart(program, overrides = {}) {
371
416
  "--port",
372
417
  String(port),
373
418
  ...tunnel ? ["--tunnel"] : [],
374
- ...opts.resetCache ? ["--reset-cache"] : []
419
+ ...resetCache ? ["--reset-cache"] : [],
420
+ "--idle-stop-minutes",
421
+ String(metroIdleStopMinutesSetting(settings))
375
422
  ];
376
423
  const childEnv = {
377
424
  ...process.env,
@@ -390,7 +437,7 @@ function registerStart(program, overrides = {}) {
390
437
  const deadline = Date.now() + 5e3;
391
438
  while (Date.now() < deadline) {
392
439
  const found = liveSupervisor({
393
- state: readWorkspaceState(root),
440
+ state: readWorkspaceState$1(root),
394
441
  project: getProject(root),
395
442
  port
396
443
  });
@@ -449,7 +496,7 @@ function registerStart(program, overrides = {}) {
449
496
  } else {
450
497
  const currentResolution = await resolveProjectMetro(port, root);
451
498
  const currentSupervisor = liveSupervisor({
452
- state: readWorkspaceState(root),
499
+ state: readWorkspaceState$1(root),
453
500
  project: getProject(root),
454
501
  port
455
502
  });
@@ -499,7 +546,7 @@ function registerStart(program, overrides = {}) {
499
546
  }
500
547
  const currentResolution = await resolveProjectMetro(port, root);
501
548
  const currentSupervisor = liveSupervisor({
502
- state: readWorkspaceState(root),
549
+ state: readWorkspaceState$1(root),
503
550
  project: getProject(root),
504
551
  port
505
552
  });
@@ -585,7 +632,7 @@ function registerStart(program, overrides = {}) {
585
632
  managedTunnel = acquisition.tunnel;
586
633
  resolution = await resolveProjectMetro(port, root);
587
634
  supervisor = liveSupervisor({
588
- state: readWorkspaceState(root),
635
+ state: readWorkspaceState$1(root),
589
636
  project: getProject(root),
590
637
  port
591
638
  });
@@ -617,13 +664,13 @@ function registerStart(program, overrides = {}) {
617
664
  root,
618
665
  seconds: waitSeconds,
619
666
  aborted: () => !liveSupervisor({
620
- state: readWorkspaceState(root),
667
+ state: readWorkspaceState$1(root),
621
668
  project: getProject(root),
622
669
  port
623
670
  })
624
671
  })) {
625
672
  const stillLive = liveSupervisor({
626
- state: readWorkspaceState(root),
673
+ state: readWorkspaceState$1(root),
627
674
  project: getProject(root),
628
675
  port
629
676
  });
@@ -634,7 +681,7 @@ function registerStart(program, overrides = {}) {
634
681
  });
635
682
  }
636
683
  supervisor = liveSupervisor({
637
- state: readWorkspaceState(root),
684
+ state: readWorkspaceState$1(root),
638
685
  project: getProject(root),
639
686
  port
640
687
  });
@@ -645,16 +692,13 @@ function registerStart(program, overrides = {}) {
645
692
  note(chalk.dim("Leaving it alone: Stim will not start a second bundler over a working one."));
646
693
  }
647
694
  if (managedTunnelExited()) return failExitedManagedTunnel();
648
- report({
649
- json,
650
- out,
695
+ clearWorkspaceStateKeys(root, [IDLE_STOP_KEY]);
696
+ return startFacts({
651
697
  port,
652
698
  supervisor,
653
699
  logsDir,
654
- alreadyRunning: true,
655
- waited: waitTimer()
700
+ alreadyRunning: true
656
701
  });
657
- return;
658
702
  }
659
703
  if (!spawnedChild && supervisor) {
660
704
  note(chalk.dim(`Supervisor pid ${supervisor.pid} is already running for this workspace; waiting for it to answer on port ${port}...`));
@@ -677,13 +721,13 @@ function registerStart(program, overrides = {}) {
677
721
  root,
678
722
  seconds: waitSeconds,
679
723
  aborted: () => !liveSupervisor({
680
- state: readWorkspaceState(root),
724
+ state: readWorkspaceState$1(root),
681
725
  project: getProject(root),
682
726
  port
683
727
  })
684
728
  })) {
685
729
  const stillLive = liveSupervisor({
686
- state: readWorkspaceState(root),
730
+ state: readWorkspaceState$1(root),
687
731
  project: getProject(root),
688
732
  port
689
733
  });
@@ -695,22 +739,18 @@ function registerStart(program, overrides = {}) {
695
739
  }
696
740
  }
697
741
  supervisor = liveSupervisor({
698
- state: readWorkspaceState(root),
742
+ state: readWorkspaceState$1(root),
699
743
  project: getProject(root),
700
744
  port
701
745
  }) || (tunnel ? null : supervisor);
702
746
  requireExpoTunnel();
703
747
  if (managedTunnelExited()) return failExitedManagedTunnel();
704
- report({
705
- json,
706
- out,
748
+ return startFacts({
707
749
  port,
708
750
  supervisor,
709
751
  logsDir,
710
- alreadyRunning: true,
711
- waited: waitTimer()
752
+ alreadyRunning: true
712
753
  });
713
- return;
714
754
  }
715
755
  if (managedTunnelExited()) return failExitedManagedTunnel();
716
756
  const child = spawnedChild ?? await spawnSupervisor(publicOrigin);
@@ -761,7 +801,7 @@ function registerStart(program, overrides = {}) {
761
801
  }
762
802
  }
763
803
  supervisor = liveSupervisor({
764
- state: readWorkspaceState(root),
804
+ state: readWorkspaceState$1(root),
765
805
  project: getProject(root),
766
806
  port
767
807
  }) || {
@@ -770,14 +810,11 @@ function registerStart(program, overrides = {}) {
770
810
  mode: null,
771
811
  startedAt: null
772
812
  };
773
- report({
774
- json,
775
- out,
813
+ return startFacts({
776
814
  port,
777
815
  supervisor,
778
816
  logsDir,
779
- alreadyRunning: false,
780
- waited: waitTimer()
817
+ alreadyRunning: false
781
818
  });
782
819
  };
783
820
  const startLocked = async () => {
@@ -809,14 +846,30 @@ function registerStart(program, overrides = {}) {
809
846
  });
810
847
  throw err;
811
848
  }
812
- });
849
+ };
850
+ try {
851
+ return {
852
+ ok: true,
853
+ facts: await run(),
854
+ waited: waitTimer(),
855
+ reclaimed
856
+ };
857
+ } catch (error) {
858
+ if (!(error instanceof StartRefusal)) throw error;
859
+ return {
860
+ ok: false,
861
+ error: startError(error.refusal),
862
+ lines: error.refusal.lines ?? [],
863
+ reclaimed
864
+ };
865
+ }
813
866
  }
814
867
  async function resolvePort(root, note) {
815
868
  const project = getProject(root);
816
869
  const recorded = project?.metroPort;
817
870
  if (!recorded) return await reserveMetroPort(root);
818
871
  const supervisor = resolveSupervisorTarget({
819
- state: readWorkspaceState(root)?.supervisor,
872
+ state: readWorkspaceState$1(root)?.supervisor,
820
873
  record: project.supervisor,
821
874
  reservedPort: recorded
822
875
  });
@@ -869,21 +922,17 @@ function failureEvidence({ logFile, logsDir, sinceTs }) {
869
922
  if (recent.length > 0) lines.push(fellBack ? "Full records: `stim logs`" : "Full records: `stim logs --errors`");
870
923
  return lines;
871
924
  }
872
- function report({ json, out, port, supervisor, logsDir, alreadyRunning, waited }) {
873
- const facts = startFacts({
874
- port,
875
- supervisor,
876
- logsDir,
877
- alreadyRunning
878
- });
925
+ function report({ json, out, facts, waited, reclaimed }) {
879
926
  if (json) {
880
- console.log(JSON.stringify(facts));
881
- return facts;
927
+ console.log(JSON.stringify(reclaimed.length ? {
928
+ ...facts,
929
+ reclaimed
930
+ } : facts));
931
+ return;
882
932
  }
883
933
  const who = facts.supervisorPid ? `supervisor pid ${facts.supervisorPid}${facts.mode ? ` (${facts.mode})` : ""}` : "started outside Stim";
884
- out(chalk.green(`OK: dev server on port ${port}, ${who}${alreadyRunning ? " (already running)" : ""} ${waited}`));
885
- out(chalk.dim(phaseLine("logs", logsDir)));
886
- return facts;
934
+ out(chalk.green(`OK: dev server on port ${facts.port}, ${who}${facts.alreadyRunning ? " (already running)" : ""} ${waited}`));
935
+ out(chalk.dim(phaseLine("logs", facts.logsDir)));
887
936
  }
888
937
  //#endregion
889
- export { startCommand as default, failureEvidence, liveSupervisor, parseWait, readLogTail, registerStart, startFacts, supervisorEntry, tailLines, wantsExpoOwnTunnel };
938
+ export { registerStart as a, startFacts as c, wantsExpoOwnTunnel as d, spawnEntry as f, readLogTail as i, supervisorEntry as l, liveSupervisor as n, startCommand as o, parseWait as r, startDevServer as s, failureEvidence as t, tailLines as u };
@@ -0,0 +1,2 @@
1
+ import { a as registerStart, c as startFacts, d as wantsExpoOwnTunnel, i as readLogTail, l as supervisorEntry, n as liveSupervisor, o as startCommand, r as parseWait, s as startDevServer, t as failureEvidence, u as tailLines } from "./start-F9gv5dcC.mjs";
2
+ export { startCommand as default, failureEvidence, liveSupervisor, parseWait, readLogTail, registerStart, startDevServer, startFacts, supervisorEntry, tailLines, wantsExpoOwnTunnel };
@@ -1,5 +1,5 @@
1
- import { D as process_identity_exports, H as deviceSlotKey, W as parseDeviceSlotKey } from "./config-Cp9lM3wX.mjs";
2
- import { S as workspaceStateFile, a as updateWorkspaceState, h as supervisorPidFile, o as withWorkspaceStateLock, r as readWorkspaceState, t as clearWorkspaceStateKey } from "./workspace-state-DF2gCFhx.mjs";
1
+ import { B as parseDeviceSlotKey, D as process_identity_exports, R as deviceSlotKey } from "./config-BEq0Qw_a.mjs";
2
+ import { E as supervisorPidFile, N as workspaceStateFile, _ as withWorkspaceStateLock, f as clearWorkspaceStateKey, g as updateWorkspaceState, m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname } from "node:path";
5
5
  //#region src/supervisor/state.ts
@@ -1,4 +1,4 @@
1
- import { T as withConfigLock, u as getConfigDir } from "./config-Cp9lM3wX.mjs";
1
+ import { T as withConfigLock, u as getConfigDir } from "./config-BEq0Qw_a.mjs";
2
2
  import { readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { basename, dirname, join, relative, resolve } from "node:path";
4
4
  const PLATFORMS = ["ios", "android"];
@@ -1,7 +1,7 @@
1
- import { _ as repoRoot, s as gitCommonDir } from "./worktree-R_cUlE7s.mjs";
2
- import { o as findProjectRoot } from "./project-DS112DYB.mjs";
3
- import { o as formatLongDuration } from "./command-output-gByVmIjy.mjs";
4
- import { a as statsProjectKey, r as readStats } from "./stats-DG9e66Rz.mjs";
1
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
2
+ import { o as findProjectRoot } from "./project-BXZzOABt.mjs";
3
+ import { o as formatLongDuration } from "./command-output-D5z2_bcF.mjs";
4
+ import { a as statsProjectKey, r as readStats } from "./stats-BAgJaLA4.mjs";
5
5
  import chalk from "chalk";
6
6
  //#region src/commands/stats.ts
7
7
  const PLATFORMS = ["ios", "android"];