stim 1.1.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 (59) hide show
  1. package/README.md +7 -0
  2. package/dist/{android-CC5bUer7.mjs → android-BW8i_YxU.mjs} +1 -1
  3. package/dist/{android-DnZlT3aU.mjs → android-Bcmev2s2.mjs} +86 -31
  4. package/dist/{android-xmyGBNy5.mjs → android-K63_0UfF.mjs} +77 -15
  5. package/dist/{android-cas-DGlTStWu.mjs → android-cas-D6HPZ6UQ.mjs} +6 -6
  6. package/dist/android-cas-compiler.mjs +1 -1
  7. package/dist/{app-install-oZIQRbdD.mjs → app-install-NFxUahnH.mjs} +25 -17
  8. package/dist/{build-lock-vE45ZzJZ.mjs → build-lock-BsVoLDaq.mjs} +6 -6
  9. package/dist/{build-slots-CgacA9zQ.mjs → build-slots-D0b6sJyo.mjs} +3 -3
  10. package/dist/{cache-manifest-oeH18ERr.mjs → cache-manifest-Cu4_Znw9.mjs} +1 -1
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +13 -13
  13. package/dist/collector-run.d.mts +1 -0
  14. package/dist/collector-run.mjs +6 -6
  15. package/dist/{config-D7uu8Gbq.mjs → config-CMtIaTk9.mjs} +1 -1
  16. package/dist/{deps-64wVnpZc.mjs → deps-BLBsTNDS.mjs} +2 -2
  17. package/dist/{dev-client-Bvky1hya.mjs → dev-client-RpvXxCXV.mjs} +72 -9
  18. package/dist/{device-DJKv5Qej.mjs → device-CoCPmazS.mjs} +5 -5
  19. package/dist/{device-lease-D-G3SgVe.mjs → device-lease-Dpik41RY.mjs} +3 -3
  20. package/dist/{device-pool-BlHXnYYs.mjs → device-pool-B5pEVa3t.mjs} +3 -3
  21. package/dist/{device-remote-CCgkG82J.mjs → device-remote-E81KAdXf.mjs} +8 -8
  22. package/dist/{doctor-DlVxTtMq.mjs → doctor-CqPeMsSm.mjs} +19 -26
  23. package/dist/{doctor-BRF9aAJ3.mjs → doctor-D_CX7ib5.mjs} +10 -10
  24. package/dist/{error-diagnostics-B5IJwv3-.mjs → error-diagnostics-Dw8Gn3yw.mjs} +8 -8
  25. package/dist/{exec-bsN9MJXb.mjs → exec-CyylIdq9.mjs} +4 -2
  26. package/dist/{gc-DhXdgSdt.mjs → gc-B7KkDinF.mjs} +39 -25
  27. package/dist/{guide-DrhrDBo5.mjs → guide-BS2Xc24o.mjs} +220 -36
  28. package/dist/{ios-CK1Vrk6Q.mjs → ios-B7KLgIp5.mjs} +38 -26
  29. package/dist/{ios-BZxKPuqP.mjs → ios-D1h1Di39.mjs} +79 -10
  30. package/dist/{ios-device-CYbuRNXR.mjs → ios-device-D3pzTKQE.mjs} +1 -1
  31. package/dist/{ios-device-CdSm0GDw.mjs → ios-device-xNt0Lg6v.mjs} +2 -2
  32. package/dist/{logs-Dxoy16Qv.mjs → logs-DcX9AvRF.mjs} +3 -3
  33. package/dist/{metro-B01H3EuD.mjs → metro-COslRK_F.mjs} +3 -3
  34. package/dist/{ownership-D8HmSv2E.mjs → ownership-CGPart6T.mjs} +3 -3
  35. package/dist/{ownership-B9QIdQOw.mjs → ownership-CYOyqxUo.mjs} +4 -4
  36. package/dist/{ownership-claim-CeJLEpjD.mjs → ownership-claim-7zRxxTfZ.mjs} +1 -1
  37. package/dist/{project-COj6nzzh.mjs → project-BBTVABUz.mjs} +2 -2
  38. package/dist/{reclaim-BPvN2HlP.mjs → reclaim-C5Jmuahx.mjs} +9 -8
  39. package/dist/{reload-DYZEBbZy.mjs → reload-Z8nKifAk.mjs} +7 -7
  40. package/dist/{remote-cache-DOi5-zLj.mjs → remote-cache-DDmJ1Roq.mjs} +73 -13
  41. package/dist/{server-bare-BYHqEeyw.mjs → server-bare-DEk37Mz2.mjs} +7 -2
  42. package/dist/{server-expo-BEMr_m6p.mjs → server-expo-C3ktAwUG.mjs} +4 -4
  43. package/dist/server-expo-Drd7ksHu.mjs +2 -0
  44. package/dist/{settings-BSwrY4FZ.mjs → settings-DwU1_U_q.mjs} +26 -5
  45. package/dist/{start-ByCylYtB.mjs → start-BrY4EuIg.mjs} +10 -10
  46. package/dist/{state-IYEY-zi8.mjs → state-CZ-ER-8d.mjs} +1 -1
  47. package/dist/{stats-wqxPm7Tv.mjs → stats-BCWEVLrM.mjs} +1 -1
  48. package/dist/{stats-DZ4Q5J-7.mjs → stats-BsF15Bti.mjs} +3 -3
  49. package/dist/{status-Dia0XTqG.mjs → status-DFI1Hfpg.mjs} +46 -16
  50. package/dist/{stop-D6o5zAdm.mjs → stop-B7DR4awK.mjs} +2 -2
  51. package/dist/{stop-BApyaF21.mjs → stop-Btg770vV.mjs} +9 -9
  52. package/dist/supervisor-run.mjs +4 -4
  53. package/dist/{workspace-process-lock-CxOO9-pf.mjs → workspace-process-lock-BKfdys1q.mjs} +1 -1
  54. package/dist/{worktree-DxEmUI_n.mjs → worktree-BPTbI-LN.mjs} +16 -16
  55. package/dist/{worktree-Dx3ZC5lS.mjs → worktree-C79xx_kM.mjs} +7 -3
  56. package/dist/{xcode-CDB6fytw.mjs → xcode-DeKCribl.mjs} +190 -63
  57. package/package.json +5 -5
  58. package/shim/bundle-response.cjs +5 -0
  59. package/dist/server-expo-rb0k-0w7.mjs +0 -2
