stim 1.0.0 → 1.2.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 (66) hide show
  1. package/README.md +29 -10
  2. package/dist/android-BW8i_YxU.mjs +204 -0
  3. package/dist/android-Bcmev2s2.mjs +2334 -0
  4. package/dist/android-K63_0UfF.mjs +727 -0
  5. package/dist/android-cas-D6HPZ6UQ.mjs +1078 -0
  6. package/dist/android-cas-compiler.mjs +2 -2
  7. package/dist/app-install-NFxUahnH.mjs +1149 -0
  8. package/dist/build-lock-BsVoLDaq.mjs +645 -0
  9. package/dist/build-slots-D0b6sJyo.mjs +152 -0
  10. package/dist/{cache-manifest-4tH64LQ9.mjs → cache-manifest-Cu4_Znw9.mjs} +2 -2
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +24 -27166
  13. package/dist/collector-run.d.mts +1 -0
  14. package/dist/collector-run.mjs +7 -5
  15. package/dist/command-output-8wHMEde0.mjs +289 -0
  16. package/dist/{config-7kmtuhO2.mjs → config-CMtIaTk9.mjs} +44 -13
  17. package/dist/deps-BLBsTNDS.mjs +435 -0
  18. package/dist/dev-client-RpvXxCXV.mjs +620 -0
  19. package/dist/device-CoCPmazS.mjs +250 -0
  20. package/dist/device-lease-Dpik41RY.mjs +335 -0
  21. package/dist/device-pool-B5pEVa3t.mjs +408 -0
  22. package/dist/device-remote-E81KAdXf.mjs +1209 -0
  23. package/dist/doctor-CqPeMsSm.mjs +1130 -0
  24. package/dist/doctor-D_CX7ib5.mjs +530 -0
  25. package/dist/error-diagnostics-Dw8Gn3yw.mjs +636 -0
  26. package/dist/{exec-bsN9MJXb.mjs → exec-CyylIdq9.mjs} +4 -2
  27. package/dist/gc-B7KkDinF.mjs +1665 -0
  28. package/dist/guide-BS2Xc24o.mjs +4503 -0
  29. package/dist/ios-B7KLgIp5.mjs +2733 -0
  30. package/dist/ios-D1h1Di39.mjs +451 -0
  31. package/dist/ios-device-D3pzTKQE.mjs +81 -0
  32. package/dist/ios-device-xNt0Lg6v.mjs +413 -0
  33. package/dist/logs-DcX9AvRF.mjs +176 -0
  34. package/dist/logs-query-oqn47Ffx.mjs +273 -0
  35. package/dist/metro-COslRK_F.mjs +184 -0
  36. package/dist/metro-store-CDDZHtPl.mjs +92 -0
  37. package/dist/ownership-CGPart6T.mjs +60 -0
  38. package/dist/ownership-CYOyqxUo.mjs +475 -0
  39. package/dist/ownership-claim-7zRxxTfZ.mjs +569 -0
  40. package/dist/{project-Dit1CckW.mjs → project-BBTVABUz.mjs} +12 -3
  41. package/dist/reclaim-C5Jmuahx.mjs +348 -0
  42. package/dist/reload-Z8nKifAk.mjs +332 -0
  43. package/dist/remote-cache-DDmJ1Roq.mjs +994 -0
  44. package/dist/{server-bare-BmTVVmBB.mjs → server-bare-DEk37Mz2.mjs} +8 -2
  45. package/dist/{server-expo-CHJe1r6j.mjs → server-expo-C3ktAwUG.mjs} +6 -5
  46. package/dist/server-expo-Drd7ksHu.mjs +2 -0
  47. package/dist/settings-DwU1_U_q.mjs +708 -0
  48. package/dist/spawn-entry-nCE6m770.mjs +14 -0
  49. package/dist/start-BrY4EuIg.mjs +822 -0
  50. package/dist/{state-2nush3MK.mjs → state-CZ-ER-8d.mjs} +21 -22
  51. package/dist/stats-BCWEVLrM.mjs +307 -0
  52. package/dist/stats-BsF15Bti.mjs +62 -0
  53. package/dist/status-DFI1Hfpg.mjs +393 -0
  54. package/dist/stop-B7DR4awK.mjs +3 -0
  55. package/dist/stop-Btg770vV.mjs +591 -0
  56. package/dist/supervisor-run.d.mts +0 -1
  57. package/dist/supervisor-run.mjs +4 -4
  58. package/dist/workspace-process-lock-BKfdys1q.mjs +47 -0
  59. package/dist/worktree-BPTbI-LN.mjs +1322 -0
  60. package/dist/worktree-C79xx_kM.mjs +543 -0
  61. package/dist/xcode-DeKCribl.mjs +1832 -0
  62. package/package.json +5 -5
  63. package/shim/bundle-response.cjs +5 -0
  64. package/dist/android-jc8MnUyL.mjs +0 -514
  65. package/dist/metro-store-COLl1pOk.mjs +0 -1249
  66. package/dist/server-expo-BZJm--wA.mjs +0 -2
