stim 1.14.0 → 1.16.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 (152) hide show
  1. package/README.md +2 -0
  2. package/dist/activity-BxwdD81S.mjs +609 -0
  3. package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
  4. package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
  5. package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
  6. package/dist/android-cas-8U4DPqeR.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
  9. package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
  10. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  11. package/dist/budget-DjrURfQn.mjs +2700 -0
  12. package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
  13. package/dist/build-slots-rUk77xqh.mjs +132 -0
  14. package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  15. package/dist/cache-manifest.mjs +1 -1
  16. package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
  17. package/dist/cli-BkYZ_6hy.mjs +51 -0
  18. package/dist/cli.mjs +6 -42
  19. package/dist/client-BTY686R6.mjs +1368 -0
  20. package/dist/collector-run.mjs +9 -195
  21. package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
  22. package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
  23. package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
  24. package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
  25. package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
  26. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  27. package/dist/dev-client-CroAIjjj.mjs +43 -0
  28. package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
  29. package/dist/device-capacity-BHwxNBlu.mjs +136 -0
  30. package/dist/device-host-worker.d.mts +1 -0
  31. package/dist/device-host-worker.mjs +964 -0
  32. package/dist/device-ios-BadmeL2V.mjs +381 -0
  33. package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
  34. package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
  35. package/dist/device-pool-CUaEWMMm.mjs +125 -0
  36. package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
  37. package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
  38. package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
  39. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  40. package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
  41. package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
  42. package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
  43. package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
  44. package/dist/hosted-client-a-WmqE2L.mjs +197 -0
  45. package/dist/hosted-ios-CIWelIqf.mjs +220 -0
  46. package/dist/hosted-logs-D5g041Q3.mjs +187 -0
  47. package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
  48. package/dist/idle-DYVymG92.mjs +1099 -0
  49. package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
  50. package/dist/in-use-DvBw0Kxo.mjs +130 -0
  51. package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
  52. package/dist/ios-Cr1h5gnO.mjs +189 -0
  53. package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
  54. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  55. package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
  56. package/dist/ios-state-DS5UpYTH.mjs +48 -0
  57. package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
  58. package/dist/logs-CHEVK8zD.mjs +371 -0
  59. package/dist/machines-BIBUdhpj.mjs +265 -0
  60. package/dist/macos-CSYEAFmF.mjs +473 -0
  61. package/dist/macos-run.d.mts +5 -0
  62. package/dist/macos-run.mjs +2 -0
  63. package/dist/maintenance-run.d.mts +4 -0
  64. package/dist/maintenance-run.mjs +254 -0
  65. package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
  66. package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
  67. package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
  68. package/dist/native-run-NaBrRFtQ.mjs +147 -0
  69. package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
  70. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  71. package/dist/offload-worker.d.mts +122 -0
  72. package/dist/offload-worker.mjs +606 -0
  73. package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
  74. package/dist/ownership-hCkPzGmr.mjs +571 -0
  75. package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
  76. package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
  77. package/dist/prebuild-D2fsca_Z.mjs +213 -0
  78. package/dist/preview-DhVbvPAZ.mjs +318 -0
  79. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  80. package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
  81. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  82. package/dist/pull-requests.d.mts +120 -0
  83. package/dist/pull-requests.mjs +2 -0
  84. package/dist/recordings-BIXOzVnr.mjs +37 -0
  85. package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
  86. package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
  87. package/dist/run-f4vI6EnK.mjs +119 -0
  88. package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
  89. package/dist/server-expo-CVqO2c35.mjs +2 -0
  90. package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
  91. package/dist/settings-BBpMcDbD.mjs +25 -0
  92. package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
  93. package/dist/settings-oTSkkNrM.mjs +1439 -0
  94. package/dist/settings.schema.json +845 -97
  95. package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
  96. package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
  97. package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  98. package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
  99. package/dist/stage-CzaiwFsI.mjs +143 -0
  100. package/dist/start-CX8Ig-U2.mjs +2 -0
  101. package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
  102. package/dist/state-3DwSQIBK.mjs +41 -0
  103. package/dist/state-B4PQFXMW.d.mts +12 -0
  104. package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
  105. package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
  106. package/dist/stats-CEZ_i5je.mjs +77 -0
  107. package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
  108. package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
  109. package/dist/status-DlKvVJBE.mjs +49 -0
  110. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  111. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  112. package/dist/stim-footprint.swift +32 -0
  113. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  114. package/dist/stop-B0Yxtmiy.mjs +48 -0
  115. package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
  116. package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
  117. package/dist/stop-cause-CidxIqup.mjs +97 -0
  118. package/dist/supervisor-run.d.mts +43 -11
  119. package/dist/supervisor-run.mjs +363 -24
  120. package/dist/support-CAP8qDUF.mjs +316 -0
  121. package/dist/support-D4aYJniO.mjs +201 -0
  122. package/dist/teardown-CL6vDs2Y.mjs +727 -0
  123. package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
  124. package/dist/trigger-Bemu8ytw.mjs +65 -0
  125. package/dist/trigger-CXts6qt1.mjs +2 -0
  126. package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
  127. package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
  128. package/dist/web-run.mjs +310 -13
  129. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  130. package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
  131. package/dist/workspaces-BV4pdHFz.mjs +306 -0
  132. package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
  133. package/dist/worktree-jnG8Iph5.mjs +2 -0
  134. package/package.json +10 -5
  135. package/shim/bundle-response.cjs +28 -12
  136. package/dist/activity-CYVDcrt3.mjs +0 -356
  137. package/dist/budget-CGDkhvv_.mjs +0 -1745
  138. package/dist/build-progress-DxKpwnaS.mjs +0 -247
  139. package/dist/idle-DXtx3RbX.mjs +0 -191
  140. package/dist/in-use-DlqBDKqY.mjs +0 -249
  141. package/dist/logs-Civ4gbBH.mjs +0 -486
  142. package/dist/merge-state-ytFQCeh4.mjs +0 -262
  143. package/dist/server-expo-DIHDhvGg.mjs +0 -2
  144. package/dist/settings-D61iNOsB.mjs +0 -629
  145. package/dist/start-Cetfvy8l.mjs +0 -2
  146. package/dist/stats-CFpFGlJV.mjs +0 -62
  147. package/dist/stats-CX1Z8Tca.mjs +0 -368
  148. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  149. package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
  150. package/dist/worktree-BVrHsYZG.mjs +0 -752
  151. package/dist/worktree-CHWWvm5v.mjs +0 -2
  152. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -0,0 +1,381 @@
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
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 { l as phaseLine } from "./command-output-DnJMdEY-.mjs";
4
+ import { y as iosSimSlimProfileSetting } from "./settings-oTSkkNrM.mjs";
5
+ import { y as workspaceId } from "./workspace-state-B8-aJ1_5.mjs";
6
+ import { ct as dropParked, ft as parkedMaxSetting, ht as selectParked, pt as readParked, st as adoptParked } from "./android-B_NumVyQ.mjs";
7
+ 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-BaInn3sW.mjs";
8
+ import { c as teardownParkedIosSim } from "./teardown-CL6vDs2Y.mjs";
9
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
10
+ import { a as runtimeMismatch, n as deviceTypeMismatch } from "./device-capacity-BHwxNBlu.mjs";
11
+ import chalk from "chalk";
12
+ //#region src/engine/device-ios.ts
13
+ function startIosBoot(udid, configure, label, out, simulatorApp) {
14
+ const done = (async () => {
15
+ await bootIosSim(udid, {
16
+ label,
17
+ out,
18
+ simulatorApp
19
+ });
20
+ await configure();
21
+ })();
22
+ done.catch(() => {});
23
+ return {
24
+ udid,
25
+ done
26
+ };
27
+ }
28
+ var IosDeviceMismatchError = class extends Error {
29
+ remedy = "Run `stim worktree remove` (or `stim gc --delete`) to reap the current sim, then `stim ios` again to create the requested one, or pass `--slot <name>` to create it beside the current one.";
30
+ };
31
+ async function ensureOwnedIosDevice({ record, projectPath, slot, settingsRoot, label, settings, flags, note, out, reconcileIosSimulator }) {
32
+ const memoryAdvice = hostMemoryPressureAdvice(readHostMemoryPressure());
33
+ if (memoryAdvice) out(chalk.yellow(phaseLine("memory", memoryAdvice)));
34
+ const simslimProfile = iosSimSlimProfileSetting(settings, settingsRoot);
35
+ if (record?.deviceUdid) {
36
+ if (record.owned) {
37
+ const resolved = resolveOwnedIosSim(record.deviceUdid);
38
+ 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
+ else if (resolved.missing) {} else {
40
+ const sim = resolved.sim;
41
+ const wantedType = flags.deviceType || settings?.ios?.deviceType;
42
+ const deviceTypes = listIosDeviceTypes();
43
+ const mismatch = deviceTypeMismatch(sim.deviceTypeIdentifier, wantedType, deviceTypes);
44
+ if (mismatch) throw new IosDeviceMismatchError(`${mismatch}. Stim will not silently boot a different model.`);
45
+ const versionMismatch = flags.runtimeFlag ? runtimeMismatch(sim.runtime, flags.runtimeFlag, listIosRuntimes()) : null;
46
+ if (versionMismatch) throw new IosDeviceMismatchError(`${versionMismatch}. Stim will not silently boot a different iOS version.`);
47
+ const model = {
48
+ model: deviceTypes.find((d) => d.identifier === sim.deviceTypeIdentifier)?.name ?? null,
49
+ runtime: parseRuntimeVersion(sim.runtime)
50
+ };
51
+ const name = await withIosDeviceNameLock(() => renameToOwnedName(sim, label, model, projectPath));
52
+ const updated = {
53
+ deviceUdid: sim.udid,
54
+ owned: true,
55
+ deviceName: name,
56
+ ...record.simslimManaged ? { simslimManaged: true } : {},
57
+ ...record.adopted ? { adopted: true } : {},
58
+ ...record.adoptionPending ? { adoptionPending: true } : {},
59
+ ...record.parkedCacheKey ? { parkedCacheKey: record.parkedCacheKey } : {},
60
+ ...record.schemeApprovals ? { schemeApprovals: record.schemeApprovals } : {}
61
+ };
62
+ const configure = async () => {
63
+ if (record.adoptionPending) resetAdoptedSim(sim.udid, out);
64
+ return configureOwnedIosSim({
65
+ record: updated,
66
+ projectPath,
67
+ slot,
68
+ profile: simslimProfile,
69
+ out,
70
+ reconcileIosSimulator
71
+ });
72
+ };
73
+ const facts = {
74
+ deviceType: model.model,
75
+ runtime: model.runtime
76
+ };
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
+ }
85
+ return {
86
+ ...await configure(),
87
+ ...facts
88
+ };
89
+ }
90
+ } else {
91
+ const sim = listAllIosSims().find((s) => s.udid === record.deviceUdid);
92
+ if (sim) {
93
+ if (sim.state !== "Booted") {
94
+ note(chalk.yellow(`Note: assigned sim ${sim.name} (${sim.udid}) is shut down and is not owned by Stim, so it will not be booted automatically.`));
95
+ note(chalk.dim("Boot it yourself, or run `stim gc --delete` to clear the assignment so Stim can create an owned sim."));
96
+ }
97
+ return record;
98
+ }
99
+ }
100
+ withConfigLock(() => {
101
+ const current = deviceSlotPlatforms(loadConfig()?.projects?.[projectPath], slot)?.ios;
102
+ if (!current) return;
103
+ if (current.deviceUdid !== record.deviceUdid || current.owned !== record.owned) throw new Error("The simulator assignment changed during recovery. Run `stim ios` again.");
104
+ clearDevice(projectPath, "ios", slot);
105
+ });
106
+ }
107
+ const choice = resolveIosCreation({
108
+ deviceType: flags.deviceType || settings.ios?.deviceType,
109
+ runtime: flags.runtime || settings.ios?.runtime
110
+ });
111
+ const adopted = parkedMaxSetting("ios").max > 0 ? await withIosDeviceNameLock(() => takeParkedIosSim({
112
+ projectPath,
113
+ slot,
114
+ label,
115
+ choice,
116
+ out
117
+ })) : null;
118
+ if (adopted) {
119
+ out(chalk.dim(phaseLine("device", `booting ${adopted.deviceName} (${adopted.deviceUdid})`)));
120
+ const booting = startIosBoot(adopted.deviceUdid, async () => {
121
+ resetAdoptedSim(adopted.deviceUdid, out);
122
+ await configureOwnedIosSim({
123
+ record: adopted,
124
+ projectPath,
125
+ slot,
126
+ profile: simslimProfile,
127
+ out,
128
+ reconcileIosSimulator
129
+ });
130
+ }, adopted.deviceName, out, flags.simulatorApp);
131
+ return {
132
+ ...adopted,
133
+ booting,
134
+ deviceType: choice.deviceType,
135
+ runtime: choice.runtime
136
+ };
137
+ }
138
+ const created = await withIosDeviceNameLock(() => {
139
+ const suffix = ownedIosNameSuffix(label, {
140
+ model: choice.deviceType,
141
+ runtime: choice.runtime
142
+ }, projectPath);
143
+ const result = createOwnedIosSim(label, { suffix }, choice);
144
+ setDevice(projectPath, "ios", {
145
+ deviceUdid: result.udid,
146
+ owned: true,
147
+ deviceName: result.name
148
+ }, slot);
149
+ return result;
150
+ });
151
+ const newRecord = {
152
+ deviceUdid: created.udid,
153
+ owned: true,
154
+ deviceName: created.name
155
+ };
156
+ const booting = startIosBoot(created.udid, () => configureOwnedIosSim({
157
+ record: newRecord,
158
+ projectPath,
159
+ slot,
160
+ profile: simslimProfile,
161
+ out,
162
+ reconcileIosSimulator
163
+ }), created.name, out, flags.simulatorApp);
164
+ return {
165
+ ...newRecord,
166
+ created: true,
167
+ booting,
168
+ deviceType: created.deviceType,
169
+ runtime: created.runtime
170
+ };
171
+ }
172
+ function withIosDeviceNameLock(fn) {
173
+ return withWorkspaceProcessLock(getConfigDir(), "ios-device-names", async () => fn(), { external: true });
174
+ }
175
+ function ownedIosNameSuffix(label, model, projectPath, udid) {
176
+ const names = new Set(listAllIosSims({ includeUnavailable: true }).filter((sim) => sim.udid !== udid).map((sim) => sim.name));
177
+ for (const project of Object.values(loadConfig()?.projects ?? {})) for (const { platforms } of projectDeviceSlots(project)) {
178
+ const record = platforms.ios;
179
+ if (record?.deviceUdid !== udid && record?.deviceName) names.add(record.deviceName);
180
+ }
181
+ for (const parked of readParked("ios")) if (parked.udid !== udid) names.add(parked.name);
182
+ let suffix = "";
183
+ for (let attempt = 0; names.has(ownedSimName(label, model, suffix)); attempt++) suffix = ` ${workspaceId(projectPath)}${attempt ? `-${attempt}` : ""}`;
184
+ return suffix;
185
+ }
186
+ function renameToOwnedName(sim, label, model, projectPath) {
187
+ const wanted = ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, sim.udid));
188
+ if (sim.name === wanted) return wanted;
189
+ try {
190
+ renameIosSim(sim.udid, wanted);
191
+ return wanted;
192
+ } catch {
193
+ return sim.name;
194
+ }
195
+ }
196
+ function resetAdoptedSim(udid, out) {
197
+ out(chalk.dim(phaseLine("device", `resetting privacy grants and the keychain on ${udid}`)));
198
+ resetIosPrivacy(udid);
199
+ resetIosKeychain(udid);
200
+ }
201
+ function takeParkedIosSim({ projectPath, slot, label, choice, out }) {
202
+ const candidates = selectParked(readParked("ios"), {
203
+ deviceTypeIdentifier: choice.deviceTypeId,
204
+ runtimeIdentifier: choice.runtimeId
205
+ });
206
+ if (candidates.length === 0) return null;
207
+ const listed = new Map(listAllIosSims({ includeUnavailable: true }).map((sim) => [sim.udid, sim]));
208
+ for (const parked of candidates) {
209
+ const sim = listed.get(parked.udid);
210
+ if (!sim || !sim.available) {
211
+ const result = sim ? teardownParkedIosSim(parked.udid, { label: parked.name }) : null;
212
+ if (sim ? result?.status === "torn-down" : dropParked("ios", parked.udid)) out(chalk.dim(phaseLine("device", `deleted parked ${parked.name} (${parked.udid}): ${sim ? "unavailable" : "gone"}`)));
213
+ else if (result?.status === "failed") out(chalk.yellow(phaseLine("device", `could not delete unavailable parked ${parked.name} (${parked.udid}): ${result.reason}`)));
214
+ continue;
215
+ }
216
+ if (!sim.name.startsWith("stim-")) {
217
+ out(chalk.yellow(phaseLine("device", `kept parked record for ${parked.udid}: simulator is now named ${JSON.stringify(sim.name)} and is not Stim-owned`)));
218
+ continue;
219
+ }
220
+ const model = {
221
+ model: choice.deviceType,
222
+ runtime: choice.runtime
223
+ };
224
+ const name = ownedSimName(label, model, ownedIosNameSuffix(label, model, projectPath, parked.udid));
225
+ const device = {
226
+ deviceUdid: parked.udid,
227
+ owned: true,
228
+ deviceName: name,
229
+ adopted: true,
230
+ adoptionPending: true,
231
+ ...parked.simslimManaged ? { simslimManaged: true } : {},
232
+ ...parked.cacheKey ? { parkedCacheKey: parked.cacheKey } : {}
233
+ };
234
+ const adopted = adoptParked({
235
+ platform: "ios",
236
+ projectPath,
237
+ slot,
238
+ udid: parked.udid,
239
+ device
240
+ });
241
+ if (!adopted) continue;
242
+ try {
243
+ renameIosSim(parked.udid, name);
244
+ } catch {}
245
+ return adopted.schemeApprovals && adopted.schemeApprovals.length > 0 ? {
246
+ ...device,
247
+ schemeApprovals: adopted.schemeApprovals
248
+ } : device;
249
+ }
250
+ return null;
251
+ }
252
+ function clearIosAdoptionPending(projectPath, slot = "default") {
253
+ withConfigLock(() => {
254
+ const cfg = loadConfig();
255
+ const ios = deviceSlotPlatforms(cfg?.projects?.[projectPath], slot)?.ios;
256
+ if (!cfg || !ios?.adoptionPending) return;
257
+ delete ios.adopted;
258
+ delete ios.adoptionPending;
259
+ delete ios.parkedCacheKey;
260
+ saveConfig(cfg);
261
+ });
262
+ }
263
+ async function configureOwnedIosSim({ record, projectPath, slot, profile, out, reconcileIosSimulator }) {
264
+ if (profile) out(chalk.dim(phaseLine("device", `applying the SimSlim profile to ${record.deviceUdid}`)));
265
+ else if (record.simslimManaged) out(chalk.dim(phaseLine("device", `restoring stock simulator services on ${record.deviceUdid}`)));
266
+ const previouslyManaged = Boolean(record.simslimManaged);
267
+ if (profile && !record.simslimManaged) {
268
+ const pending = {
269
+ ...record,
270
+ simslimManaged: true
271
+ };
272
+ setDevice(projectPath, "ios", pending, slot);
273
+ record = pending;
274
+ }
275
+ const result = await reconcileIosSimulator({
276
+ udid: record.deviceUdid,
277
+ profile,
278
+ previouslyManaged,
279
+ out
280
+ });
281
+ const updated = { ...record };
282
+ if (result.managed) updated.simslimManaged = true;
283
+ else delete updated.simslimManaged;
284
+ setDevice(projectPath, "ios", updated, slot);
285
+ return updated;
286
+ }
287
+ async function ensureIosBooted({ device, simulatorApp, timeoutMs, pollMs, out }) {
288
+ const udid = device?.deviceUdid;
289
+ if (!udid) return {
290
+ failed: true,
291
+ reason: "No iOS simulator is recorded for this project."
292
+ };
293
+ const ready = () => {
294
+ try {
295
+ getExecutor().runFile("xcrun", [
296
+ "simctl",
297
+ "spawn",
298
+ udid,
299
+ "launchctl",
300
+ "list"
301
+ ], { timeoutMs: 3e4 });
302
+ return {
303
+ ok: true,
304
+ udid
305
+ };
306
+ } catch (error) {
307
+ return {
308
+ failed: true,
309
+ reason: `Simulator ${udid} failed its process-spawn readiness check: ${error?.message || error}. ${iosSimulatorFailureAdvice()}`
310
+ };
311
+ }
312
+ };
313
+ const booting = device?.booting;
314
+ if (booting?.udid === udid) {
315
+ try {
316
+ await booting.done;
317
+ } catch (e) {
318
+ return {
319
+ failed: true,
320
+ reason: `Could not boot simulator ${udid}: ${e?.message || e}`
321
+ };
322
+ }
323
+ return ready();
324
+ }
325
+ let resolved;
326
+ try {
327
+ resolved = resolveOwnedIosSim(udid);
328
+ } catch (e) {
329
+ return {
330
+ failed: true,
331
+ reason: `Could not list simulators: ${e?.message || e}`
332
+ };
333
+ }
334
+ if (resolved.missing) return {
335
+ failed: true,
336
+ reason: `Simulator ${udid} no longer exists. Run \`stim ios\` again to create a fresh owned sim.`
337
+ };
338
+ if (resolved.notOwned) return {
339
+ failed: true,
340
+ reason: `Simulator ${udid} is now named "${resolved.notOwned}" and is not Stim-owned; refusing to boot it.`
341
+ };
342
+ const sim = resolved.sim;
343
+ if (sim.state === "Booted") {
344
+ const result = ready();
345
+ if (result.ok && simulatorApp !== void 0) configuredIosSimulatorViewer(simulatorApp).open(udid);
346
+ return result;
347
+ }
348
+ out(chalk.dim(phaseLine("device", `booting ${sim.name} (${udid})`)));
349
+ const bootDeadline = Date.now() + timeoutMs;
350
+ try {
351
+ await bootIosSim(udid, {
352
+ timeoutMs,
353
+ label: sim.name,
354
+ out,
355
+ simulatorApp
356
+ });
357
+ } catch (e) {
358
+ return {
359
+ failed: true,
360
+ reason: `Could not boot simulator ${udid}: ${e?.message || e}`
361
+ };
362
+ }
363
+ const deadline = Math.max(bootDeadline, Date.now() + 2 * pollMs);
364
+ while (Date.now() < deadline) {
365
+ await sleep(pollMs);
366
+ let state = null;
367
+ try {
368
+ state = listAllIosSims({ timeoutMs: 3e4 }).find((s) => s.udid === udid)?.state ?? null;
369
+ } catch {}
370
+ if (state === "Booted") return ready();
371
+ }
372
+ return {
373
+ failed: true,
374
+ reason: `Simulator ${udid} did not reach the Booted state within ${Math.round(timeoutMs / 1e3)}s.`
375
+ };
376
+ }
377
+ function sleep(ms) {
378
+ return new Promise((r) => setTimeout(r, ms));
379
+ }
380
+ //#endregion
381
+ export { ensureOwnedIosDevice as i, clearIosAdoptionPending as n, ensureIosBooted as r, IosDeviceMismatchError as t };
@@ -1,15 +1,16 @@
1
- import { A as ownership_claim_exports, G as validateDeviceSlot, V as parseDeviceSlotKey, d as getConfigDir, z as deviceSlotKey } from "./config-lvc7d3C2.mjs";
2
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { r as register } from "./cache-manifest-C68QQ0ua.mjs";
4
- import { C as sharedBuildCache, F as withDirLock, b as writeWorkspaceState, h as readWorkspaceState, m as clearWorkspaceStateKeys, v as withWorkspaceStateLock } from "./metro-CcEo8Fl8.mjs";
5
- import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Drw_o-Fb.mjs";
6
- import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-DVcpw6eE.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, d as getConfigDir } from "./config-D0DbpZtM.mjs";
3
+ import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
4
+ import { r as register } from "./cache-manifest-DnUHBJaU.mjs";
5
+ import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-DnJMdEY-.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-B8-aJ1_5.mjs";
7
+ import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-D0XfSe8u.mjs";
8
+ import { createHash, randomBytes } from "node:crypto";
7
9
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
10
+ import { join } from "node:path";
8
11
  import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