@@ -1,4 +1,4 @@
1
- import { u as getConfigDir } from "./config-D7uu8Gbq.mjs";
1
+ import { u as getConfigDir } from "./config-CMtIaTk9.mjs";
2
2
  import { existsSync } from "fs";
3
3
  import { homedir } from "os";
4
4
  import { join, resolve } from "path";
@@ -1,2 +1,2 @@
1
- import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-oeH18ERr.mjs";
1
+ import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-Cu4_Znw9.mjs";
2
2
  export { manifestPath, readManifest, register, registeredCaches, unregister };
package/dist/cli.mjs CHANGED
@@ -3,19 +3,19 @@ import { readFileSync } from "node:fs";
3
3
  import { Command } from "commander";
4
4
  //#region bin/cli.ts
5
5
  const commands = /* @__PURE__ */ new Map([
6
- ["doctor", () => import("./doctor-BRF9aAJ3.mjs")],
7
- ["worktree", () => import("./worktree-DxEmUI_n.mjs")],
8
- ["start", () => import("./start-ByCylYtB.mjs")],
9
- ["stop", () => import("./stop-D6o5zAdm.mjs")],
10
- ["ios", () => import("./ios-CK1Vrk6Q.mjs")],
11
- ["android", () => import("./android-DnZlT3aU.mjs")],
12
- ["reload", () => import("./reload-DYZEBbZy.mjs")],
13
- ["device", () => import("./device-DJKv5Qej.mjs")],
14
- ["logs", () => import("./logs-Dxoy16Qv.mjs")],
15
- ["status", () => import("./status-Dia0XTqG.mjs")],
16
- ["stats", () => import("./stats-DZ4Q5J-7.mjs")],
17
- ["gc", () => import("./gc-DhXdgSdt.mjs")],
18
- ["guide", () => import("./guide-DrhrDBo5.mjs")]
6
+ ["doctor", () => import("./doctor-D_CX7ib5.mjs")],
7
+ ["worktree", () => import("./worktree-BPTbI-LN.mjs")],
8
+ ["start", () => import("./start-BrY4EuIg.mjs")],
9
+ ["stop", () => import("./stop-B7DR4awK.mjs")],
10
+ ["ios", () => import("./ios-B7KLgIp5.mjs")],
11
+ ["android", () => import("./android-Bcmev2s2.mjs")],
12
+ ["reload", () => import("./reload-Z8nKifAk.mjs")],
13
+ ["device", () => import("./device-CoCPmazS.mjs")],
14
+ ["logs", () => import("./logs-DcX9AvRF.mjs")],
15
+ ["status", () => import("./status-DFI1Hfpg.mjs")],
16
+ ["stats", () => import("./stats-BsF15Bti.mjs")],
17
+ ["gc", () => import("./gc-B7KkDinF.mjs")],
18
+ ["guide", () => import("./guide-BS2Xc24o.mjs")]
19
19
  ]);
20
20
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
21
21
  const program = new Command();
@@ -4,6 +4,7 @@ import { ChildProcess as ChildProcess$1 } from "node:child_process";
4
4
  //#region src/exec.d.ts