@@ -0,0 +1,451 @@
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
3
+ import { mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ //#region src/host-memory.ts
7
+ function readHostMemoryPressure(exec = getExecutor(), platform = process.platform) {
8
+ if (platform !== "darwin") return null;
9
+ try {
10
+ switch (exec.runFile("/usr/sbin/sysctl", ["-n", "kern.memorystatus_vm_pressure_level"], { timeoutMs: 2e3 }).trim()) {
11
+ case "1": return "normal";
12
+ case "2": return "warning";
13
+ case "4": return "critical";
14
+ default: return null;
15
+ }
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ function hostMemoryPressureAdvice(pressure) {
21
+ if (pressure === null || pressure === "normal") return null;
22
+ return `macOS reports ${pressure} host memory pressure. Simulator processes can stall even when the device is Booted. Free memory before retrying: use \`stim stop\` only in workspaces you own, and ask before closing other apps or devices. For parallel iOS work, consider a reviewed SimSlim profile (\`stim guide lifecycle simslim\`). This observation does not establish an OOM crash.`;
23
+ }
24
+ //#endregion
25
+ //#region src/sim/ios.ts
26
+ function parseSimctlList(jsonOutput, { includeUnavailable = false } = {}) {
27
+ const parsed = JSON.parse(jsonOutput);
28
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Expected simctl list to return a JSON object with a devices object.");
29
+ const data = parsed;
30
+ if (data.devices === null || typeof data.devices !== "object" || Array.isArray(data.devices)) throw new Error("Expected simctl list to return a JSON object with a devices object.");
31
+ const sims = [];
32
+ for (const [runtime, devices] of Object.entries(data.devices)) {
33
+ if (!Array.isArray(devices)) throw new Error(`Expected simctl devices for ${runtime} to be an array.`);
34
+ if (!/\.iOS-/.test(runtime)) continue;
35
+ for (const dev of devices) {
36
+ if (dev === null || typeof dev !== "object" || Array.isArray(dev)) throw new Error(`Expected every simctl device for ${runtime} to be an object.`);
37
+ const record = dev;
38
+ for (const field of [
39
+ "udid",
40
+ "name",
41
+ "state",
42
+ "deviceTypeIdentifier"
43
+ ]) if (typeof record[field] !== "string" || record[field].length === 0) throw new Error(`Expected simctl device field ${field} for ${runtime} to be a non-empty string.`);
44
+ if (typeof record.isAvailable !== "boolean") throw new Error(`Expected simctl device field isAvailable for ${runtime} to be a boolean.`);
45
+ if (record.dataPath !== void 0 && typeof record.dataPath !== "string") throw new Error(`Expected simctl device field dataPath for ${runtime} to be a string.`);
46
+ if (record.dataPathSize !== void 0 && (typeof record.dataPathSize !== "number" || !Number.isFinite(record.dataPathSize))) throw new Error(`Expected simctl device field dataPathSize for ${runtime} to be a finite number.`);
47
+ const typed = record;
48
+ const available = Boolean(typed.isAvailable);
49
+ if (!available && !includeUnavailable) continue;
50
+ sims.push({
51
+ udid: typed.udid,
52
+ name: typed.name,
53
+ state: typed.state,
54
+ runtime,
55
+ deviceTypeIdentifier: typed.deviceTypeIdentifier,
56
+ available,
57
+ ...typed.dataPath !== void 0 ? { dataPath: typed.dataPath } : {},
58
+ ...typed.dataPathSize !== void 0 ? { dataPathSize: typed.dataPathSize } : {}
59
+ });
60
+ }
61
+ }
62
+ return sims;
63
+ }
64
+ function listAllIosSims({ timeoutMs = 3e4, includeUnavailable = false } = {}) {
65
+ return parseSimctlList(getExecutor().runFile("xcrun", [
66
+ "simctl",
67
+ "list",
68
+ "devices",
69
+ "--json"
70
+ ], {
71
+ timeoutMs,
72
+ killSignal: "SIGKILL"
73
+ }), { includeUnavailable });
74
+ }
75
+ function parseRuntimeVersion(runtimeId) {
76
+ const m = runtimeId.match(/iOS-(\d+)(?:-(\d+))?$/);
77
+ if (!m) return runtimeId;
78
+ const major = m[1];
79
+ if (major === void 0) return runtimeId;
80
+ const minor = m[2];
81
+ return minor ? `${major}.${minor}` : major;
82
+ }
83
+ const IOS_BOOT_TIMEOUT_MS = 6e5;
84
+ const BOOTSTATUS_ATTEMPT_MS = 24e4;
85
+ const BOOTSTATUS_ATTEMPT_FLOOR_MS = 1e3;
86
+ const BOOT_STATE_LIST_TIMEOUT_MS = 3e4;
87
+ function iosSimulatorFailureAdvice(exec = getExecutor()) {
88
+ return hostMemoryPressureAdvice(readHostMemoryPressure(exec)) ?? "The simulator may be unresponsive. Check Activity Monitor for memory pressure and free host memory before retrying.";
89
+ }
90
+ function bootstatusTimeout(udid) {
91
+ const e = /* @__PURE__ */ new Error(`xcrun simctl bootstatus ${udid} -b timed out`);
92
+ e.code = "ETIMEDOUT";
93
+ return e;
94
+ }
95
+ async function awaitBootstatus(udid, attemptMs) {
96
+ const lines = [];
97
+ const reader = createLineReader((raw) => {
98
+ const line = stripAnsi(raw).trim();
99
+ if (!line) return;
100
+ lines.push(line);
101
+ if (lines.length > 10) lines.shift();
102
+ });
103
+ const child = getExecutor().spawn("xcrun", [
104
+ "simctl",
105
+ "bootstatus",
106
+ udid,
107
+ "-b"
108
+ ], { stdio: [
109
+ "ignore",
110
+ "pipe",
111
+ "pipe"
112
+ ] });
113
+ child.stdout?.on("data", (chunk) => reader.push(chunk));
114
+ child.stderr?.on("data", (chunk) => reader.push(chunk));
115
+ let timer;
116
+ const attempt = new Promise((resolve) => {
117
+ timer = setTimeout(() => resolve("timeout"), attemptMs);
118
+ });
119
+ const exited = new Promise((resolve) => child.once("exit", () => resolve()));
120
+ const result = await Promise.race([waitForChild(child), attempt]);
121
+ clearTimeout(timer);
122
+ reader.flush();
123
+ if (result === "timeout") {
124
+ try {
125
+ child.kill("SIGKILL");
126
+ } catch {}
127
+ const stopped = await Promise.race([exited.then(() => true), new Promise((resolve) => {
128
+ timer = setTimeout(() => resolve(false), 1e4);
129
+ })]);
130
+ clearTimeout(timer);
131
+ if (!stopped) {
132
+ child.stdout?.destroy?.();
133
+ child.stderr?.destroy?.();
134
+ child.unref();
135
+ throw new Error(`Timed out waiting for simctl bootstatus ${udid}; its process could not be confirmed stopped. Inspect pid ${child.pid ?? "unknown"} before retrying.`);
136
+ }
137
+ throw bootstatusTimeout(udid);
138
+ }
139
+ if (result.error) throw result.error;
140
+ if (result.code === 0) return;
141
+ const detail = lines.length ? `: ${lines.join(" | ")}` : "";
142
+ throw new Error(`xcrun simctl bootstatus ${udid} -b failed with exit code ${result.code ?? "unknown"}${detail}`);
143
+ }
144
+ async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = BOOTSTATUS_ATTEMPT_MS } = {}) {
145
+ const exec = getExecutor();
146
+ const deadline = Date.now() + timeoutMs;
147
+ try {
148
+ exec.runFile("xcrun", [
149
+ "simctl",
150
+ "boot",
151
+ udid
152
+ ], {
153
+ timeoutMs,
154
+ killSignal: "SIGKILL"
155
+ });
156
+ } catch (e) {
157
+ if (!String(e?.message || e).includes("Booted")) throw e;
158
+ }
159
+ for (;;) {
160
+ const remaining = deadline - Date.now();
161
+ if (remaining > 0) try {
162
+ await awaitBootstatus(udid, Math.min(Math.max(remaining, BOOTSTATUS_ATTEMPT_FLOOR_MS), attemptMs));
163
+ break;
164
+ } catch (e) {
165
+ if (e?.code !== "ETIMEDOUT") throw e;
166
+ }
167
+ let state;
168
+ try {
169
+ state = listAllIosSims({ timeoutMs: BOOT_STATE_LIST_TIMEOUT_MS }).find((s) => s.udid === udid)?.state ?? null;
170
+ } catch {
171
+ state = void 0;
172
+ }
173
+ if (state === "Booted") break;
174
+ const waited = Math.round((timeoutMs - Math.max(0, deadline - Date.now())) / 1e3);
175
+ if (state !== "Booting" && state !== void 0) throw new Error(`Simulator ${udid} reports "${state ?? "missing"}" after ${waited}s of boot wait.`);
176
+ if (deadline - Date.now() <= 0) throw new Error(`Simulator ${udid} did not finish booting within ${Math.round(timeoutMs / 1e3)}s.`);
177
+ }
178
+ exec.runFileQuiet("open", ["-a", "Simulator"], {
179
+ timeoutMs: 5e3,
180
+ killSignal: "SIGKILL"
181
+ });
182
+ }
183
+ function shutdownIosSim(udid) {
184
+ getExecutor().runQuiet(`xcrun simctl shutdown ${udid}`);
185
+ }
186
+ function listIosDeviceTypes() {
187
+ const out = getExecutor().runFile("xcrun", [
188
+ "simctl",
189
+ "list",
190
+ "devicetypes",
191
+ "--json"
192
+ ], {
193
+ timeoutMs: 3e4,
194
+ killSignal: "SIGKILL"
195
+ });
196
+ return (JSON.parse(out).devicetypes || []).map((dt) => ({
197
+ identifier: dt.identifier,
198
+ name: dt.name
199
+ }));
200
+ }
201
+ function rankIphone(name) {
202
+ const gen = /^iPhone\s+(\d+)/i.exec(name);
203
+ return {
204
+ gen: gen ? Number(gen[1]) : -1,
205
+ variant: -name.length
206
+ };
207
+ }
208
+ function iosRuntimeMatches(runtime, requested) {
209
+ return runtime.version === requested || runtime.name === requested;
210
+ }
211
+ function pickDefaultIosCreation(_deviceTypes, runtimes, { deviceType, runtime } = {}) {
212
+ const rts = runtimes.toSorted((a, b) => String(b.version).localeCompare(String(a.version), void 0, { numeric: true }));
213
+ const wantedRts = runtime ? rts.filter((r) => iosRuntimeMatches(r, runtime)) : rts;
214
+ for (const rt of wantedRts) {
215
+ const supported = (rt.supportedDeviceTypes || []).filter((d) => deviceType ? d.name === deviceType : /^iPhone/i.test(d.name));
216
+ if (supported.length === 0) continue;
217
+ const best = supported.toSorted((a, b) => {
218
+ const ra = rankIphone(a.name), rb = rankIphone(b.name);
219
+ return rb.gen - ra.gen || rb.variant - ra.variant || b.name.localeCompare(a.name, void 0, { numeric: true });
220
+ })[0];
221
+ if (best === void 0) continue;
222
+ return {
223
+ deviceTypeId: best.identifier,
224
+ runtimeId: rt.identifier
225
+ };
226
+ }
227
+ return null;
228
+ }
229
+ function sanitizeDeviceLabel(label) {
230
+ return String(label).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
231
+ }
232
+ const SIM_NAME_MAX = 60;
233
+ const PARKED_SIM_LABEL = "parked";
234
+ function fitSimName(label, { model, runtime }, suffix = "", preserveLabel = false) {
235
+ const version = runtime ?? "";
236
+ const modelName = model ?? "";
237
+ if (!version && !modelName) return `stim-${label}${suffix}`;
238
+ let over = `stim-`.length + 2 + 1 + 1 + version.length + suffix.length + label.length + modelName.length - SIM_NAME_MAX;
239
+ let shortLabel = label;
240
+ if (over > 0 && !preserveLabel) {
241
+ const cut = Math.min(over, label.length);
242
+ shortLabel = label.slice(0, label.length - cut).replace(/[._-]+$/g, "");
243
+ over -= cut;
244
+ }
245
+ const shortModel = over > 0 ? modelName.slice(0, Math.max(0, modelName.length - over)) : modelName;
246
+ return `stim-${shortLabel} (${shortModel} ${version})${suffix}`;
247
+ }
248
+ function ownedSimName(label, model = {
249
+ model: null,
250
+ runtime: null
251
+ }, suffix = "") {
252
+ const clean = sanitizeDeviceLabel(label);
253
+ return fitSimName(clean.startsWith("stim-") ? clean.slice(5) : clean, model, suffix);
254
+ }
255
+ function parkedSimName(udid, model) {
256
+ return fitSimName(PARKED_SIM_LABEL, model, ` ${udid.replace(/-/g, "").slice(0, 4).toLowerCase()}`, true);
257
+ }
258
+ function resolveIosCreation({ deviceType, runtime } = {}) {
259
+ const deviceTypes = listIosDeviceTypes();
260
+ const runtimes = listIosRuntimes();
261
+ const pick = pickDefaultIosCreation(deviceTypes, runtimes, {
262
+ deviceType,
263
+ runtime
264
+ });
265
+ if (!pick) throw new Error("No matching simulator device type / runtime is installed. Install one via Xcode, or pass --device-type / --runtime.");
266
+ return {
267
+ deviceTypeId: pick.deviceTypeId,
268
+ runtimeId: pick.runtimeId,
269
+ deviceType: deviceTypes.find((d) => d.identifier === pick.deviceTypeId)?.name ?? null,
270
+ runtime: runtimes.find((r) => r.identifier === pick.runtimeId)?.version ?? null
271
+ };
272
+ }
273
+ function createOwnedIosSim(label, { deviceType, runtime, suffix = "" } = {}, choice = resolveIosCreation({
274
+ deviceType,
275
+ runtime
276
+ })) {
277
+ const name = ownedSimName(label, {
278
+ model: choice.deviceType,
279
+ runtime: choice.runtime
280
+ }, suffix);
281
+ return {
282
+ udid: getExecutor().run(`xcrun simctl create "${name}" "${choice.deviceTypeId}" "${choice.runtimeId}"`).trim(),
283
+ name,
284
+ deviceType: choice.deviceType,
285
+ runtime: choice.runtime
286
+ };
287
+ }
288
+ function renameIosSim(udid, name) {
289
+ getExecutor().runFile("xcrun", [
290
+ "simctl",
291
+ "rename",
292
+ udid,
293
+ name
294
+ ]);
295
+ }
296
+ function resetIosPrivacy(udid) {
297
+ getExecutor().runFile("xcrun", [
298
+ "simctl",
299
+ "privacy",
300
+ udid,
301
+ "reset",
302
+ "all"
303
+ ]);
304
+ }
305
+ function resetIosKeychain(udid) {
306
+ getExecutor().runFile("xcrun", [
307
+ "simctl",
308
+ "keychain",
309
+ udid,
310
+ "reset"
311
+ ]);
312
+ }
313
+ function uninstallIosApp(udid, bundleId) {
314
+ getExecutor().runFile("xcrun", [
315
+ "simctl",
316
+ "uninstall",
317
+ udid,
318
+ bundleId
319
+ ]);
320
+ }
321
+ function parseUserApps(jsonOutput) {
322
+ const data = JSON.parse(jsonOutput);
323
+ if (data === null || typeof data !== "object" || Array.isArray(data)) throw new Error("Expected simctl listapps to convert to a JSON object.");
324
+ const userApps = [];
325
+ for (const [bundleId, app] of Object.entries(data)) {
326
+ if (app === null || typeof app !== "object" || Array.isArray(app)) throw new Error(`Expected simctl listapps entry ${JSON.stringify(bundleId)} to be an object.`);
327
+ const applicationType = app.ApplicationType;
328
+ if (applicationType !== "User" && applicationType !== "System") throw new Error(`Expected simctl listapps entry ${JSON.stringify(bundleId)} to name a known ApplicationType.`);
329
+ if (applicationType === "User") userApps.push(bundleId);
330
+ }
331
+ return userApps;
332
+ }
333
+ const LISTAPPS_TIMEOUT_MS = 6e4;
334
+ function listUserApps(udid) {
335
+ const exec = getExecutor();
336
+ const dir = mkdtempSync(join(tmpdir(), "stim-listapps-"));
337
+ const plist = join(dir, "apps.plist");
338
+ try {
339
+ writeFileSync(plist, exec.runFile("xcrun", [
340
+ "simctl",
341
+ "listapps",
342
+ udid
343
+ ], { timeoutMs: LISTAPPS_TIMEOUT_MS }));
344
+ return parseUserApps(exec.runFile("plutil", [
345
+ "-convert",
346
+ "json",
347
+ "-o",
348
+ "-",
349
+ plist
350
+ ]));
351
+ } finally {
352
+ rmSync(dir, {
353
+ recursive: true,
354
+ force: true
355
+ });
356
+ }
357
+ }
358
+ const CONTAINER_METADATA = ".com.apple.mobile_container_manager.metadata.plist";
359
+ const CLEARED_CONTAINER_DIRS = [
360
+ "Documents",
361
+ "Library",
362
+ "tmp",
363
+ "SystemData"
364
+ ];
365
+ const PLUTIL_TIMEOUT_MS = 1e4;
366
+ function findAppDataContainer(dataPath, bundleId) {
367
+ const root = join(dataPath, "Containers", "Data", "Application");
368
+ let entries;
369
+ try {
370
+ entries = readdirSync(root);
371
+ } catch (error) {
372
+ if (error?.code === "ENOENT") return null;
373
+ throw error;
374
+ }
375
+ const exec = getExecutor();
376
+ for (const entry of entries) {
377
+ const dir = join(root, entry);
378
+ if (exec.runFile("plutil", [
379
+ "-extract",
380
+ "MCMMetadataIdentifier",
381
+ "raw",
382
+ join(dir, CONTAINER_METADATA)
383
+ ], { timeoutMs: PLUTIL_TIMEOUT_MS }).trim() === bundleId) return dir;
384
+ }
385
+ return null;
386
+ }
387
+ function clearAppDataContainer(container) {
388
+ for (const name of CLEARED_CONTAINER_DIRS) {
389
+ const dir = join(container, name);
390
+ let children;
391
+ try {
392
+ if (!statSync(dir).isDirectory()) throw new Error(`Expected app data path ${dir} to be a directory.`);
393
+ children = readdirSync(dir);
394
+ } catch (error) {
395
+ if (error?.code === "ENOENT") continue;
396
+ throw error;
397
+ }
398
+ for (const child of children) rmSync(join(dir, child), {
399
+ recursive: true,
400
+ force: true
401
+ });
402
+ }
403
+ }
404
+ function resolveOwnedIosSim(udid) {
405
+ const sim = listAllIosSims().find((s) => s.udid === udid);
406
+ if (!sim) return { missing: true };
407
+ if (!sim.name?.startsWith("stim-")) return { notOwned: sim.name };
408
+ return { sim };
409
+ }
410
+ function deleteIosSim(udid) {
411
+ const result = resolveOwnedIosSim(udid);
412
+ if (result.missing) return;
413
+ if (result.notOwned) throw new Error(`Refusing to delete simulator "${result.notOwned}" (${udid}): not a Stim-owned sim (name must start with "stim-").`);
414
+ getExecutor().run(`xcrun simctl delete ${udid}`);
415
+ }
416
+ const PARKED_DELETE_TIMEOUT_MS = 3e4;
417
+ function deleteParkedIosSim(udid) {
418
+ const sim = listAllIosSims({
419
+ includeUnavailable: true,
420
+ timeoutMs: PARKED_DELETE_TIMEOUT_MS
421
+ }).find((entry) => entry.udid === udid);
422
+ if (!sim) return;
423
+ if (!sim.name.startsWith("stim-")) throw new Error(`Simulator ${udid} is now named "${sim.name}" and is not Stim-owned; refusing to delete it.`);
424
+ getExecutor().runFile("xcrun", [
425
+ "simctl",
426
+ "delete",
427
+ udid
428
+ ], { timeoutMs: PARKED_DELETE_TIMEOUT_MS });
429
+ }
430
+ function listIosRuntimes() {
431
+ const out = getExecutor().runFile("xcrun", [
432
+ "simctl",
433
+ "list",
434
+ "runtimes",
435
+ "--json"
436
+ ], {
437
+ timeoutMs: 3e4,
438
+ killSignal: "SIGKILL"
439
+ });
440
+ return (JSON.parse(out).runtimes || []).filter((r) => r.isAvailable && r.platform === "iOS").map((r) => ({
441
+ identifier: r.identifier,
442
+ name: r.name,
443
+ version: r.version,
444
+ supportedDeviceTypes: (r.supportedDeviceTypes || []).map((d) => ({
445
+ identifier: d.identifier,
446
+ name: d.name
447
+ }))
448
+ }));
449
+ }
450
+ //#endregion
451
+ export { shutdownIosSim as C, readHostMemoryPressure as E, sanitizeDeviceLabel as S, hostMemoryPressureAdvice as T, renameIosSim as _, deleteIosSim as a, resolveIosCreation as b, iosRuntimeMatches as c, listIosDeviceTypes as d, listIosRuntimes as f, parseRuntimeVersion as g, parkedSimName as h, createOwnedIosSim as i, iosSimulatorFailureAdvice as l, ownedSimName as m, bootIosSim as n, deleteParkedIosSim as o, listUserApps as p, clearAppDataContainer as r, findAppDataContainer as s, IOS_BOOT_TIMEOUT_MS as t, listAllIosSims as u, resetIosKeychain as v, uninstallIosApp as w, resolveOwnedIosSim as x, resetIosPrivacy as y };
@@ -0,0 +1,81 @@
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ //#region src/collector/ios-device.ts
3
+ const CONSOLE_ENV = { OS_ACTIVITY_DT_MODE: "enable" };
4
+ const DEV_MENU_LAUNCH_ARGS = [
5
+ "-EXDevMenuShowsAtLaunch",
6
+ "0",
7
+ "-EXDevMenuShowFloatingActionButton",
8
+ "0"
9
+ ];
10
+ const FATAL_MARKERS = [
11
+ /^\*\*\* Terminating app due to uncaught exception/,
12
+ /^libc\+\+abi: terminating/,
13
+ /^\*\*\* Assertion failure in/,
14
+ /^(?:\S+:\d+: )?Fatal error: /
15
+ ];
16
+ const MIRROR_LINE = /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+[+-]\d{4}) (.+?)\[(\d+):(\d+)\] ?(?:\[([^\]\s]+)\] )?([\s\S]*)$/;
17
+ function deviceConsoleLevel(message) {
18
+ const text = typeof message === "string" ? message : "";
19
+ return FATAL_MARKERS.some((marker) => marker.test(text)) ? "fatal" : "info";
20
+ }
21
+ function parseDeviceConsoleLine(line, { now = Date.now } = {}) {
22
+ if (typeof line !== "string") return null;
23
+ const text = line.replace(/\r$/, "").trimEnd();
24
+ if (!text.trim()) return null;
25
+ const match = MIRROR_LINE.exec(text);
26
+ const record = {
27
+ ts: now(),
28
+ src: "device",
29
+ level: "info",
30
+ msg: text,
31
+ raw: true
32
+ };
33
+ if (!match) {
34
+ record.level = text.startsWith("ERROR: ") ? "error" : deviceConsoleLevel(text);
35
+ return record;
36
+ }
37
+ const [, timestamp, proc, pid, , category, message] = match;
38
+ if (message === void 0 || !message.trim()) return null;
39
+ const parsed = Date.parse(timestamp);
40
+ if (Number.isFinite(parsed)) record.ts = parsed;
41
+ record.msg = message;
42
+ record.level = deviceConsoleLevel(message);
43
+ record.proc = `${proc}(${pid})`;
44
+ if (category) record.category = category;
45
+ return record;
46
+ }
47
+ function deviceConsoleArgs({ udid, bundleId, payloadUrl = null }) {
48
+ const args = [
49
+ "devicectl",
50
+ "device",
51
+ "process",
52
+ "launch",
53
+ "--quiet",
54
+ "--device",
55
+ udid,
56
+ "--console",
57
+ "--terminate-existing",
58
+ "--environment-variables",
59
+ JSON.stringify(CONSOLE_ENV)
60
+ ];
61
+ if (payloadUrl) args.push("--payload-url", payloadUrl);
62
+ args.push(bundleId);
63
+ if (payloadUrl) args.push("--", ...DEV_MENU_LAUNCH_ARGS);
64
+ return args;
65
+ }
66
+ function startIosDeviceConsole({ udid, bundleId, payloadUrl = null, spawnFn = null }) {
67
+ return (spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts)))("xcrun", deviceConsoleArgs({
68
+ udid,
69
+ bundleId,
70
+ payloadUrl
71
+ }), {
72
+ stdio: [
73
+ "ignore",
74
+ "pipe",
75
+ "pipe"
76
+ ],
77
+ detached: false
78
+ });
79
+ }
80
+ //#endregion
81
+ export { startIosDeviceConsole as i, deviceConsoleLevel as n, parseDeviceConsoleLine as r, DEV_MENU_LAUNCH_ARGS as t };