stim 1.15.0 → 1.17.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 (123) hide show
  1. package/dist/{activity-B2-kb7k0.mjs → activity-IRvJY_ru.mjs} +49 -16
  2. package/dist/agent-device-usage-output-BK41vnzN.mjs +411 -0
  3. package/dist/{android-Cu_L4RpL.mjs → android--GorydsK.mjs} +692 -321
  4. package/dist/{android-Db2eEMaf.mjs → android-B_YNZy61.mjs} +25 -60
  5. package/dist/{android-CYmq0jNi.mjs → android-DE4v59Mb.mjs} +12 -3
  6. package/dist/{android-cas-PnKfAdB2.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
  7. package/dist/{app-install-CAAplXAt.mjs → app-install-VPkI5WEg.mjs} +52 -8
  8. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  9. package/dist/{budget-CMiqghig.mjs → budget-DM984mnd.mjs} +372 -366
  10. package/dist/{build-plan-aeGMFX7e.mjs → build-plan-CmQCoyT-.mjs} +346 -88
  11. package/dist/{build-slots-Df1ApSuH.mjs → build-slots-41v_d2x9.mjs} +36 -21
  12. package/dist/{cli-0cX5s4NM.mjs → cli-Daxug5-K.mjs} +23 -17
  13. package/dist/cli.mjs +1 -1
  14. package/dist/collector-run.mjs +5 -192
  15. package/dist/{command-output-CliHHn7a.mjs → command-output-CDAIFD-8.mjs} +3 -3
  16. package/dist/{created-devices-BwVb3liH.mjs → created-devices-CpvzBL25.mjs} +1 -1
  17. package/dist/{dependency-state-BmsjKZ2H.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
  18. package/dist/{deps-BFlKbOIp.mjs → deps-DNWaQs4V.mjs} +2 -2
  19. package/dist/{dev-client-CjzLoNs0.mjs → dev-client-B-XC4uRH.mjs} +3 -40
  20. package/dist/{device-BZ1IyS5A.mjs → device-C8IOoJPv.mjs} +7 -6
  21. package/dist/device-capacity-D0GWHnTM.mjs +580 -0
  22. package/dist/device-host-worker.mjs +587 -110
  23. package/dist/{device-ios-DMQBUPus.mjs → device-ios-Bc7vbGwl.mjs} +75 -44
  24. package/dist/{device-lease-W5Pi1q38.mjs → device-lease-DpoS36_u.mjs} +2 -2
  25. package/dist/{device-pool-B2r38YjS.mjs → device-lease-run-B8YltIH_.mjs} +5 -125
  26. package/dist/device-pool-3o7s5lo4.mjs +125 -0
  27. package/dist/{device-remote-9ulPsdhY.mjs → device-remote-hFSkpfQu.mjs} +13 -13
  28. package/dist/{doctor-BcE5xsBn.mjs → doctor-Cnk9d7Hm.mjs} +86 -59
  29. package/dist/{error-diagnostics-Cb0P1WLS.mjs → error-diagnostics-C-NMnhrk.mjs} +11 -15
  30. package/dist/{gc-BuL1Genr.mjs → gc-DxCL2A46.mjs} +478 -33
  31. package/dist/{gradle-CmdOBq1d.mjs → gradle-D7-L2Th3.mjs} +4 -4
  32. package/dist/{guide-cCSGRFd3.mjs → guide-DjrTQGik.mjs} +2198 -566
  33. package/dist/{guide-status-CIoWK6mG.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
  34. package/dist/hosted-android-DwLS4Mse.mjs +32 -0
  35. package/dist/hosted-client-wk1W_CNW.mjs +196 -0
  36. package/dist/hosted-ios-aMo7Cljf.mjs +15 -0
  37. package/dist/hosted-logs-DqYmWtXc.mjs +187 -0
  38. package/dist/hosted-macos-dlHXEeF5.mjs +135 -0
  39. package/dist/hosted-native-C9xJ9rpA.mjs +255 -0
  40. package/dist/{build-progress-C2Jv1AtA.mjs → idle-B2m-Ovod.mjs} +300 -9
  41. package/dist/{idle-shutdown-B5LPaNyY.mjs → idle-shutdown-_3oOV1V_.mjs} +25 -17
  42. package/dist/{in-use-CndPMilN.mjs → in-use-CvGOUn-x.mjs} +30 -10
  43. package/dist/ios-Cr1h5gnO.mjs +189 -0
  44. package/dist/{ios-Chob8ny7.mjs → ios-DE6duQoz.mjs} +819 -460
  45. package/dist/{ios-3CtCRhwr.mjs → ios-DSfnPfse.mjs} +4 -4
  46. package/dist/{ios-device-DERmMmk-.mjs → ios-device-pAN4t54-.mjs} +1 -1
  47. package/dist/ios-state-8L3lgum6.mjs +89 -0
  48. package/dist/{launch-verify-CLlofxRt.mjs → launch-verify-lTnWZikR.mjs} +3 -3
  49. package/dist/logs-DUoKlDoS.mjs +384 -0
  50. package/dist/{client-C2IS36Qf.mjs → machines-C2XiNwh9.mjs} +330 -37
  51. package/dist/{macos-BwtbUtTN.mjs → macos-32po3kUq.mjs} +23 -18
  52. package/dist/macos-run.mjs +1 -1
  53. package/dist/maintenance-run.d.mts +4 -0
  54. package/dist/maintenance-run.mjs +254 -0
  55. package/dist/{metro-Di8EN2Tb.mjs → metro-g8NqiJp-.mjs} +1 -1
  56. package/dist/metro-gateway-DmslUM30.mjs +103 -0
  57. package/dist/{named-ports-Dj_XBNaL.mjs → named-ports-C8m8EQs2.mjs} +2 -2
  58. package/dist/{native-run-DFDoIRbY.mjs → native-run-D1Q56rAD.mjs} +17 -6
  59. package/dist/{native-runtime-i6OkVg-w.mjs → native-runtime-DhJI3IVQ.mjs} +6 -6
  60. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  61. package/dist/offload-worker.d.mts +1 -0
  62. package/dist/offload-worker.mjs +13 -8
  63. package/dist/{teardown-BYuQafiA.mjs → ownership-BMLqyBgJ.mjs} +639 -53
  64. package/dist/{ownership-BkYxUtuj.mjs → ownership-DyRQru0q.mjs} +2 -2
  65. package/dist/{ports-DddwttKM.mjs → ports-4nYqxPWC.mjs} +2 -2
  66. package/dist/{prebuild-BvxDlD6C.mjs → prebuild-D7RUMkwN.mjs} +4 -4
  67. package/dist/preview-CxPRIEht.mjs +318 -0
  68. package/dist/{project-CV3tDFHl.mjs → project-D47Rh0ly.mjs} +72 -3
  69. package/dist/{recordings-GEXp4iBT.mjs → recordings-BNgsD1Tr.mjs} +1 -1
  70. package/dist/{reload-ChPiwvot.mjs → reload-qZei6iWn.mjs} +77 -13
  71. package/dist/{remote-cache-CO2elm_b.mjs → remote-cache-Ci4DQYYj.mjs} +4 -4
  72. package/dist/{run-B-xqRrsg.mjs → run-CkE9y0nc.mjs} +2 -2
  73. package/dist/{server-bare-X7PUgizL.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
  74. package/dist/{server-expo-DhtX6bom.mjs → server-expo-CHTyXD0G.mjs} +4 -4
  75. package/dist/server-expo-CeakhI8P.mjs +2 -0
  76. package/dist/settings-BBpMcDbD.mjs +25 -0
  77. package/dist/settings-Cfd-0r2d.mjs +1440 -0
  78. package/dist/{settings-DbL6uhH8.mjs → settings-SR9OmW9h.mjs} +10 -4
  79. package/dist/settings.schema.json +472 -50
  80. package/dist/{simslim-Ciluxlq4.mjs → simslim-BWNrc3M3.mjs} +3 -3
  81. package/dist/{slot-launch-BY0BrOLh.mjs → slot-launch-DmjBmpQV.mjs} +10 -7
  82. package/dist/{spawn-entry-DncpJvWL.mjs → spawn-entry-jw19m8Nl.mjs} +1 -0
  83. package/dist/{start-CPO4wRg7.mjs → start-BopZcr4n.mjs} +1 -1
  84. package/dist/{start-CUD9nasA.mjs → start-uee1wWjY.mjs} +21 -17
  85. package/dist/{state-CaeaHbDA.mjs → state-BKa8wNN5.mjs} +1 -1
  86. package/dist/{state-BxCgeTQu.mjs → state-DyaNTgfR.mjs} +2 -2
  87. package/dist/{state-DFm77wRn.mjs → state-PeQiJuIu.mjs} +5 -5
  88. package/dist/{stats-DBLLFmKd.mjs → stats-Bq4fJOdB.mjs} +19 -5
  89. package/dist/{status-l84Gbvp2.mjs → status-CzS4bPO9.mjs} +5 -3
  90. package/dist/status-DlKvVJBE.mjs +49 -0
  91. package/dist/{status-DYXxNOT0.mjs → status-dXX2JX1C.mjs} +244 -50
  92. package/dist/{stop-CceYh1yG.mjs → stop-BCwvvs7F.mjs} +2 -2
  93. package/dist/{stop-Bad61z_2.mjs → stop-BjizrQwv.mjs} +83 -21
  94. package/dist/{stop-Bvf1MflS.mjs → stop-Cr1d8DSE.mjs} +4 -4
  95. package/dist/stop-cause-rhmGfwvt.mjs +97 -0
  96. package/dist/supervisor-run.d.mts +7 -4
  97. package/dist/supervisor-run.mjs +156 -27
  98. package/dist/{support-WLOzVKUv.mjs → support-BJPgYCu-.mjs} +61 -11
  99. package/dist/{support-CDQbDkL5.mjs → support-F9-sr0Oi.mjs} +6 -5
  100. package/dist/{toolchain-DmeYjXD9.mjs → toolchain-CNIBTIOv.mjs} +11 -11
  101. package/dist/trigger-Bemu8ytw.mjs +65 -0
  102. package/dist/trigger-CXts6qt1.mjs +2 -0
  103. package/dist/{warm-progress-DVHLN4uC.mjs → warm-progress-DF4JRvYI.mjs} +274 -5
  104. package/dist/watchman-APYjXSQa.mjs +48 -0
  105. package/dist/{web-k6w8-HnE.mjs → web-exQtGkoc.mjs} +14 -16
  106. package/dist/web-run.mjs +5 -5
  107. package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
  108. package/dist/{workspace-state-CL2V2Ons.mjs → workspace-state-DqcCbpE7.mjs} +34 -34
  109. package/dist/workspaces-Bcib97-6.mjs +306 -0
  110. package/dist/{worktree-BT_uULFx.mjs → worktree-Dc98cE6_.mjs} +1 -1
  111. package/dist/{worktree-qXKzADSC.mjs → worktree-ZpZR3S1k.mjs} +601 -33
  112. package/package.json +5 -5
  113. package/dist/device-capacity-DMuKC7nx.mjs +0 -136
  114. package/dist/hosted-macos-DwowNU7W.mjs +0 -447
  115. package/dist/logs-h9h6MUvE.mjs +0 -568
  116. package/dist/machine-usage-D_YYMzfR.mjs +0 -283
  117. package/dist/machines-CYtOCqcj.mjs +0 -259
  118. package/dist/merge-state-BnxLNQiM.mjs +0 -272
  119. package/dist/server-expo-KJeD109I.mjs +0 -2
  120. package/dist/settings-CduVcoxj.mjs +0 -680
  121. package/dist/stop-cause-CZ_Mr-v9.mjs +0 -665
  122. package/dist/watchman-Bx0wceoF.mjs +0 -238
  123. package/dist/worktree-C0c5Udwa.mjs +0 -753
@@ -1,24 +1,33 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { C as saveConfig, D as withConfigLock, H as projectDeviceSlots, _ as loadConfig, a as clearDevice, d as getConfigDir, w as setDevice, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
3
- import { x as workspaceId } from "./workspace-state-CL2V2Ons.mjs";
4
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
5
- import { l as phaseLine } from "./command-output-CliHHn7a.mjs";
6
- import { dt as parkedMaxSetting, ft as readParked, mt as selectParked, ot as adoptParked, st as dropParked } from "./android-Db2eEMaf.mjs";
7
- import { y as iosSimSlimProfileSetting } from "./settings-CduVcoxj.mjs";
8
- import { c as teardownParkedIosSim } from "./teardown-BYuQafiA.mjs";
9
- import { A as hostMemoryPressureAdvice, C as resolveIosCreation, O as configuredIosSimulatorViewer, S as resetIosPrivacy, _ as parseRuntimeVersion, b as renameIosSim, f as listIosDeviceTypes, h as ownedSimName, i as createOwnedIosSim, j as readHostMemoryPressure, l as iosSimulatorFailureAdvice, n as bootIosSim, p as listIosRuntimes, u as listAllIosSims, w as resolveOwnedIosSim, x as resetIosKeychain } from "./ios-3CtCRhwr.mjs";
10
- import { a as runtimeMismatch, n as deviceTypeMismatch } from "./device-capacity-DMuKC7nx.mjs";
3
+ import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
4
+ import { l as phaseLine } from "./command-output-CDAIFD-8.mjs";
5
+ import { v as iosSimSlimProfileSetting } from "./settings-Cfd-0r2d.mjs";
6
+ import { y as workspaceId } from "./workspace-state-DqcCbpE7.mjs";
7
+ import { ct as dropParked, ft as parkedMaxSetting, ht as selectParked, pt as readParked, st as adoptParked } from "./android-B_YNZy61.mjs";
8
+ import { A as hostMemoryPressureAdvice, C as resolveIosCreation, O as configuredIosSimulatorViewer, S as resetIosPrivacy, _ as parseRuntimeVersion, b as renameIosSim, f as listIosDeviceTypes, h as ownedSimName, i as createOwnedIosSim, j as readHostMemoryPressure, l as iosSimulatorFailureAdvice, n as bootIosSim, p as listIosRuntimes, u as listAllIosSims, w as resolveOwnedIosSim, x as resetIosKeychain } from "./ios-DSfnPfse.mjs";
9
+ import { v as teardownParkedIosSim } from "./ownership-BMLqyBgJ.mjs";
10
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
11
+ import { a as deviceTypeMismatch, c as runtimeMismatch, n as DeviceAdmissionRefusal, p as withDeviceBootAdmission } from "./device-capacity-D0GWHnTM.mjs";
11
12
  import chalk from "chalk";
12
13
  //#region src/engine/device-ios.ts
13
- function startIosBoot(udid, configure, label, out, simulatorApp) {
14
- const done = (async () => {
14
+ function startIosBoot(udid, configure, label, out, simulatorApp, root, deviceSlotWait) {
15
+ const done = withDeviceBootAdmission({
16
+ platform: "ios",
17
+ key: udid
18
+ }, async () => {
19
+ out(chalk.dim(phaseLine("device", `booting ${label} (${udid})`)));
15
20
  await bootIosSim(udid, {
16
21
  label,
17
22
  out,
18
23
  simulatorApp
19
24
  });
20
25
  await configure();
21
- })();
26
+ }, {
27
+ ...deviceSlotWait,
28
+ root,
29
+ out
30
+ });
22
31
  done.catch(() => {});
23
32
  return {
24
33
  udid,
@@ -34,7 +43,8 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
34
43
  const simslimProfile = iosSimSlimProfileSetting(settings, settingsRoot);
35
44
  if (record?.deviceUdid) {
36
45
  if (record.owned) {
37
- const resolved = resolveOwnedIosSim(record.deviceUdid);
46
+ const listed = listAllIosSims({ includeUnavailable: true });
47
+ const resolved = resolveOwnedIosSim(record.deviceUdid, listed);
38
48
  if (resolved.notOwned) note(chalk.yellow(`Note: recorded sim is now named "${resolved.notOwned}", not Stim-owned -- creating a fresh owned sim instead of booting it.`));
39
49
  else if (resolved.missing) {} else {
40
50
  const sim = resolved.sim;
@@ -48,7 +58,7 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
48
58
  model: deviceTypes.find((d) => d.identifier === sim.deviceTypeIdentifier)?.name ?? null,
49
59
  runtime: parseRuntimeVersion(sim.runtime)
50
60
  };
51
- const name = await withIosDeviceNameLock(() => renameToOwnedName(sim, label, model, projectPath));
61
+ const name = ownedIosName(sim, label, model, projectPath, listed) === sim.name ? sim.name : await withIosDeviceNameLock(() => renameToOwnedName(sim, label, model, projectPath));
52
62
  const updated = {
53
63
  deviceUdid: sim.udid,
54
64
  owned: true,
@@ -74,17 +84,15 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
74
84
  deviceType: model.model,
75
85
  runtime: model.runtime
76
86
  };
77
- if (sim.state !== "Booted") {
78
- out(chalk.dim(phaseLine("device", `booting ${name} (${sim.udid})`)));
79
- return {
80
- ...updated,
81
- booting: startIosBoot(sim.udid, configure, name, out, flags.simulatorApp),
82
- ...facts
83
- };
84
- }
87
+ if (sim.state !== "Booted") return {
88
+ ...updated,
89
+ booting: startIosBoot(sim.udid, configure, name, out, flags.simulatorApp, projectPath, flags.deviceSlotWait),
90
+ ...facts
91
+ };
85
92
  return {
86
93
  ...await configure(),
87
- ...facts
94
+ ...facts,
95
+ booted: sim.udid
88
96
  };
89
97
  }
90
98
  } else {
@@ -116,7 +124,6 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
116
124
  out
117
125
  })) : null;
118
126
  if (adopted) {
119
- out(chalk.dim(phaseLine("device", `booting ${adopted.deviceName} (${adopted.deviceUdid})`)));
120
127
  const booting = startIosBoot(adopted.deviceUdid, async () => {
121
128
  resetAdoptedSim(adopted.deviceUdid, out);
122
129
  await configureOwnedIosSim({
@@ -127,7 +134,7 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
127
134
  out,
128
135
  reconcileIosSimulator
129
136
  });
130
- }, adopted.deviceName, out, flags.simulatorApp);
137
+ }, adopted.deviceName, out, flags.simulatorApp, projectPath, flags.deviceSlotWait);
131
138
  return {
132
139
  ...adopted,
133
140
  booting,
@@ -160,7 +167,7 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
160
167
  profile: simslimProfile,
161
168
  out,
162
169
  reconcileIosSimulator
163
- }), created.name, out, flags.simulatorApp);
170
+ }), created.name, out, flags.simulatorApp, projectPath, flags.deviceSlotWait);
164
171
  return {
165
172
  ...newRecord,
166
173
  created: true,
@@ -172,8 +179,8 @@ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, l
172
179
  function withIosDeviceNameLock(fn) {
173
180
  return withWorkspaceProcessLock(getConfigDir(), "ios-device-names", async () => fn(), { external: true });
174
181
  }
175
- function ownedIosNameSuffix(label, model, projectPath, udid) {
176
- const names = new Set(listAllIosSims({ includeUnavailable: true }).filter((sim) => sim.udid !== udid).map((sim) => sim.name));
182
+ function ownedIosNameSuffix(label, model, projectPath, udid, listed = listAllIosSims({ includeUnavailable: true })) {
183
+ const names = new Set(listed.filter((sim) => sim.udid !== udid).map((sim) => sim.name));
177
184
  for (const project of Object.values(loadConfig()?.projects ?? {})) for (const { platforms } of projectDeviceSlots(project)) {
178
185
  const record = platforms.ios;
179
186
  if (record?.deviceUdid !== udid && record?.deviceName) names.add(record.deviceName);
@@ -183,8 +190,11 @@ function ownedIosNameSuffix(label, model, projectPath, udid) {
183
190
  for (let attempt = 0; names.has(ownedSimName(label, model, suffix)); attempt++) suffix = ` ${workspaceId(projectPath)}${attempt ? `-${attempt}` : ""}`;
184
191
  return suffix;
185
192
  }
193
+ function ownedIosName(sim, label, model, projectPath, listed) {
194
+ return ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, sim.udid, listed));
195
+ }
186
196
  function renameToOwnedName(sim, label, model, projectPath) {
187
- const wanted = ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, sim.udid));
197
+ const wanted = ownedIosName(sim, label, model, projectPath);
188
198
  if (sim.name === wanted) return wanted;
189
199
  try {
190
200
  renameIosSim(sim.udid, wanted);
@@ -284,7 +294,7 @@ async function configureOwnedIosSim({ record, projectPath, slot, profile, out, r
284
294
  setDevice(projectPath, "ios", updated, slot);
285
295
  return updated;
286
296
  }
287
- async function ensureIosBooted({ device, simulatorApp, timeoutMs, pollMs, out }) {
297
+ async function ensureIosBooted({ device, projectPath, deviceSlotWait, simulatorApp, timeoutMs, pollMs, out }) {
288
298
  const udid = device?.deviceUdid;
289
299
  if (!udid) return {
290
300
  failed: true,
@@ -315,13 +325,15 @@ async function ensureIosBooted({ device, simulatorApp, timeoutMs, pollMs, out })
315
325
  try {
316
326
  await booting.done;
317
327
  } catch (e) {
318
- return {
319
- failed: true,
320
- reason: `Could not boot simulator ${udid}: ${e?.message || e}`
321
- };
328
+ return bootFailure(udid, e);
322
329
  }
323
330
  return ready();
324
331
  }
332
+ const readiness = device?.booted === udid ? ready() : null;
333
+ if (readiness?.ok) {
334
+ if (simulatorApp !== void 0) configuredIosSimulatorViewer(simulatorApp).open(udid);
335
+ return readiness;
336
+ }
325
337
  let resolved;
326
338
  try {
327
339
  resolved = resolveOwnedIosSim(udid);
@@ -341,24 +353,30 @@ async function ensureIosBooted({ device, simulatorApp, timeoutMs, pollMs, out })
341
353
  };
342
354
  const sim = resolved.sim;
343
355
  if (sim.state === "Booted") {
344
- const result = ready();
356
+ const result = readiness ?? ready();
345
357
  if (result.ok && simulatorApp !== void 0) configuredIosSimulatorViewer(simulatorApp).open(udid);
346
358
  return result;
347
359
  }
348
- out(chalk.dim(phaseLine("device", `booting ${sim.name} (${udid})`)));
349
360
  const bootDeadline = Date.now() + timeoutMs;
350
361
  try {
351
- await bootIosSim(udid, {
352
- timeoutMs,
353
- label: sim.name,
354
- out,
355
- simulatorApp
362
+ await withDeviceBootAdmission({
363
+ platform: "ios",
364
+ key: udid
365
+ }, () => {
366
+ out(chalk.dim(phaseLine("device", `booting ${sim.name} (${udid})`)));
367
+ return bootIosSim(udid, {
368
+ timeoutMs,
369
+ label: sim.name,
370
+ out,
371
+ simulatorApp
372
+ });
373
+ }, {
374
+ ...deviceSlotWait,
375
+ root: projectPath,
376
+ out
356
377
  });
357
378
  } catch (e) {
358
- return {
359
- failed: true,
360
- reason: `Could not boot simulator ${udid}: ${e?.message || e}`
361
- };
379
+ return bootFailure(udid, e);
362
380
  }
363
381
  const deadline = Math.max(bootDeadline, Date.now() + 2 * pollMs);
364
382
  while (Date.now() < deadline) {
@@ -374,6 +392,19 @@ async function ensureIosBooted({ device, simulatorApp, timeoutMs, pollMs, out })
374
392
  reason: `Simulator ${udid} did not reach the Booted state within ${Math.round(timeoutMs / 1e3)}s.`
375
393
  };
376
394
  }
395
+ function bootFailure(udid, error) {
396
+ const refusal = error instanceof DeviceAdmissionRefusal ? error : (0, ownership_claim_exports.claimFailure)(error, "stim ios");
397
+ if (refusal) return {
398
+ failed: true,
399
+ code: refusal.code,
400
+ reason: refusal.message,
401
+ remedy: refusal.remedy
402
+ };
403
+ return {
404
+ failed: true,
405
+ reason: `Could not boot simulator ${udid}: ${error?.message || error}`
406
+ };
407
+ }
377
408
  function sleep(ms) {
378
409
  return new Promise((r) => setTimeout(r, ms));
379
410
  }
@@ -2,9 +2,9 @@ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, d as getConfigDir } from "./config-D0DbpZtM.mjs";
3
3
  import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
4
4
  import { r as register } from "./cache-manifest-DnUHBJaU.mjs";
5
- import { E as withDirLock$1, c as writeWorkspaceState, m as sharedBuildCache, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-CL2V2Ons.mjs";
5
+ import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-CDAIFD-8.mjs";
6
+ import { c as writeWorkspaceState, d as sharedBuildCache, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState, w as withDirLock$1 } from "./workspace-state-DqcCbpE7.mjs";
6
7
  import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-D0XfSe8u.mjs";
7
- import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-CliHHn7a.mjs";
8
8
  import { createHash, randomBytes } from "node:crypto";
9
9
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
10
10
  import { join } from "node:path";
@@ -1,11 +1,12 @@
1
1
  import { R as deviceSlotKey } from "./config-D0DbpZtM.mjs";
2
- import { a as formatElapsed, r as clockTime } from "./command-output-CliHHn7a.mjs";
3
- import { a as parseLease, c as raiseLease, f as selectPoolDevice, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-W5Pi1q38.mjs";
4
- import { a as VERIFY_TIMEOUT_MS, m as APP_READINESS_TIMEOUT_MS } from "./launch-verify-CLlofxRt.mjs";
2
+ import { a as formatElapsed, r as clockTime } from "./command-output-CDAIFD-8.mjs";
3
+ import { a as parseLease, c as raiseLease, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-DpoS36_u.mjs";
4
+ import { a as VERIFY_TIMEOUT_MS, m as APP_READINESS_TIMEOUT_MS } from "./launch-verify-lTnWZikR.mjs";
5
5
  //#region src/engine/device-lease-run.ts
6
6
  const LEASE_STEP_FLOOR_MS = 6e4;
7
7
  const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
8
8
  const DEVICE_WAIT_POLL_MS = 2e3;
9
+ const DEVICE_WAIT_LINE_MS = 3e4;
9
10
  const DEVICE_BUSY = "STIM_DEVICE_BUSY";
10
11
  const DEVICE_LOST = "STIM_DEVICE_LOST";
11
12
  function leaseStepMs(boundMs = 0) {
@@ -290,125 +291,4 @@ async function acquireRunLease({ root, platform, slot = "default", id, deviceNam
290
291
  }
291
292
  }
292
293
  //#endregion
293
- //#region src/engine/device-pool.ts
294
- function heldPoolId(root, platform, now, io = fileLeaseIo, slot = "default") {
295
- const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
296
- if (!record) return null;
297
- const lease = parseLease(io.readLease(deviceLeasePath(platform, record.id)));
298
- if (!lease || lease.token !== record.token || leaseIsExpired(lease, now)) return null;
299
- return record.id;
300
- }
301
- function readPool(platform, candidates, io) {
302
- const reading = {
303
- usable: [],
304
- leases: [],
305
- unreadable: []
306
- };
307
- for (const candidate of candidates) {
308
- const path = deviceLeasePath(platform, candidate.id);
309
- const raw = io.readLease(path);
310
- const lease = parseLease(raw);
311
- if (raw !== null && !lease) {
312
- reading.unreadable.push(path);
313
- continue;
314
- }
315
- reading.usable.push(candidate);
316
- if (lease) reading.leases.push(lease);
317
- }
318
- return reading;
319
- }
320
- function disconnectedHeldRefusal(id, idLabel) {
321
- return {
322
- code: "STIM_NO_DEVICE",
323
- message: `This workspace leases ${id}, and it is not connected.`,
324
- remedy: `Run \`stim device unlock\` to give it up, then run this command again. Naming another \`--device <${idLabel}>\` refuses the same way while this lease is held.`,
325
- lease: null
326
- };
327
- }
328
- const NO_LEASE_FACTS = {
329
- platform: null,
330
- id: null,
331
- deviceName: null,
332
- holder: null,
333
- expiresAt: null
334
- };
335
- function unreadableSentence(unreadable) {
336
- return unreadable.length ? ` Unreadable lease file, so no run may take that device around it: ${unreadable.join("; ")}.` : "";
337
- }
338
- function poolBusyRefusal(holders, leases, unreadable, now, waitSeconds, spare = [], idLabel = "id") {
339
- const named = holders.map((holder) => `${holder.id} (${holder.holder}, until ${leaseExpiryText(holder.expiresAt, now)})`);
340
- const first = holders[0];
341
- const lease = first ? leases.find((entry) => entry.id === first.id) : void 0;
342
- if (!first) return {
343
- code: DEVICE_BUSY,
344
- message: `Every connected device has an unreadable lease file, so Stim cannot tell who holds them: ${unreadable.join("; ")}.`,
345
- remedy: "Read each file and, once you know no run depends on it, delete it. `stim gc` reports them on every run.",
346
- lease: NO_LEASE_FACTS
347
- };
348
- return {
349
- code: DEVICE_BUSY,
350
- message: `Every connected device is leased by another workspace${waitSeconds > 0 ? `, and this run waited ${waitSeconds}s for one` : ""}: ${named.join("; ")}.${unreadableSentence(unreadable)}`,
351
- remedy: (spare.length ? `Also connected and free: ${spare.join(", ")}. Name one with \`--device <${idLabel}>\` to use it now. ` : "") + "Wait longer with `--wait <seconds>`, connect another device, or pass `--no-wait` to install anyway -- which takes no lease and, when both workspaces build the same app id, terminates the holder's running app.",
352
- lease: {
353
- platform: lease?.platform ?? null,
354
- id: first.id,
355
- deviceName: lease?.deviceName ?? null,
356
- holder: first.holder,
357
- expiresAt: first.expiresAt
358
- }
359
- };
360
- }
361
- async function selectFromPool({ root, platform, slot = "default", idLabel, list, noCandidates, waitSeconds, deadline, noWait = false, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
362
- const held = heldPoolId(root, platform, now(), io, slot);
363
- const until = deadline ?? now() + waitSeconds * 1e3;
364
- let lastLine = null;
365
- for (;;) {
366
- const { usable, leases, unreadable } = readPool(platform, list(), io);
367
- const selection = selectPoolDevice({
368
- candidates: usable,
369
- leases,
370
- held,
371
- now: now()
372
- });
373
- if (selection.status === "selected") return selection;
374
- if (selection.status === "held-disconnected") return {
375
- status: "refused",
376
- refusal: disconnectedHeldRefusal(selection.id, idLabel)
377
- };
378
- if (selection.status === "none") {
379
- if (unreadable.length) return {
380
- status: "refused",
381
- refusal: poolBusyRefusal([], leases, unreadable, now(), waitSeconds)
382
- };
383
- const { message, remedy } = noCandidates();
384
- return {
385
- status: "refused",
386
- refusal: {
387
- code: "STIM_NO_DEVICE",
388
- message,
389
- remedy,
390
- lease: null
391
- }
392
- };
393
- }
394
- const first = selection.holders[0];
395
- if (noWait && first) {
396
- const candidate = usable.find((entry) => entry.id === first.id);
397
- if (candidate) return {
398
- status: "selected",
399
- candidate
400
- };
401
- }
402
- if (now() >= until) return {
403
- status: "refused",
404
- refusal: poolBusyRefusal(selection.holders, leases, unreadable, now(), waitSeconds, selection.spare, idLabel)
405
- };
406
- if (lastLine === null || now() - lastLine >= 3e4) {
407
- lastLine = now();
408
- warn(`waiting for a free device; every connected one is leased: ${selection.holders.map((holder) => `${holder.id} (${holder.holder}, until ${leaseExpiryText(holder.expiresAt, now())})`).join("; ")}`);
409
- }
410
- await sleep(DEVICE_WAIT_POLL_MS);
411
- }
412
- }
413
- //#endregion
414
- export { lostLine as a, releaseLeaseOnSignal as c, waitForDevice as d, leaseExpiryText as i, runLease as l, DEBUG_VERIFY_STEP_MS as n, lostRefusal as o, acquireRunLease as r, parseDeviceWait as s, selectFromPool as t, waitFlagConflict as u };
294
+ export { acquireRunLease as a, lostRefusal as c, runLease as d, waitFlagConflict as f, DEVICE_WAIT_POLL_MS as i, parseDeviceWait as l, DEVICE_BUSY as n, leaseExpiryText as o, waitForDevice as p, DEVICE_WAIT_LINE_MS as r, lostLine as s, DEBUG_VERIFY_STEP_MS as t, releaseLeaseOnSignal as u };
@@ -0,0 +1,125 @@
1
+ import { R as deviceSlotKey } from "./config-D0DbpZtM.mjs";
2
+ import { a as parseLease, f as selectPoolDevice, n as fileLeaseIo, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-DpoS36_u.mjs";
3
+ import { i as DEVICE_WAIT_POLL_MS, n as DEVICE_BUSY, o as leaseExpiryText } from "./device-lease-run-B8YltIH_.mjs";
4
+ //#region src/engine/device-pool.ts
5
+ function heldPoolId(root, platform, now, io = fileLeaseIo, slot = "default") {
6
+ const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
7
+ if (!record) return null;
8
+ const lease = parseLease(io.readLease(deviceLeasePath(platform, record.id)));
9
+ if (!lease || lease.token !== record.token || leaseIsExpired(lease, now)) return null;
10
+ return record.id;
11
+ }
12
+ function readPool(platform, candidates, io) {
13
+ const reading = {
14
+ usable: [],
15
+ leases: [],
16
+ unreadable: []
17
+ };
18
+ for (const candidate of candidates) {
19
+ const path = deviceLeasePath(platform, candidate.id);
20
+ const raw = io.readLease(path);
21
+ const lease = parseLease(raw);
22
+ if (raw !== null && !lease) {
23
+ reading.unreadable.push(path);
24
+ continue;
25
+ }
26
+ reading.usable.push(candidate);
27
+ if (lease) reading.leases.push(lease);
28
+ }
29
+ return reading;
30
+ }
31
+ function disconnectedHeldRefusal(id, idLabel) {
32
+ return {
33
+ code: "STIM_NO_DEVICE",
34
+ message: `This workspace leases ${id}, and it is not connected.`,
35
+ remedy: `Run \`stim device unlock\` to give it up, then run this command again. Naming another \`--device <${idLabel}>\` refuses the same way while this lease is held.`,
36
+ lease: null
37
+ };
38
+ }
39
+ const NO_LEASE_FACTS = {
40
+ platform: null,
41
+ id: null,
42
+ deviceName: null,
43
+ holder: null,
44
+ expiresAt: null
45
+ };
46
+ function unreadableSentence(unreadable) {
47
+ return unreadable.length ? ` Unreadable lease file, so no run may take that device around it: ${unreadable.join("; ")}.` : "";
48
+ }
49
+ function poolBusyRefusal(holders, leases, unreadable, now, waitSeconds, spare = [], idLabel = "id") {
50
+ const named = holders.map((holder) => `${holder.id} (${holder.holder}, until ${leaseExpiryText(holder.expiresAt, now)})`);
51
+ const first = holders[0];
52
+ const lease = first ? leases.find((entry) => entry.id === first.id) : void 0;
53
+ if (!first) return {
54
+ code: DEVICE_BUSY,
55
+ message: `Every connected device has an unreadable lease file, so Stim cannot tell who holds them: ${unreadable.join("; ")}.`,
56
+ remedy: "Read each file and, once you know no run depends on it, delete it. `stim gc` reports them on every run.",
57
+ lease: NO_LEASE_FACTS
58
+ };
59
+ return {
60
+ code: DEVICE_BUSY,
61
+ message: `Every connected device is leased by another workspace${waitSeconds > 0 ? `, and this run waited ${waitSeconds}s for one` : ""}: ${named.join("; ")}.${unreadableSentence(unreadable)}`,
62
+ remedy: (spare.length ? `Also connected and free: ${spare.join(", ")}. Name one with \`--device <${idLabel}>\` to use it now. ` : "") + "Wait longer with `--wait <seconds>`, connect another device, or pass `--no-wait` to install anyway -- which takes no lease and, when both workspaces build the same app id, terminates the holder's running app.",
63
+ lease: {
64
+ platform: lease?.platform ?? null,
65
+ id: first.id,
66
+ deviceName: lease?.deviceName ?? null,
67
+ holder: first.holder,
68
+ expiresAt: first.expiresAt
69
+ }
70
+ };
71
+ }
72
+ async function selectFromPool({ root, platform, slot = "default", idLabel, list, noCandidates, waitSeconds, deadline, noWait = false, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
73
+ const held = heldPoolId(root, platform, now(), io, slot);
74
+ const until = deadline ?? now() + waitSeconds * 1e3;
75
+ let lastLine = null;
76
+ for (;;) {
77
+ const { usable, leases, unreadable } = readPool(platform, list(), io);
78
+ const selection = selectPoolDevice({
79
+ candidates: usable,
80
+ leases,
81
+ held,
82
+ now: now()
83
+ });
84
+ if (selection.status === "selected") return selection;
85
+ if (selection.status === "held-disconnected") return {
86
+ status: "refused",
87
+ refusal: disconnectedHeldRefusal(selection.id, idLabel)
88
+ };
89
+ if (selection.status === "none") {
90
+ if (unreadable.length) return {
91
+ status: "refused",
92
+ refusal: poolBusyRefusal([], leases, unreadable, now(), waitSeconds)
93
+ };
94
+ const { message, remedy } = noCandidates();
95
+ return {
96
+ status: "refused",
97
+ refusal: {
98
+ code: "STIM_NO_DEVICE",
99
+ message,
100
+ remedy,
101
+ lease: null
102
+ }
103
+ };
104
+ }
105
+ const first = selection.holders[0];
106
+ if (noWait && first) {
107
+ const candidate = usable.find((entry) => entry.id === first.id);
108
+ if (candidate) return {
109
+ status: "selected",
110
+ candidate
111
+ };
112
+ }
113
+ if (now() >= until) return {
114
+ status: "refused",
115
+ refusal: poolBusyRefusal(selection.holders, leases, unreadable, now(), waitSeconds, selection.spare, idLabel)
116
+ };
117
+ if (lastLine === null || now() - lastLine >= 3e4) {
118
+ lastLine = now();
119
+ warn(`waiting for a free device; every connected one is leased: ${selection.holders.map((holder) => `${holder.id} (${holder.holder}, until ${leaseExpiryText(holder.expiresAt, now())})`).join("; ")}`);
120
+ }
121
+ await sleep(DEVICE_WAIT_POLL_MS);
122
+ }
123
+ }
124
+ //#endregion
125
+ export { selectFromPool as t };
@@ -1,18 +1,18 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { d as getConfigDir } from "./config-D0DbpZtM.mjs";
3
- import { C as workspaceLogsDir, E as withDirLock, T as workspaceStateFile, b as workspaceDir, x as workspaceId } from "./workspace-state-CL2V2Ons.mjs";
4
- import { c as ownedDeviceLabel } from "./project-CV3tDFHl.mjs";
5
- import { a as clearRemoteSession, c as readMetroTunnel, u as readRemoteSession } from "./state-CaeaHbDA.mjs";
6
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
7
- import { a as formatElapsed } from "./command-output-CliHHn7a.mjs";
8
- import { o as pidExists } from "./metro-Di8EN2Tb.mjs";
9
- import { W as planMetroReach } from "./settings-CduVcoxj.mjs";
10
- import { T as sanitizeDeviceLabel } from "./ios-3CtCRhwr.mjs";
11
- import { y as probePublicHttp } from "./stop-cause-CZ_Mr-v9.mjs";
12
- import { i as INSTALL_ERROR, o as LAUNCH_ERROR, u as devClientDeepLink } from "./app-install-CAAplXAt.mjs";
13
- import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-CLlofxRt.mjs";
3
+ import { a as formatElapsed } from "./command-output-CDAIFD-8.mjs";
4
+ import { K as planMetroReach } from "./settings-Cfd-0r2d.mjs";
5
+ import { u as ownedDeviceLabel } from "./project-D47Rh0ly.mjs";
6
+ import { o as pidExists } from "./metro-g8NqiJp-.mjs";
7
+ import { C as workspaceStateFile, v as workspaceDir, w as withDirLock, x as workspaceLogsDir$1, y as workspaceId } from "./workspace-state-DqcCbpE7.mjs";
8
+ import { a as clearRemoteSession, c as readMetroTunnel, u as readRemoteSession } from "./state-BKa8wNN5.mjs";
9
+ import { T as sanitizeDeviceLabel } from "./ios-DSfnPfse.mjs";
10
+ import { u as probePublicHttp } from "./ownership-BMLqyBgJ.mjs";
11
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
12
+ import { i as INSTALL_ERROR, o as LAUNCH_ERROR, u as devClientDeepLink } from "./app-install-VPkI5WEg.mjs";
13
+ import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-lTnWZikR.mjs";
14
14
  import { t as compareStimVersions } from "./stim-installations-QMEI32v1.mjs";
15
- import { c as nativeRunWaitNotice } from "./native-run-DFDoIRbY.mjs";
15
+ import { c as nativeRunWaitNotice } from "./native-run-D1Q56rAD.mjs";
16
16
  import { existsSync, mkdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
17
17
  import { dirname, join, resolve } from "node:path";
18
18
  import { easMachineStateRoot, easMachineStateRoot as easMachineStateRoot$1, easSessionLedgerFile, easSessionLedgerLock, readEasSessionLedger, readEasSessionLedger as readEasSessionLedger$1, readJsonObject, validEasSessionClaim } from "@stim-cli/core/state";
@@ -1293,7 +1293,7 @@ async function ensureMetroReachable({ ctx, metroPort, isExpo, tunnelMode = "auto
1293
1293
  gate = recorded.provider !== "tailscale";
1294
1294
  }
1295
1295
  if (gate && resolvedUrl) {
1296
- const logsDir = workspaceLogsDir(root);
1296
+ const logsDir = workspaceLogsDir$1(root);
1297
1297
  const result = await gateOrigin({
1298
1298
  origin: resolvedUrl,
1299
1299
  metroPort,