5
5
  interface ExecOptions {
6
6
  timeoutMs?: number;
7
+ killSignal?: NodeJS.Signals;
7
8
  cwd?: string;
8
9
  env?: Record<string, string>;
9
10
  omitEnv?: readonly string[];
@@ -1,11 +1,11 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { T as captureProcessToken } from "./config-D7uu8Gbq.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { T as captureProcessToken } from "./config-CMtIaTk9.mjs";
3
3
  import { r as createNdjsonWriter } from "./ndjson-DcAtEx_K.mjs";
4
- import { D as workspaceLogsDir } from "./state-IYEY-zi8.mjs";
4
+ import { D as workspaceLogsDir } from "./state-CZ-ER-8d.mjs";
5
5
  import { t as createLineReader } from "./process-output-C7IlIzd7.mjs";
6
- import { i as startIosDeviceConsole, r as parseDeviceConsoleLine } from "./ios-device-CYbuRNXR.mjs";
7
- import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-D8HmSv2E.mjs";
8
- import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-CC5bUer7.mjs";
6
+ import { i as startIosDeviceConsole, r as parseDeviceConsoleLine } from "./ios-device-D3pzTKQE.mjs";
7
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-CGPart6T.mjs";
8
+ import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-BW8i_YxU.mjs";
9
9
  import { existsSync } from "node:fs";
10
10
  import { isAbsolute, join, resolve } from "node:path";
11
11
  import { fileURLToPath } from "node:url";
@@ -1,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
2
  import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
3
3
  import { homedir } from "os";
4
4
  import { dirname, isAbsolute, join, normalize } from "path";
@@ -1,6 +1,6 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
2
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
3
- import { f as startBuildHeartbeat, h as bundlerPin, r as HEARTBEAT_INTERVAL_MS } from "./xcode-CDB6fytw.mjs";
3
+ import { f as startBuildHeartbeat, h as bundlerPin, r as HEARTBEAT_INTERVAL_MS } from "./xcode-DeKCribl.mjs";
4
4
  import { existsSync, readFileSync } from "node:fs";
5
5
  import { dirname, join, relative, resolve, sep } from "node:path";
6
6
  import { homedir } from "node:os";
@@ -1,15 +1,78 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { y as ensureWorkspaceStorage } from "./state-IYEY-zi8.mjs";
3
- import { C as removeTemporaryEntry, S as makeTemporaryDirectory } from "./worktree-Dx3ZC5lS.mjs";
4
- import { i as detectIsExpo, o as isPackageResolvable } from "./project-COj6nzzh.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { y as ensureWorkspaceStorage } from "./state-CZ-ER-8d.mjs";
3
+ import { C as removeTemporaryEntry, S as makeTemporaryDirectory } from "./worktree-C79xx_kM.mjs";
4
+ import { i as detectIsExpo, o as isPackageResolvable } from "./project-BBTVABUz.mjs";
5
5
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
6
- import { t as NOT_OURS_FOREIGN_CWD } from "./metro-B01H3EuD.mjs";
7
- import { i as LAUNCH_BUNDLING, s as LAUNCH_UNVERIFIED } from "./app-install-oZIQRbdD.mjs";
8
- import { f as startBuildHeartbeat, p as tailLines, r as HEARTBEAT_INTERVAL_MS } from "./xcode-CDB6fytw.mjs";
9
- import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-BEMr_m6p.mjs";
6
+ import { t as NOT_OURS_FOREIGN_CWD } from "./metro-COslRK_F.mjs";
7
+ import { i as LAUNCH_BUNDLING, s as LAUNCH_UNVERIFIED } from "./app-install-NFxUahnH.mjs";
8
+ import { f as startBuildHeartbeat, p as tailLines, r as HEARTBEAT_INTERVAL_MS } from "./xcode-DeKCribl.mjs";
9
+ import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-C3ktAwUG.mjs";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
11
11
  import { basename, join } from "node:path";
12
12
  import chalk from "chalk";
13
+ import { request } from "node:http";
14
+ //#region src/engine/metro-warmup.ts
15
+ const WARMUP_TIMEOUT_MS = 6e4;
16
+ async function requestLocal(url, platform, prefetch) {
17
+ return new Promise((resolve) => {
18
+ const req = request(url, { headers: {
19
+ accept: "application/json",
20
+ "expo-platform": platform,
21
+ ...prefetch ? { "x-stim-metro-warmup": "1" } : {}
22
+ } });
23
+ const timer = setTimeout(() => req.destroy(), WARMUP_TIMEOUT_MS);
24
+ timer.unref();
25
+ req.on("socket", (socket) => socket.unref());
26
+ req.on("error", () => resolve(null));
27
+ req.on("close", () => {
28
+ clearTimeout(timer);
29
+ resolve(null);
30
+ });
31
+ req.on("response", (res) => {
32
+ let body = "";
33
+ res.setEncoding("utf8");
34
+ res.on("data", (chunk) => {
35
+ if (!prefetch) body += chunk;
36
+ });
37
+ res.on("error", () => resolve(null));
38
+ res.on("end", () => resolve(res.statusCode === 200 ? body : null));
39
+ });
40
+ req.end();
41
+ });
42
+ }
43
+ async function warmMetro({ port, platform, isExpo, appId, bundleUrl }) {
44
+ try {
45
+ const origin = `http://127.0.0.1:${port}`;
46
+ if (await requestLocal(new URL("/_stim/metro-warmup", origin), platform, false) !== "ready") return;
47
+ const url = new URL("/index.bundle", origin);
48
+ url.search = new URLSearchParams({
49
+ platform,
50
+ dev: "true",
51
+ lazy: "true",
52
+ minify: "false",
53
+ ...platform === "ios" ? { inlineSourceMap: "false" } : {},
54
+ modulesOnly: "false",
55
+ runModule: "true",
56
+ excludeSource: "true",
57
+ sourcePaths: "url-server",
58
+ ...appId ? { app: appId } : {}
59
+ }).toString();
60
+ if (!bundleUrl && isExpo) {
61
+ const body = await requestLocal(new URL(origin), platform, false);
62
+ if (body === null) return;
63
+ const manifest = JSON.parse(body);
64
+ bundleUrl = manifest.launchAsset?.url ?? manifest.bundleUrl;
65
+ if (typeof bundleUrl !== "string") return;
66
+ }
67
+ if (bundleUrl) {
68
+ const bundle = new URL(bundleUrl, origin);
69
+ url.pathname = bundle.pathname;
70
+ url.search = bundle.search;
71
+ }
72
+ await requestLocal(url, platform, true);
73
+ } catch {}
74
+ }
75
+ //#endregion
13
76
  //#region src/commands/native-runtime.ts
14
77
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
15
78
  const GATE_RETRY_DELAYS_MS = [
@@ -554,4 +617,4 @@ function readJson(file) {
554
617
  }
555
618
  }
556
619
  //#endregion
557
- export { swapJsBundle as a, ensureWorkspaceStorageSafely as c, noMetroMessage as d, noMetroRemedy as f, detectEntryFile as i, gateShouldRetry as l, sleep as m, pickDevClientScheme as n, needsPrebuild as o, resolveMetroWithRetry as p, schemesFromInfoPlist as r, runPrebuild as s, devClientScheme as t, launchOutcomeRecord as u };
620
+ export { swapJsBundle as a, ensureWorkspaceStorageSafely as c, noMetroMessage as d, noMetroRemedy as f, warmMetro as h, detectEntryFile as i, gateShouldRetry as l, sleep as m, pickDevClientScheme as n, needsPrebuild as o, resolveMetroWithRetry as p, schemesFromInfoPlist as r, runPrebuild as s, devClientScheme as t, launchOutcomeRecord as u };
@@ -1,9 +1,9 @@
1
- import { a as findProjectRoot } from "./project-COj6nzzh.mjs";
1
+ import { a as findProjectRoot } from "./project-BBTVABUz.mjs";
2
2
  import { r as clockTime } from "./command-output-8wHMEde0.mjs";
3
- import { f as takeLease, l as releaseWorkspaceLeases, n as fileLeaseIo, o as parseLeaseDuration } from "./device-lease-D-G3SgVe.mjs";
4
- import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-BlHXnYYs.mjs";
5
- import { E as physicalDeviceModel, O as probeEmulatorSerial, _ as listAdbDevices, b as memoizeEmulatorProbe, i as androidPoolNoCandidatesRefusal, j as resolvePhysicalDevice, r as androidPoolCandidates } from "./android-xmyGBNy5.mjs";
6
- import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-CdSm0GDw.mjs";
3
+ import { f as takeLease, l as releaseWorkspaceLeases, n as fileLeaseIo, o as parseLeaseDuration } from "./device-lease-Dpik41RY.mjs";
4
+ import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-B5pEVa3t.mjs";
5
+ import { C as memoizeEmulatorProbe, P as resolvePhysicalDevice, i as androidPoolNoCandidatesRefusal, j as probeEmulatorSerial, k as physicalDeviceModel, r as androidPoolCandidates, y as listAdbDevices } from "./android-K63_0UfF.mjs";
6
+ import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-xNt0Lg6v.mjs";
7
7
  import chalk from "chalk";
8
8
  //#region src/commands/device.ts
9
9
  const DEFAULT_FOR = "5m";
@@ -1,6 +1,6 @@
1
- import { k as withDirLock, u as getConfigDir } from "./config-D7uu8Gbq.mjs";
2
- import { _ as writeWorkspaceState, o as clearWorkspaceStateKeys, p as readWorkspaceState } from "./state-IYEY-zi8.mjs";
3
- import { a as segment } from "./build-lock-vE45ZzJZ.mjs";
1
+ import { k as withDirLock, u as getConfigDir } from "./config-CMtIaTk9.mjs";
2
+ import { _ as writeWorkspaceState, o as clearWorkspaceStateKeys, p as readWorkspaceState } from "./state-CZ-ER-8d.mjs";
3
+ import { a as segment } from "./build-lock-BsVoLDaq.mjs";
4
4
  import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { randomBytes } from "node:crypto";
6
6
  import { join } from "node:path";
@@ -1,6 +1,6 @@
1
1
  import { a as formatElapsed, r as clockTime } from "./command-output-8wHMEde0.mjs";
2
- import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install-oZIQRbdD.mjs";
3
- import { a as parseLease, c as releaseRunLease, d as selectPoolDevice, f as takeLease, n as fileLeaseIo, r as leaseIsExpired, s as raiseLease, t as deviceLeasePath } from "./device-lease-D-G3SgVe.mjs";
2
+ import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install-NFxUahnH.mjs";
3
+ import { a as parseLease, c as releaseRunLease, d as selectPoolDevice, f as takeLease, n as fileLeaseIo, r as leaseIsExpired, s as raiseLease, t as deviceLeasePath } from "./device-lease-Dpik41RY.mjs";
4
4
  //#region src/engine/device-lease-run.ts
5
5
  const LEASE_STEP_FLOOR_MS = 6e4;
6
6
  const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
@@ -36,7 +36,7 @@ function facts(lease) {
36
36
  };
37
37
  }