9
- import { join } from "path";
12
+ import { join as join$1 } from "path";
10
13
  import { artifactIn, buildCacheKey, resolveArtifact, storeArtifact } from "@stim-cli/core";
11
- import { join as join$1 } from "node:path";
12
- import { createHash, randomBytes } from "node:crypto";
13
14
  import { isDeepStrictEqual } from "util";
14
15
  import * as expoFingerprint from "@expo/fingerprint";
15
16
  import { buildUploadTimeoutMs } from "@stim-cli/cache";
@@ -36,7 +37,7 @@ function readAssetManifest(root) {
36
37
  return;
37
38
  }
38
39
  for (const name of names) {
39
- const child = join$1(abs, name);
40
+ const child = join(abs, name);
40
41
  let stat;
41
42
  try {
42
43
  stat = statSync(child);
@@ -108,16 +109,16 @@ function pickGeneratedResDir(names, variant, reactChildren = []) {
108
109
  return null;
109
110
  }
110
111
  function androidModuleDirs(root, { list = safeList } = {}) {
111
- const android = join$1(root, "android");
112
- return ["app", ...list(android).filter((name) => name !== "app" && existsSync(join$1(android, name, "build", "generated", "res"))).toSorted()];
112
+ const android = join(root, "android");
113
+ return ["app", ...list(android).filter((name) => name !== "app" && existsSync(join(android, name, "build", "generated", "res"))).toSorted()];
113
114
  }
114
115
  function findGeneratedResDir(root, variant, { list = safeList } = {}) {
115
116
  for (const module of androidModuleDirs(root, { list })) {
116
- const base = join$1(root, "android", module, "build", "generated", "res");
117
+ const base = join(root, "android", module, "build", "generated", "res");
117
118
  const names = list(base);
118
119
  if (names.length === 0) continue;
119
- const picked = pickGeneratedResDir(names, variant, names.includes("react") ? list(join$1(base, "react")) : []);
120
- if (picked) return join$1(base, ...picked.split("/"));
120
+ const picked = pickGeneratedResDir(names, variant, names.includes("react") ? list(join(base, "react")) : []);
121
+ if (picked) return join(base, ...picked.split("/"));
121
122
  }
122
123
  return null;
123
124
  }
@@ -159,7 +160,7 @@ function safeList(dir) {
159
160
  //#endregion
160
161
  //#region src/cache/build-cache.ts
161
162
  function entryDir(platform, key, root = sharedBuildCache()) {
162
- return join(root, platform, key);
163
+ return join$1(root, platform, key);
163
164
  }
164
165
  const FINGERPRINT_PLATFORMS = /* @__PURE__ */ new Set(["ios", "android"]);
165
166
  /**
@@ -211,17 +212,17 @@ function storeBuild(platform, key, buildPath, rootOrOptions = {}) {
211
212
  overwrite: Boolean(options.overwrite),
212
213
  writeMetadata: (staging) => {
213
214
  if (Array.isArray(options.sources)) try {
214
- writeFileSync$1(join(staging, SOURCES_FILE), JSON.stringify(options.sources.map(withoutContents)));
215
+ writeFileSync$1(join$1(staging, SOURCES_FILE), JSON.stringify(options.sources.map(withoutContents)));
215
216
  } catch {}
216
217
  if (options.assetManifest) try {
217
- writeFileSync$1(join(staging, ASSET_MANIFEST_FILE), JSON.stringify(options.assetManifest));
218
+ writeFileSync$1(join$1(staging, ASSET_MANIFEST_FILE), JSON.stringify(options.assetManifest));
218
219
  } catch {}
219
220
  }
220
221
  });
221
222
  }
222
223
  const PROVIDER_DOWNLOAD_DIR = "cache-provider";
223
224
  function providerDownloadPath(workspacePath) {
224
- return join(workspacePath, PROVIDER_DOWNLOAD_DIR);
225
+ return join$1(workspacePath, PROVIDER_DOWNLOAD_DIR);
225
226
  }
226
227
  /**
227
228
  * Empties and registers the scratch directory a provider downloads into. It is
@@ -283,7 +284,7 @@ function withoutContents(source) {
283
284
  }
284
285
  function storedSources(platform, key, root = sharedBuildCache()) {
285
286
  try {
286
- const parsed = JSON.parse(readFileSync$1(join(entryDir(platform, key, root), SOURCES_FILE), "utf-8"));
287
+ const parsed = JSON.parse(readFileSync$1(join$1(entryDir(platform, key, root), SOURCES_FILE), "utf-8"));
287
288
  return Array.isArray(parsed) ? parsed : null;
288
289
  } catch {
289
290
  return null;
@@ -291,7 +292,7 @@ function storedSources(platform, key, root = sharedBuildCache()) {
291
292
  }
292
293
  function storedAssetManifest(platform, key, root = sharedBuildCache()) {
293
294
  try {
294
- return parseAssetManifest(readFileSync$1(join(entryDir(platform, key, root), ASSET_MANIFEST_FILE), "utf-8"));
295
+ return parseAssetManifest(readFileSync$1(join$1(entryDir(platform, key, root), ASSET_MANIFEST_FILE), "utf-8"));
295
296
  } catch {
296
297
  return null;
297
298
  }
@@ -485,10 +486,10 @@ function segment(value) {
485
486
  return String(value).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^\.+/, "") || "unknown";
486
487
  }
487
488
  function buildLocksDir() {
488
- return join$1(getConfigDir(), "build-locks");
489
+ return join(getConfigDir(), "build-locks");
489
490
  }
490
491
  function buildLockPath(platform, key) {
491
- return join$1(buildLocksDir(), `${segment(platform)}-${segment(key)}${LOCK_SUFFIX$1}`);
492
+ return join(buildLocksDir(), `${segment(platform)}-${segment(key)}${LOCK_SUFFIX$1}`);
492
493
  }
493
494
  function label(platform) {
494
495
  return `${platform} build`;
@@ -560,7 +561,7 @@ function listBuildLocks() {
560
561
  const locks = [];
561
562
  for (const name of names) {
562
563
  if (!name.endsWith(LOCK_SUFFIX$1)) continue;
563
- const path = join$1(dir, name);
564
+ const path = join(dir, name);
564
565
  try {
565
566
  if (!statSync(path).isDirectory()) continue;
566
567
  } catch {
@@ -652,7 +653,7 @@ async function waitForBuild({ platform, key, resolve = resolveBuild, intervalMs
652
653
  await sleep(intervalMs);
653
654
  }
654
655
  }
655
- async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, command, acquire, wait, now, phase, warn, out }) {
656
+ async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, command, acquire, wait, now, phase, waitingOn, warn, out }) {
656
657
  const waitStarted = now();
657
658
  let failedHolder;
658
659
  let released = null;
@@ -673,6 +674,7 @@ async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, c
673
674
  if (attempt?.acquired) {
674
675
  const previous = attempt.tookOver ?? failedHolder;
675
676
  if (previous) warn(takeoverLine(previous));
677
+ waitingOn(null);
676
678
  return {
677
679
  refusal: null,
678
680
  lock: attempt,
@@ -680,16 +682,20 @@ async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, c
680
682
  released
681
683
  };
682
684
  }
683
- if (!attempt?.held) return {
684
- refusal: null,
685
- lock: null,
686
- hit: null,
687
- released
688
- };
685
+ if (!attempt?.held) {
686
+ waitingOn(null);
687
+ return {
688
+ refusal: null,
689
+ lock: null,
690
+ hit: null,
691
+ released
692
+ };
693
+ }
689
694
  released = null;
690
695
  const holder = attempt.held;
691
696
  const who = holder.projectRoot || "another workspace";
692
697
  phase(`${who} is already building ${shortHash(fingerprint)} (pid ${holder.pid})${holder.logFile ? ` -- tail ${holder.logFile}` : ""} -- stim guide lifecycle concurrency`);
698
+ waitingOn(holder.projectRoot || null);
693
699
  let waited;
694
700
  try {
695
701
  const ceilingMs = WAIT_CEILING_MS - (now() - waitStarted);
@@ -715,6 +721,7 @@ async function waitForSharedBuild({ platform, key, fingerprint, root, logFile, c
715
721
  } };
716
722
  }
717
723
  if (waited.hit) {
724
+ waitingOn(null);
718
725
  phase(`waited ${formatDuration(waited.waitedMs)} for ${who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
719
726
  return {
720
727
  refusal: null,
@@ -750,16 +757,16 @@ const LEASE_SUFFIX = ".json";
750
757
  const LOCK_SUFFIX = ".lock";
751
758
  const DURATION = /^[1-9][0-9]*(s|m)$/;
752
759
  function deviceLocksDir() {
753
- return join$1(getConfigDir(), "device-locks");
760
+ return join(getConfigDir(), "device-locks");
754
761
  }
755
762
  function leaseStem(platform, id) {
756
763
  return `${segment(platform)}-${segment(id)}`;
757
764
  }
758
765
  function deviceLeasePath(platform, id) {
759
- return join$1(deviceLocksDir(), `${leaseStem(platform, id)}${LEASE_SUFFIX}`);
766
+ return join(deviceLocksDir(), `${leaseStem(platform, id)}${LEASE_SUFFIX}`);
760
767
  }
761
768
  function deviceLeaseLockPath(platform, id) {
762
- return join$1(deviceLocksDir(), `${leaseStem(platform, id)}${LOCK_SUFFIX}`);
769
+ return join(deviceLocksDir(), `${leaseStem(platform, id)}${LOCK_SUFFIX}`);
763
770
  }
764
771
  const fileLeaseIo = {
765
772
  withHolderLock: withWorkspaceStateLock,
@@ -793,7 +800,7 @@ const fileLeaseIo = {
793
800
  }
794
801
  },
795
802
  withLeaseLock(lockPath, fn) {
796
- return withDirLock(lockPath, fn, { ensureParent: () => mkdirSync(deviceLocksDir(), { recursive: true }) });
803
+ return withDirLock$1(lockPath, fn, { ensureParent: () => mkdirSync(deviceLocksDir(), { recursive: true }) });
797
804
  },
798
805
  readHolder(root) {
799
806
  return parseWorkspaceLeases(readWorkspaceState(root)?.deviceLeases);
@@ -878,7 +885,7 @@ function listLeaseFiles(io = fileLeaseIo) {
878
885
  const entries = [];
879
886
  for (const name of io.listLeaseNames().toSorted()) {
880
887
  if (!name.endsWith(LEASE_SUFFIX)) continue;
881
- const path = join$1(dir, name);
888
+ const path = join(dir, name);
882
889
  const lease = parseLease(io.readLease(path));
883
890
  const stem = name.slice(0, -5);
884
891
  const cut = stem.indexOf("-");