38
38
  function waitingLine(lease, now) {
39
- return `waiting for ${lease.holder} to release ${describeDevice(lease)}; its lease runs until ${leaseExpiryText(lease.expiresAt, now)}`;
39
+ return `waiting for ${lease.holder} to release ${describeDevice(lease)}; its lease runs until ${leaseExpiryText(lease.expiresAt, now)} -- stim guide lifecycle lease`;
40
40
  }
41
41
  function appIdMatch(ours, theirs) {
42
42
  if (!ours || !theirs) return "unknown";
@@ -1,11 +1,11 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { k as withDirLock, u as getConfigDir } from "./config-D7uu8Gbq.mjs";
3
- import { D as workspaceLogsDir, O as workspaceName, T as workspaceDir, a as clearRemoteSession, c as readMetroTunnel, k as workspaceStateFile, u as readRemoteSession } from "./state-IYEY-zi8.mjs";
4
- import { r as pidExists } from "./metro-B01H3EuD.mjs";
5
- import { R as planMetroReach } from "./settings-BSwrY4FZ.mjs";
6
- import { T as readMetroRecords, a as LAUNCH_ERROR, b as isBundleProof, p as devClientDeepLink, r as INSTALL_ERROR } from "./app-install-oZIQRbdD.mjs";
7
- import { x as sanitizeDeviceLabel } from "./ios-BZxKPuqP.mjs";
8
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-CxOO9-pf.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { k as withDirLock, u as getConfigDir } from "./config-CMtIaTk9.mjs";
3
+ import { D as workspaceLogsDir, O as workspaceName, T as workspaceDir, a as clearRemoteSession, c as readMetroTunnel, k as workspaceStateFile, u as readRemoteSession } from "./state-CZ-ER-8d.mjs";
4
+ import { r as pidExists } from "./metro-COslRK_F.mjs";
5
+ import { z as planMetroReach } from "./settings-DwU1_U_q.mjs";
6
+ import { T as readMetroRecords, a as LAUNCH_ERROR, b as isBundleProof, p as devClientDeepLink, r as INSTALL_ERROR } from "./app-install-NFxUahnH.mjs";
7
+ import { S as sanitizeDeviceLabel } from "./ios-D1h1Di39.mjs";
8
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BKfdys1q.mjs";
9
9
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
10
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
11
11
  import { homedir } from "node:os";
@@ -1,17 +1,17 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { g as loadConfig, l as getConcurrencyLimits, o as configCorruptRepair } from "./config-D7uu8Gbq.mjs";
3
- import { b as sharedBuildCache, w as workspaceDerivedData } from "./state-IYEY-zi8.mjs";
4
- import { S as makeTemporaryDirectory, a as dirtyFingerprintFiles, f as listWorktrees, g as repoRoot, s as gitCommonDir, w as temporaryRoot, x as filesystemDevice } from "./worktree-Dx3ZC5lS.mjs";
5
- import { i as detectIsExpo, t as appProjectProblem } from "./project-COj6nzzh.mjs";
6
- import { d as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DOi5-zLj.mjs";
7
- import { B as compilerCacheFallbackMessage, C as projectOptimizations, D as remoteIosSetting, F as unknownSettingKeys, H as resolveOptimizations, M as settingShapeErrors, N as settingsLayers, T as remoteAndroidSetting, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, j as settingOrigin, k as resolveSettings, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, y as mergeSettingsLayers } from "./settings-BSwrY4FZ.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { g as loadConfig, l as getConcurrencyLimits, o as configCorruptRepair } from "./config-CMtIaTk9.mjs";
3
+ import { b as sharedBuildCache, w as workspaceDerivedData } from "./state-CZ-ER-8d.mjs";
4
+ import { S as makeTemporaryDirectory, a as dirtyFingerprintFiles, f as listWorktrees, g as repoRoot, s as gitCommonDir, w as temporaryRoot, x as filesystemDevice } from "./worktree-C79xx_kM.mjs";
5
+ import { i as detectIsExpo, t as appProjectProblem } from "./project-BBTVABUz.mjs";
6
+ import { d as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
7
+ import { A as resolveSettings, E as remoteAndroidSetting, I as unknownSettingKeys, M as settingOrigin, N as settingShapeErrors, O as remoteIosSetting, P as settingsLayers, U as resolveOptimizations, V as compilerCacheFallbackMessage, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, w as projectOptimizations, y as mergeSettingsLayers } from "./settings-DwU1_U_q.mjs";
8
8
  import { d as quotedPath, u as plural } from "./command-output-8wHMEde0.mjs";
9
- import { l as listAllIosSims } from "./ios-BZxKPuqP.mjs";
10
- import { m as fingerprintProject, r as listBuildLocks, u as diffFingerprintSources } from "./build-lock-vE45ZzJZ.mjs";
11
- import { n as listBuildSlots } from "./build-slots-CgacA9zQ.mjs";
12
- import { _ as listAdbDevices } from "./android-xmyGBNy5.mjs";
13
- import { T as simslimIsOnPath, a as ccacheEnabled, g as podInstallCommand, x as liveOwnedDeviceCount } from "./xcode-CDB6fytw.mjs";
14
- import { d as projectCmakeLauncher, i as apkOutputsDir, r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-DGlTStWu.mjs";
9
+ import { E as readHostMemoryPressure, T as hostMemoryPressureAdvice, u as listAllIosSims } from "./ios-D1h1Di39.mjs";
10
+ import { m as fingerprintProject, r as listBuildLocks, u as diffFingerprintSources } from "./build-lock-BsVoLDaq.mjs";
11
+ import { n as listBuildSlots } from "./build-slots-D0b6sJyo.mjs";
12
+ import { y as listAdbDevices } from "./android-K63_0UfF.mjs";
13
+ import { E as simslimIsOnPath, S as liveOwnedDeviceCount, a as ccacheEnabled, g as podInstallCommand } from "./xcode-DeKCribl.mjs";
14
+ import { d as projectCmakeLauncher, i as apkOutputsDir, r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-D6HPZ6UQ.mjs";
15
15
  import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
16
16
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
17
17
  import { existsSync as existsSync$1, lstatSync as lstatSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1 } from "fs";
@@ -699,15 +699,6 @@ function checkMainCheckout(projectRoot, { npmTreeValid, brokenPods = void 0, ups
699
699
  if (linkedWorktrees === void 0 ? hasLinkedWorktree(projectRoot) : linkedWorktrees) findings.push(...seedFindings(mainRoot, upstream === void 0 ? locallyKnownUpstream(mainRoot) : upstream));
700
700
  return findings;
701
701
  }
702
- function checkDevClient(pkg, isExpo = true) {
703
- const deps = {
704
- ...pkg?.dependencies,
705
- ...pkg?.devDependencies
706
- };
707
- if (deps["expo-dev-client"]) return null;
708
- if (!isExpo || !deps.expo) return null;
709
- return finding("cost", "expo-dev-client is not installed", "A Metro port reserved by Stim cannot reach the app without it: the port travels in the dev-client deep link `stim ios` opens, and without the dev client nothing handles that URL. The app falls back to port 8081 and shows \"No script URL provided\".", "npx expo install expo-dev-client, then rebuild with `stim ios` / `stim android`. It is a NATIVE dependency: an app already on the device will not pick it up, and the first build after installing it is a cache miss by design because the native fingerprint moved. Do not solve this by compiling the port in (RCT_METRO_PORT, or the dev client defaultLaunchURL) -- the build cache does not key on the port, so a binary built for one workspace would silently talk to another workspace bundler.");
710
- }
711
702
  function checkMetroCache(metroConfigSource) {
712
703
  if (metroConfigSource == null) return null;
713
704
  const lines = String(metroConfigSource).split("\n");
@@ -811,10 +802,11 @@ function checkRemoteDevice({ configured = null, daemonInEnv = false, agentDevice
811
802
  }
812
803
  function checkSimSlim({ configured = false, profileError = null, onPath = false } = {}) {
813
804
  if (profileError) return finding("cost", "The SimSlim profile is invalid", profileError, "Set ios.simslimProfile to a readable JSON profile inside the repository.");
814
- if (!configured || onPath) return null;
805
+ if (!configured) return finding("note", "SimSlim is recommended for parallel iOS simulator work", "A reviewed profile can reduce background simulator services and memory use. It is optional: disabling services can affect tests that depend on them, and installing the binary alone does not apply a profile.", "Run `stim guide lifecycle simslim` to install SimSlim and configure ios.simslimProfile. Stim does not enable a profile through doctor --fix.");
806
+ if (onPath) return null;
815
807
  return finding("cost", "A SimSlim profile is configured, but SimSlim is not installed", "`stim ios` needs the `simslim` command to apply the profile to its owned simulator.", "brew install mobai-app/tap/simslim");
816
808
  }
817
- function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null, easAuth = checkEasAuth$1, concurrency = getConcurrencyLimits, liveDevices = null, activeBuilds = null, remoteEnv = process.env, lookupAgentDevice = null, lookupEasCli = null, lookupSimSlim = null, lookupCcache = null, platform } = {}) {
809
+ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null, easAuth = checkEasAuth$1, concurrency = getConcurrencyLimits, liveDevices = null, activeBuilds = null, remoteEnv = process.env, lookupAgentDevice = null, lookupEasCli = null, lookupSimSlim = null, memoryPressure = readHostMemoryPressure, lookupCcache = null, platform } = {}) {
818
810
  const read = (rel) => {
819
811
  const p = join$1(projectRoot, rel);
820
812
  if (!existsSync$1(p)) return null;
@@ -886,7 +878,7 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
886
878
  } catch (error) {
887
879
  simslimProfileError = String(error?.message || error);
888
880
  }
889
- const simslimFinding = platform === "android" ? null : checkSimSlim({
881
+ const simslimFinding = platform === "android" || !simslimProfile && !simslimProfileError && remoteIosSetting(projectSettings) ? null : checkSimSlim({
890
882
  configured: Boolean(simslimProfile),
891
883
  profileError: simslimProfileError,
892
884
  onPath: simslimProfile ? lookupSimSlim ? lookupSimSlim() : simslimIsOnPath() : false
@@ -901,12 +893,12 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
901
893
  agentDeviceOnPath,
902
894
  easCliResolvable
903
895
  })).filter((remoteFinding) => remoteFinding !== null);
896
+ const memoryAdvice = platform !== "android" && !remoteIosSetting(projectSettings) ? hostMemoryPressureAdvice(memoryPressure()) : null;
904
897
  return [
905
898
  checkAppProject(projectRoot),
906
899
  ...checkMainCheckout(projectRoot, { platform }),
907
900
  ...platform === "android" ? [] : inspectIosDebugArchitectures(mainCheckoutProjectRoot(projectRoot)),
908
901
  ...checkStorageLayout(projectRoot, { platform }),
909
- checkDevClient(pkg, isExpo),
910
902
  optimizations?.metroSharedCache ? checkMetroCache(metroConfig) : null,
911
903
  platform === "android" || !optimizations?.ios.compilationCache ? null : checkCompilationCache(podfile, xcodeMajor),
912
904
  platform === "android" || !optimizations?.ios.compilationCache ? null : checkCcacheConflict(podfile, podfileProperties),
@@ -914,6 +906,7 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
914
906
  remoteBuildCache ? checkBuildCacheProvider(appConfig, sdkMajor, isExpo, dynamicConfig) : null,
915
907
  easFinding,
916
908
  concurrencyFinding,
909
+ memoryAdvice ? finding("cost", "Host memory pressure can stall the iOS simulator", memoryAdvice, "Free host memory, then retry. Run `stim guide lifecycle simslim` for the optional memory reduction setup.") : null,
917
910
  simslimFinding,
918
911
  ...remoteFindings,
919
912
  ...settingShapeFindings,
@@ -1,9 +1,9 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { g as repoRoot } from "./worktree-Dx3ZC5lS.mjs";
3
- import { a as findProjectRoot } from "./project-COj6nzzh.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { g as repoRoot } from "./worktree-C79xx_kM.mjs";
3
+ import { a as findProjectRoot } from "./project-BBTVABUz.mjs";
4
4
  import { l as phaseLine } from "./command-output-8wHMEde0.mjs";
5
- import { s as detectXcodeMajor } from "./xcode-CDB6fytw.mjs";
6
- import { c as repairCxxLauncherState, n as detectFingerprintParity, r as detectLinkedLibraryGitMetadata, s as runDoctor } from "./doctor-DlVxTtMq.mjs";
5
+ import { s as detectXcodeMajor } from "./xcode-DeKCribl.mjs";
6
+ import { c as repairCxxLauncherState, n as detectFingerprintParity, r as detectLinkedLibraryGitMetadata, s as runDoctor } from "./doctor-CqPeMsSm.mjs";
7
7
  import { accessSync, constants, realpathSync, statSync } from "node:fs";
8
8
  import { InvalidArgumentError } from "commander";
9
9
  import { delimiter, join, resolve } from "node:path";
@@ -209,7 +209,7 @@ function sandboxFinding(settingsRoot, { env = process.env, home = homedir(), sti
209
209
  level: "cost",
210
210
  title,
211
211
  detail: `${symptoms} Missing: ${missing.join(", ")}.`,
212
- fix: `Run \`stim doctor --fix\` to add them to ${paths[0]}, or add them by hand. See \`stim guide errors sandbox\`.`
212
+ fix: `Run \`stim doctor --fix\` to write sandbox.filesystem.allowWrite, sandbox.network.allowMachLookup, and sandbox.network.allowLocalBinding into ${paths[0]}, merged with what is there, or add the missing keys by hand. See \`stim guide errors sandbox\`.`
213
213
  };
214
214
  }
215
215
  //#endregion
@@ -395,13 +395,13 @@ function doctorSuccessLines(platform, stim) {
395
395
  ];
396
396
  if (platform !== "android") {
397
397
  lines.push("", "iOS");
398
- lines.push(phaseLine("setup", "CocoaPods, warm state, dev client, effective Debug simulator architectures"));
398
+ lines.push(phaseLine("setup", "CocoaPods, warm state, effective Debug simulator architectures"));
399
399
  lines.push(phaseLine("caches", "Metro, Xcode compilation, ccache, build provider"));
400
400
  lines.push(phaseLine("devices", "remote device, SimSlim profile"));
401
401
  }
402
402
  if (platform !== "ios") {
403
403
  lines.push("", "Android");
404
- lines.push(phaseLine("setup", "warm state, dev client"));
404
+ lines.push(phaseLine("setup", "warm state"));
405
405
  lines.push(phaseLine("caches", "Metro, Gradle, ccache, build provider"));
406
406
  lines.push(phaseLine("devices", "remote device"));
407
407
  }
@@ -464,7 +464,7 @@ function applySandboxFix(root, env = process.env) {
464
464
  console.error(chalk.dim("Added writes to Stim's state directory, the simulator XPC service, and local port binding. Claude Code reads project settings from the directory a session starts in, so this file only counts for sessions rooted there. Restart the session for it to take effect."));
465
465
  }
466
466
  function doctorCommand(program, version, inspectVersions = inspectStimVersions) {
467
- program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. Read-only unless --fix is passed; --platform filters native findings.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance and stale Android .cxx configurations in this checkout. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
467
+ program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. Read-only unless --fix is passed; --platform filters native findings.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance when the report names it, and stale Android .cxx configurations in this checkout. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
468
468
  const root = findProjectRoot(process.cwd());
469
469
  if (!root) {
470
470
  console.error(chalk.red("Not in a React Native project (no package.json found)."));
@@ -472,7 +472,7 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions)
472
472
  return;
473
473
  }
474
474
  if (opts.fix) {
475
- if (detectHarness() !== "codex" || sandboxFinding(repoRoot(root) ?? root)) applySandboxFix(root);
475
+ if (sandboxFinding(repoRoot(root) ?? root)) applySandboxFix(root);
476
476
  if (opts.platform !== "ios") try {
477
477
  const repair = repairCxxLauncherState(root);
478
478
  for (const path of repair.removed) console.error(phaseLine("cache", `removed ${path}; next build reconfigures`));
@@ -1,12 +1,12 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { f as getProject, k as withDirLock } from "./config-D7uu8Gbq.mjs";
3
- import { f as readWorkspaceLaunches, p as readWorkspaceState } from "./state-IYEY-zi8.mjs";
4
- import { n as deviceConsoleLevel } from "./ios-device-CYbuRNXR.mjs";
5
- import { i as resolveProjectMetro } from "./metro-B01H3EuD.mjs";
6
- import { n as parseLogcatLine, t as androidClockOffset } from "./android-CC5bUer7.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { f as getProject, k as withDirLock } from "./config-CMtIaTk9.mjs";
3
+ import { f as readWorkspaceLaunches, p as readWorkspaceState } from "./state-CZ-ER-8d.mjs";
4
+ import { n as deviceConsoleLevel } from "./ios-device-D3pzTKQE.mjs";
5
+ import { i as resolveProjectMetro } from "./metro-COslRK_F.mjs";
6
+ import { n as parseLogcatLine, t as androidClockOffset } from "./android-BW8i_YxU.mjs";
7
7
  import { _ as launchErrorPreview } from "./command-output-8wHMEde0.mjs";
8
- import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-D-G3SgVe.mjs";
9
- import { n as androidHome } from "./android-xmyGBNy5.mjs";
8
+ import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-Dpik41RY.mjs";
9
+ import { n as androidHome } from "./android-K63_0UfF.mjs";
10
10
  import { c as readLogRecords, t as attachExpoErrorContext } from "./logs-query-oqn47Ffx.mjs";
11
11
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
12
  import { createHash, randomUUID } from "node:crypto";
@@ -2,7 +2,7 @@ import { execFileSync, execSync, spawn } from "child_process";
2
2
  //#region src/exec.ts
3
3
  const MAX_BUFFER = 67108864;
4
4
  let active = {
5
- run(cmd, { timeoutMs, cwd } = {}) {
5
+ run(cmd, { timeoutMs, killSignal, cwd } = {}) {
6
6
  const opts = {
7
7
  encoding: "utf-8",
8
8
  stdio: [
@@ -13,10 +13,11 @@ let active = {
13
13
  maxBuffer: MAX_BUFFER
14
14
  };
15
15
  if (timeoutMs) opts.timeout = timeoutMs;
16
+ if (killSignal) opts.killSignal = killSignal;
16
17
  if (cwd) opts.cwd = cwd;
17
18
  return String(execSync(cmd, opts)).trim();
18
19
  },
19
- runFile(file, args = [], { timeoutMs, cwd, env, omitEnv } = {}) {
20
+ runFile(file, args = [], { timeoutMs, killSignal, cwd, env, omitEnv } = {}) {
20
21
  const opts = {
21
22
  encoding: "utf-8",
22
23
  stdio: [
@@ -27,6 +28,7 @@ let active = {
27
28
  maxBuffer: MAX_BUFFER
28
29
  };
29
30
  if (timeoutMs) opts.timeout = timeoutMs;
31
+ if (killSignal) opts.killSignal = killSignal;
30
32
  if (cwd) opts.cwd = cwd;
31
33
  if (env || omitEnv?.length) {
32
34
  const childEnv = {
@@ -1,20 +1,20 @@
1
- import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
2
- import { A as directorySize, M as isOnMountedVolume, N as listMountedVolumes, P as volumeRootFor, g as loadConfig, i as clearDevice, j as formatBytes, u as getConfigDir, v as removeProject } from "./config-D7uu8Gbq.mjs";
3
- import { i as registeredCaches } from "./cache-manifest-oeH18ERr.mjs";
4
- import { T as workspaceDir, k as workspaceStateFile } from "./state-IYEY-zi8.mjs";
5
- import { g as repoRoot, s as gitCommonDir } from "./worktree-Dx3ZC5lS.mjs";
6
- import { a as findProjectRoot, i as detectIsExpo } from "./project-COj6nzzh.mjs";
7
- import { S as readParked, _ as teardownParkedIosSim, b as dropParked, d as resolveEasCliBin, g as teardownParkedAvd, h as teardownOwnedIosSim, m as teardownOwnedAvd, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DOi5-zLj.mjs";
8
- import { M as settingShapeErrors, a as SETTING_SHAPE_REMEDY, k as resolveSettings } from "./settings-BSwrY4FZ.mjs";
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { A as directorySize, M as isOnMountedVolume, N as listMountedVolumes, P as volumeRootFor, g as loadConfig, i as clearDevice, j as formatBytes, u as getConfigDir, v as removeProject } from "./config-CMtIaTk9.mjs";
3
+ import { i as registeredCaches } from "./cache-manifest-Cu4_Znw9.mjs";
4
+ import { T as workspaceDir, k as workspaceStateFile } from "./state-CZ-ER-8d.mjs";
5
+ import { g as repoRoot, s as gitCommonDir } from "./worktree-C79xx_kM.mjs";
6
+ import { a as findProjectRoot, i as detectIsExpo } from "./project-BBTVABUz.mjs";
7
+ import { S as readParked, _ as teardownParkedIosSim, b as dropParked, d as resolveEasCliBin, g as teardownParkedAvd, h as teardownOwnedIosSim, m as teardownOwnedAvd, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
8
+ import { A as resolveSettings, N as settingShapeErrors, a as SETTING_SHAPE_REMEDY } from "./settings-DwU1_U_q.mjs";
9
9
  import { m as shortUdid, o as formatLongDuration, u as plural } from "./command-output-8wHMEde0.mjs";
10
- import { h as parseRuntimeVersion, l as listAllIosSims, u as listIosDeviceTypes } from "./ios-BZxKPuqP.mjs";
11
- import { r as listBuildLocks } from "./build-lock-vE45ZzJZ.mjs";
12
- import { d as readClaimSet, o as clearFreeClaimSet } from "./ownership-claim-CeJLEpjD.mjs";
13
- import { i as listLeaseFiles, r as leaseIsExpired, u as removeExpiredLease } from "./device-lease-D-G3SgVe.mjs";
14
- import { n as listBuildSlots } from "./build-slots-CgacA9zQ.mjs";
15
- import { S as ownedAvdDirectory, v as listAvds } from "./android-xmyGBNy5.mjs";
16
- import { C as verifyStoppedSession, S as stopSessionArgs, _ as inspectSessionForTeardown, d as withEasProjectLock, f as easMachineStateRoot, g as getSessionArgs, h as findOrphanedOwnedSessions, m as removeEasSessionClaim, p as readEasSessionLedger, u as withRemoteSessionLock, v as isDefinitiveMissingSessionError, x as parseSessionListPage, y as listOwnedSessionsArgs } from "./device-remote-CCgkG82J.mjs";
17
- import { n as reclaimProject, t as describeDereferenced } from "./reclaim-BPvN2HlP.mjs";
10
+ import { d as listIosDeviceTypes, g as parseRuntimeVersion, u as listAllIosSims } from "./ios-D1h1Di39.mjs";
11
+ import { r as listBuildLocks } from "./build-lock-BsVoLDaq.mjs";
12
+ import { d as readClaimSet, o as clearFreeClaimSet } from "./ownership-claim-7zRxxTfZ.mjs";
13
+ import { i as listLeaseFiles, r as leaseIsExpired, u as removeExpiredLease } from "./device-lease-Dpik41RY.mjs";
14
+ import { n as listBuildSlots } from "./build-slots-D0b6sJyo.mjs";
15
+ import { S as listOrphanedAvdDirectories, T as ownedAvdDirectory, b as listAvds } from "./android-K63_0UfF.mjs";
16
+ import { C as verifyStoppedSession, S as stopSessionArgs, _ as inspectSessionForTeardown, d as withEasProjectLock, f as easMachineStateRoot, g as getSessionArgs, h as findOrphanedOwnedSessions, m as removeEasSessionClaim, p as readEasSessionLedger, u as withRemoteSessionLock, v as isDefinitiveMissingSessionError, x as parseSessionListPage, y as listOwnedSessionsArgs } from "./device-remote-E81KAdXf.mjs";
17
+ import { n as reclaimProject, t as describeDereferenced } from "./reclaim-C5Jmuahx.mjs";
18
18
  import { InvalidArgumentError } from "commander";
19
19
  import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "fs";
20
20
  import { homedir, tmpdir } from "os";
@@ -532,7 +532,7 @@ function describeUnverifiableDevices(simNames = [], avdNames = [], { reason = "n
532
532
  function withAndroidAvdSizes(devices, { avdDirectory = ownedAvdDirectory, size = directorySize } = {}) {
533
533
  return devices.map((device) => {
534
534
  if (device.kind !== "android") return device;
535
- const dir = avdDirectory(device.id);
535
+ const dir = device.orphanedDirectory?.directory ?? avdDirectory(device.id);
536
536
  if (!dir) return device;
537
537
  try {
538
538
  const bytes = size(dir, { timeoutMs: AVD_SIZE_TIMEOUT_MS });
@@ -648,8 +648,8 @@ function deleteParkedSims(parkedSims, deps = {}) {
648
648
  if (emptied) console.log(chalk.dim(` emptied ${plural(emptied, "parked simulator")} from the pool`));
649
649
  return failures;
650
650
  }
651
- function deviceSweepIsScoped(unsafeAllowScopedDeviceSweep) {
652
- return Boolean(process.env.STIM_HOME) && !unsafeAllowScopedDeviceSweep;
651
+ function deviceSweepIsScoped() {
652
+ return Boolean(process.env.STIM_HOME);
653
653
  }
654
654
  function collectDeviceLeases(now) {
655
655
  const expired = [];
@@ -685,7 +685,11 @@ function deleteProjectDevices(orphanedDevices, staleDevices, staleDeviceRecords)
685
685
  const r = d.kind === "ios" ? teardownOwnedIosSim(d.id, {
686
686
  del: true,
687
687
  label: d.name
688
- }) : teardownOwnedAvd(d.name, { del: true });
688
+ }) : teardownOwnedAvd(d.name, {
689
+ del: true,
690
+ ..."project" in d ? { owner: { projectPath: d.project } } : {},
691
+ ..."orphanedDirectory" in d ? { orphanedDirectory: d.orphanedDirectory } : {}
692
+ });
689
693
  const what = d.kind === "ios" ? `ios sim ${d.name} (${d.id})` : `android avd ${d.name}`;
690
694
  if (r.status === "torn-down") console.log(chalk.green(`Deleted ${what}`));
691
695
  else if (r.status === "missing") console.log(chalk.dim(`${what} is already gone; nothing to delete.`));
@@ -1294,7 +1298,7 @@ function projectLastTouched(path) {
1294
1298
  return NaN;
1295
1299
  }
1296
1300
  }
1297
- async function collectGcReport({ olderThan = null, cache = null, now = Date.now(), lastTouched = projectLastTouched, unsafeAllowScopedDeviceSweep = false } = {}, deps = {}) {
1301
+ async function collectGcReport({ olderThan = null, cache = null, now = Date.now(), lastTouched = projectLastTouched } = {}, deps = {}) {
1298
1302
  const scope = typeof cache === "string" && cache.trim() ? cache : null;
1299
1303
  const all = scope !== null && olderThan === null;
1300
1304
  const caches = planCacheEmptying(sizeCaches(selectCaches(discoverCaches({ declared: declaredCachePaths() }), scope)), all);
@@ -1374,7 +1378,7 @@ async function collectGcReport({ olderThan = null, cache = null, now = Date.now(
1374
1378
  let orphanedDevices = [];
1375
1379
  let staleDevices = [];
1376
1380
  let staleDeviceRecords = [];
1377
- const unsweepableReason = cfg === null ? "no Stim config found" : deviceSweepIsScoped(unsafeAllowScopedDeviceSweep) ? "STIM_HOME scopes this config, but simulators and AVDs are machine-global" : null;
1381
+ const unsweepableReason = cfg === null ? "no Stim config found" : deviceSweepIsScoped() ? "STIM_HOME scopes this config, but simulators and AVDs are machine-global" : null;
1378
1382
  if (unsweepableReason) {
1379
1383
  let simNames = [];
1380
1384
  let avdNames = [];
@@ -1402,6 +1406,14 @@ async function collectGcReport({ olderThan = null, cache = null, now = Date.now(
1402
1406
  avdsChecked = false;
1403
1407
  deviceSweepNotices.push(`android device sweep skipped: emulator tooling did not answer within ${DEVICE_LIST_TIMEOUT_MS / 1e3}s`);
1404
1408
  }
1409
+ let orphanedAvdDirectories = [];
1410
+ if (avdsChecked) try {
1411
+ orphanedAvdDirectories = listOrphanedAvdDirectories();
1412
+ } catch (error) {
1413
+ avdsChecked = false;
1414
+ deviceSweepNotices.push(`android data sweep skipped: ${error.message}`);
1415
+ }
1416
+ avds = [.../* @__PURE__ */ new Set([...avds, ...orphanedAvdDirectories.map((entry) => entry.name)])];
1405
1417
  const isMounted = (path) => isOnMountedVolume(path, mountedVolumes);
1406
1418
  orphanedDevices = withAndroidAvdSizes(findOrphanedDevices({
1407
1419
  sims,
@@ -1409,7 +1421,10 @@ async function collectGcReport({ olderThan = null, cache = null, now = Date.now(
1409
1421
  config: cfg,
1410
1422
  isMounted,
1411
1423
  deadProjects
1412
- }).orphaned, {
1424
+ }).orphaned.flatMap((device) => {
1425
+ const directories = device.kind === "android" ? orphanedAvdDirectories.filter((entry) => entry.name === device.name) : [];
1426
+ return directories.length ? directories.map((orphanedDirectory) => Object.assign({}, device, { orphanedDirectory })) : [device];
1427
+ }), {
1413
1428
  avdDirectory: deps.avdDirectory ?? ownedAvdDirectory,
1414
1429
  size: deps.directorySize ?? directorySize
1415
1430
  });
@@ -1546,8 +1561,7 @@ async function runGcCore(opts, deps) {
1546
1561
  const cache = typeof opts.cache === "string" && opts.cache.trim() ? opts.cache : null;
1547
1562
  const report = await collectGcReport({
1548
1563
  olderThan,
1549
- cache,
1550
- unsafeAllowScopedDeviceSweep: opts.unsafeAllowScopedDeviceSweep
1564
+ cache
1551
1565
  }, deps);
1552
1566
  if (cache && report.caches.length === 0) {
1553
1567
  const names = [...new Set(discoverCaches({ declared: declaredCachePaths() }).map((c) => c.name))];