stim 1.6.0 → 1.7.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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/{android-BkYmndPp.mjs → android-DWssqHQ8.mjs} +165 -661
  3. package/dist/{android-DLJB8ljN.mjs → android-Da-G_o3n.mjs} +646 -548
  4. package/dist/{android-BW8i_YxU.mjs → android-DeYdjjBP.mjs} +6 -2
  5. package/dist/{android-cas-CrzI_Zha.mjs → android-cas-SWIjzeuL.mjs} +54 -18
  6. package/dist/android-cas-compiler.mjs +1 -1
  7. package/dist/{app-install--PAocWvq.mjs → app-install-DJg7bVv-.mjs} +36 -10
  8. package/dist/build-lock-CgtsB6TV.mjs +604 -0
  9. package/dist/{build-slots-CuPszJDu.mjs → build-slots-C-oAHRT1.mjs} +2 -2
  10. package/dist/{cache-manifest-uoOKhgUD.mjs → cache-manifest-CYJi8-Hx.mjs} +2 -2
  11. package/dist/cache-manifest.d.mts +1 -1
  12. package/dist/cache-manifest.mjs +1 -1
  13. package/dist/cli.mjs +14 -14
  14. package/dist/collector-run.d.mts +2 -0
  15. package/dist/collector-run.mjs +7 -7
  16. package/dist/{command-output-BuIb_ZOI.mjs → command-output-B3ycpsYv.mjs} +2 -2
  17. package/dist/{config-DMP7L7H6.mjs → config-B7iyKWkL.mjs} +56 -16
  18. package/dist/{dependency-state-CTL8A9p3.mjs → dependency-state-D0M7oKA7.mjs} +2 -2
  19. package/dist/{deps-C1zGnr61.mjs → deps-oCXVNEqQ.mjs} +6 -6
  20. package/dist/detached-entry-Bpo6ZY_I.mjs +65 -0
  21. package/dist/{dev-client-BaTXAAnC.mjs → dev-client-DDUkWgJL.mjs} +12 -12
  22. package/dist/{device-xoQxw8hR.mjs → device-CBSaC6BU.mjs} +7 -7
  23. package/dist/{device-XY_5eGdN.mjs → device-CLeDp-KH.mjs} +17 -15
  24. package/dist/{device-lease-DBW-IL4p.mjs → device-lease-Ffz_M5t0.mjs} +3 -3
  25. package/dist/{device-pool-C0s_83Og.mjs → device-pool-DNSHL5z8.mjs} +4 -4
  26. package/dist/{device-remote-D9wN3CdE.mjs → device-remote-BprxZp-m.mjs} +11 -11
  27. package/dist/{doctor-BRO8UKlK.mjs → doctor-CTAx9gMu.mjs} +90 -46
  28. package/dist/{error-diagnostics-B5STzxqN.mjs → error-diagnostics-D1Kaf-eT.mjs} +23 -17
  29. package/dist/{exec-CyylIdq9.mjs → exec-B29XNuhP.mjs} +14 -2
  30. package/dist/{gc-C-6grAQI.mjs → gc-CX0KRfLG.mjs} +17 -16
  31. package/dist/{guide-CYtd7xbA.mjs → guide-CPmAG9me.mjs} +38 -15
  32. package/dist/{guide-status-BF6RsJJp.mjs → guide-status-Craq9z0t.mjs} +3 -3
  33. package/dist/{ios-Ccm6c8Hj.mjs → ios-BRXYSxSc.mjs} +34 -37
  34. package/dist/{ios-device-DJOi9FR5.mjs → ios-device-CDbvn5H2.mjs} +2 -2
  35. package/dist/{ios-device-D3pzTKQE.mjs → ios-device-CFXA46ez.mjs} +1 -1
  36. package/dist/{ios-Deh5js5V.mjs → ios-lEJ5pKsq.mjs} +3 -3
  37. package/dist/{logs-D4Poojxy.mjs → logs-CakdBTtm.mjs} +6 -6
  38. package/dist/{logs-query-Cdp5aaCH.mjs → logs-query-BGL-Pl12.mjs} +1 -1
  39. package/dist/metro-C7bcJ0uo.mjs +233 -0
  40. package/dist/{named-ports-DH9SXd0f.mjs → named-ports-DzMOlmaX.mjs} +57 -42
  41. package/dist/{ownership-CD_XnpDu.mjs → ownership-Cp52QAK1.mjs} +3 -3
  42. package/dist/{ownership-CVY9cqCr.mjs → ownership-D5vkdm8H.mjs} +13 -13
  43. package/dist/{ports-A6uTJSPj.mjs → ports-BIbJaKNW.mjs} +3 -3
  44. package/dist/{process-output-C7IlIzd7.mjs → process-output-Dl5uKE03.mjs} +1 -1
  45. package/dist/{project-B_SDt4ip.mjs → project-DDZWf_16.mjs} +3 -3
  46. package/dist/{reclaim-WXTbXPX4.mjs → reclaim-D614jI6_.mjs} +11 -11
  47. package/dist/{reload-xlQvHKfN.mjs → reload-ChW46VDb.mjs} +9 -9
  48. package/dist/{server-bare-CCLb90FS.mjs → server-bare-BQkyxa_b.mjs} +1 -1
  49. package/dist/{server-expo-CX-zkgWl.mjs → server-expo-BVAA1OqJ.mjs} +23 -11
  50. package/dist/server-expo-YDDG3eP7.mjs +2 -0
  51. package/dist/{settings-CGHTt5vb.mjs → settings-BXXorVM2.mjs} +3 -3
  52. package/dist/{slot-launch-BYjnljAs.mjs → slot-launch-DbLvyrup.mjs} +4 -4
  53. package/dist/{start-DHYAyGzm.mjs → start-TTVILlUi.mjs} +111 -38
  54. package/dist/{state-CnWzvCWP.mjs → state-DZobzxLW.mjs} +2 -2
  55. package/dist/{stats-Fo9ACIv7.mjs → stats-BYcZ6n1h.mjs} +1 -1
  56. package/dist/{stats-DHrO0frH.mjs → stats-CLg5RuDS.mjs} +4 -4
  57. package/dist/{status-QeLZb8SM.mjs → status-DUNy_HZs.mjs} +14 -15
  58. package/dist/{stop-CHTaw65F.mjs → stop-CnUpnFT5.mjs} +2 -2
  59. package/dist/{stop-DsdOx9Hj.mjs → stop-ZrfODZ51.mjs} +13 -13
  60. package/dist/supervisor-run.mjs +7 -5
  61. package/dist/{teardown-sm1FwF6V.mjs → teardown-5J5UXz2P.mjs} +14 -17
  62. package/dist/{workspace-process-lock-Bz19_R9R.mjs → workspace-process-lock-BYfZz_S-.mjs} +1 -1
  63. package/dist/{workspace-state-WVwWw_hB.mjs → workspace-state-BT5E3SA2.mjs} +3 -3
  64. package/dist/{worktree-CCNPg_f0.mjs → worktree-BfE4lzHK.mjs} +21 -16
  65. package/dist/{worktree-DJnBbQZ9.mjs → worktree-FG_ZKKdb.mjs} +13 -9
  66. package/dist/{xcode-DUF7jrXj.mjs → xcode-B6YaWeg0.mjs} +8 -8
  67. package/package.json +12 -8
  68. package/shim/android-optimizations.gradle +6 -0
  69. package/dist/metro-ato6ef3J.mjs +0 -99
  70. package/dist/ports-BZprTJRa.mjs +0 -90
  71. package/dist/server-expo-CjeTJ273.mjs +0 -2
@@ -1,11 +1,11 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { P as deviceSlotKey, w as process_identity_exports, z as validateDeviceSlot } from "./config-DMP7L7H6.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { B as validateDeviceSlot, F as deviceSlotKey, w as process_identity_exports } from "./config-B7iyKWkL.mjs";
3
3
  import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
4
- import { _ as workspaceLogsDir } from "./workspace-state-WVwWw_hB.mjs";
5
- import { t as createLineReader } from "./process-output-C7IlIzd7.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-CD_XnpDu.mjs";
8
- import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-BW8i_YxU.mjs";
4
+ import { _ as workspaceLogsDir } from "./workspace-state-BT5E3SA2.mjs";
5
+ import { t as createLineReader } from "./process-output-Dl5uKE03.mjs";
6
+ import { i as startIosDeviceConsole, r as parseDeviceConsoleLine } from "./ios-device-CFXA46ez.mjs";
7
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-Cp52QAK1.mjs";
8
+ import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-DeYdjjBP.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,6 +1,6 @@
1
- import { n as stripAnsi } from "./process-output-C7IlIzd7.mjs";
1
+ import { n as stripAnsi } from "./process-output-Dl5uKE03.mjs";
2
2
  import { quotedPath } from "@stim-cli/core";
3
- //#region src/launch-error-preview.ts
3
+ //#region src/diagnostics/launch-error-preview.ts
4
4
  function framePriority(frame, root) {
5
5
  const normalized = frame.replaceAll("\\", "/");
6
6
  if (/^\s*at (?:android\.|java\.|com\.android\.|dalvik\.)/.test(normalized)) return 2;
@@ -1,11 +1,11 @@
1
1
  import { n as __exportAll, r as __reExport } from "./rolldown-runtime-BsOwBuO_.mjs";
2
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
3
3
  import { join } from "node:path";
4
4
  import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
5
5
  import { homedir } from "os";
6
- import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, normalize } from "path";
6
+ import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, normalize, parse as parse$1, sep as sep$1 } from "path";
7
7
  import { configDir, withDirLock } from "@stim-cli/core";
8
- //#region src/device-slots.ts
8
+ //#region src/devices/device-slots.ts
9
9
  const DEFAULT_DEVICE_SLOT = "default";
10
10
  function validateDeviceSlot(slot = "default") {
11
11
  if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/.test(slot) || [
@@ -69,6 +69,15 @@ function deviceSlotKey(platform, slot = "default") {
69
69
  if (platform !== "ios" && platform !== "android") throw new Error(`Unknown device platform: ${platform}`);
70
70
  return slot === "default" ? platform : `${platform}:${slot}`;
71
71
  }
72
+ /**
73
+ * The slot key in a form that is legal as a file name. NTFS reads a colon in a file name as an
74
+ * alternate data stream: the write and the read of the exact path both succeed while `readdirSync`
75
+ * cannot see the file, so every non-default slot's logs would be invisible to `stim logs`. A slot
76
+ * name can contain neither a colon nor a dot, so the two forms stay one-to-one.
77
+ */
78
+ function deviceSlotFileKey(platform, slot = "default") {
79
+ return deviceSlotKey(platform, slot).replace(":", ".");
80
+ }
72
81
  function parseDeviceSlotKey(key) {
73
82
  const [platform, slot = "default", extra] = key.split(":");
74
83
  if (platform !== "ios" && platform !== "android" || extra !== void 0) return null;
@@ -85,22 +94,27 @@ function parseDeviceSlotKey(key) {
85
94
  }
86
95
  //#endregion
87
96
  //#region src/fs-util.ts
97
+ const WINDOWS = process.platform === "win32";
98
+ const DRIVE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
88
99
  function volumeRootFor(path) {
89
- const m = normalize(String(path)).match(/^\/volumes\/([^/]+)/i);
100
+ const normalized = normalize(String(path));
101
+ if (WINDOWS) return parse$1(normalized).root.replace(/^[a-z]:/, (drive) => drive.toUpperCase());
102
+ const m = normalized.match(/^\/volumes\/([^/]+)/i);
90
103
  return m ? `/Volumes/${m[1]}` : "/";
91
104
  }
92
105
  function resolveWorkspaceRealish(workspacePath) {
93
106
  const raw = String(workspacePath);
94
- if (!raw.startsWith("/")) return null;
107
+ if (!isAbsolute$1(raw)) return null;
95
108
  let current = raw;
96
109
  const MAX_HOPS = 40;
97
110
  for (let hops = 0; hops < MAX_HOPS; hops++) {
98
111
  const normalized = normalize(current);
99
- const segments = normalized.split("/").filter(Boolean);
100
- let prefix = "";
112
+ const root = parse$1(normalized).root;
113
+ const segments = normalized.slice(root.length).split(sep$1).filter(Boolean);
114
+ let prefix = root.endsWith(sep$1) ? root.slice(0, -sep$1.length) : root;
101
115
  let followedSymlink = false;
102
116
  for (const segment of segments) {
103
- prefix += `/${segment}`;
117
+ prefix += `${sep$1}${segment}`;
104
118
  let st;
105
119
  try {
106
120
  st = lstatSync(prefix);
@@ -115,7 +129,7 @@ function resolveWorkspaceRealish(workspacePath) {
115
129
  } catch {
116
130
  return null;
117
131
  }
118
- current = `${target.startsWith("/") ? target : normalize(join$1(dirname$1(prefix), target))}${normalized.slice(prefix.length)}`;
132
+ current = `${isAbsolute$1(target) ? target : normalize(join$1(dirname$1(prefix), target))}${normalized.slice(prefix.length)}`;
119
133
  followedSymlink = true;
120
134
  break;
121
135
  }
@@ -127,7 +141,21 @@ function resolveWorkspaceRealish(workspacePath) {
127
141
  function isRealMount(entryDev, rootDev) {
128
142
  return entryDev != null && rootDev != null && entryDev !== rootDev;
129
143
  }
144
+ function listWindowsVolumeRoots(statFn) {
145
+ const roots = [];
146
+ for (const letter of DRIVE_LETTERS) {
147
+ const root = `${letter}:${sep$1}`;
148
+ try {
149
+ statFn(root);
150
+ } catch {
151
+ continue;
152
+ }
153
+ roots.push(root);
154
+ }
155
+ return roots;
156
+ }
130
157
  function listMountedVolumes({ statFn = statSync } = {}) {
158
+ if (WINDOWS) return listWindowsVolumeRoots(statFn);
131
159
  const roots = ["/"];
132
160
  let rootDev;
133
161
  try {
@@ -153,11 +181,19 @@ function resolveVolumeRoot(path) {
153
181
  const realish = resolveWorkspaceRealish(path);
154
182
  return realish === null ? null : volumeRootFor(realish);
155
183
  }
184
+ function uncShareIsReachable(volume) {
185
+ if (!WINDOWS || !volume.startsWith(`${sep$1}${sep$1}`)) return false;
186
+ try {
187
+ return statSync(volume).isDirectory();
188
+ } catch {
189
+ return false;
190
+ }
191
+ }
156
192
  function isOnMountedVolume(path, mountedVolumes) {
157
193
  const mounted = new Set(mountedVolumes || listMountedVolumes());
158
194
  const volume = resolveVolumeRoot(path);
159
195
  if (volume === null) return false;
160
- return mounted.has(volume);
196
+ return mounted.has(volume) || uncShareIsReachable(volume);
161
197
  }
162
198
  function directorySize(dir, { timeoutMs } = {}) {
163
199
  let out;
@@ -181,7 +217,7 @@ var ownership_claim_exports = /* @__PURE__ */ __exportAll({});
181
217
  import * as import__stim_cli_core_ownership_claim from "@stim-cli/core/ownership-claim";
182
218
  __reExport(ownership_claim_exports, import__stim_cli_core_ownership_claim);
183
219
  //#endregion
184
- //#region src/avd-claim.ts
220
+ //#region src/devices/avd-claim.ts
185
221
  function acquireAvdClaim(avdName) {
186
222
  const root = join(configDir(), "avd-locks", `${encodeURIComponent(avdName.toLowerCase())}.lock`);
187
223
  const label = `AVD ${avdName}`;
@@ -205,7 +241,7 @@ var process_identity_exports = /* @__PURE__ */ __exportAll({});
205
241
  import * as import__stim_cli_core_process_identity from "@stim-cli/core/process-identity";
206
242
  __reExport(process_identity_exports, import__stim_cli_core_process_identity);
207
243
  //#endregion
208
- //#region src/config.ts
244
+ //#region src/workspace/config.ts
209
245
  function getConfigDir() {
210
246
  return process.env.STIM_HOME || join$1(homedir(), ".stim");
211
247
  }
@@ -421,9 +457,13 @@ function getRepoSettings(gitCommonDir) {
421
457
  return loadConfig()?.repos?.[gitCommonDir]?.settings || {};
422
458
  }
423
459
  function isPathPrefix(prefix, path) {
424
- if (prefix === path) return true;
425
- const withSlash = prefix.endsWith("/") ? prefix : `${prefix}/`;
426
- return path.startsWith(withSlash);
460
+ const head = comparablePath(prefix);
461
+ const candidate = comparablePath(path);
462
+ if (head === candidate) return true;
463
+ return candidate.startsWith(head.endsWith("/") ? head : `${head}/`);
464
+ }
465
+ function comparablePath(path) {
466
+ return sep$1 === "/" ? path : path.replaceAll(sep$1, "/");
427
467
  }
428
468
  function findEnclosingWorktreeRoot(projectPath) {
429
469
  const cfg = loadConfig();
@@ -459,4 +499,4 @@ function allConsolePortsAndSerials({ isMounted = isOnMountedVolume } = {}) {
459
499
  return result;
460
500
  }
461
501
  //#endregion
462
- export { isOnMountedVolume as A, withConfigLock as C, withDirLock as D, ownership_claim_exports as E, deviceSlotPlatforms as F, parseDeviceSlotKey as I, projectDeviceSlots as L, volumeRootFor as M, assignSlotDevice as N, directorySize as O, deviceSlotKey as P, removeSlotDevice as R, upsertProject as S, acquireAvdClaim as T, releaseAndroidConsolePort as _, clearSupervisor as a, setDevice as b, findEnclosingWorktreeRoot as c, getConfigPath as d, getProject as f, loadConfig as g, isPathPrefix as h, clearDevice as i, listMountedVolumes as j, formatBytes as k, getConcurrencyLimits as l, getRepoSettings as m, allMetroPorts as n, configCorruptRepair as o, getProjectSettings as p, claimMetroPort as r, ensureConfig as s, allConsolePortsAndSerials as t, getConfigDir as u, removeProject as v, process_identity_exports as w, setSupervisor as x, saveConfig as y, validateDeviceSlot as z };
502
+ export { isOnMountedVolume as A, validateDeviceSlot as B, withConfigLock as C, withDirLock as D, ownership_claim_exports as E, deviceSlotKey as F, deviceSlotPlatforms as I, parseDeviceSlotKey as L, volumeRootFor as M, assignSlotDevice as N, directorySize as O, deviceSlotFileKey as P, projectDeviceSlots as R, upsertProject as S, acquireAvdClaim as T, releaseAndroidConsolePort as _, clearSupervisor as a, setDevice as b, findEnclosingWorktreeRoot as c, getConfigPath as d, getProject as f, loadConfig as g, isPathPrefix as h, clearDevice as i, listMountedVolumes as j, formatBytes as k, getConcurrencyLimits as l, getRepoSettings as m, allMetroPorts as n, configCorruptRepair as o, getProjectSettings as p, claimMetroPort as r, ensureConfig as s, allConsolePortsAndSerials as t, getConfigDir as u, removeProject as v, process_identity_exports as w, setSupervisor as x, saveConfig as y, removeSlotDevice as z };
@@ -1,5 +1,5 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { g as repoRoot } from "./worktree-DJnBbQZ9.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { g as repoRoot } from "./worktree-FG_ZKKdb.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { dirname, join, relative } from "node:path";
5
5
  //#region src/dependency-state.ts
@@ -1,8 +1,8 @@
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 { d as startBuildHeartbeat, m as bundlerPin, n as HEARTBEAT_INTERVAL_MS } from "./xcode-DUF7jrXj.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Dl5uKE03.mjs";
3
+ import { d as startBuildHeartbeat, m as bundlerPin, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B6YaWeg0.mjs";
4
4
  import { existsSync, readFileSync } from "node:fs";
5
- import { dirname, join, relative, resolve, sep } from "node:path";
5
+ import { delimiter, dirname, join, relative, resolve, sep } from "node:path";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/engine/deps.ts
8
8
  const DEPS_ERROR = "STIM_DEPS_FAILED";
@@ -138,7 +138,7 @@ function podEnv(root, { env = process.env, home = homedir(), exists = existsSync
138
138
  ];
139
139
  for (const c of candidates) {
140
140
  if (!exists(c.bin)) continue;
141
- out.PATH = `${c.bin}:${out.PATH ?? ""}`;
141
+ out.PATH = `${c.bin}${delimiter}${out.PATH ?? ""}`;
142
142
  if (c.gems && exists(c.gems)) {
143
143
  out.GEM_HOME = c.gems;
144
144
  out.GEM_PATH = c.gems;
@@ -266,7 +266,7 @@ async function ensureBundledGems(root, pin, ctx) {
266
266
  });
267
267
  if (install.error) return bundlerSpawnFailure("bundle install", install, pin);
268
268
  const inProject = bundlePathInsideProject(cwd, env);
269
- const note = inProject ? `\`bundle install\` put this project's gems in ${inProject.path}/, ${inProject.where}; Gemfile.lock itself is never written.` : void 0;
269
+ const note = inProject ? `\`bundle install\` put this project's gems in ${inProject.path}${sep}, ${inProject.where}; Gemfile.lock itself is never written.` : void 0;
270
270
  if (install.code === 0) return {
271
271
  bundler: true,
272
272
  note
@@ -0,0 +1,65 @@
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { openSync } from "node:fs";
3
+ //#region src/detached-entry.ts
4
+ const LOG_FILE_FLAG = "--log-file";
5
+ /**
6
+ * How a detached Node entry is started on win32. libuv spawns with bInheritHandles=TRUE and never
7
+ * closes the CRT's stdio descriptors, so every child inherits every inheritable handle this process
8
+ * holds, including the pipe a `stim start | Out-File x` pipeline gave it for stdout; a detached
9
+ * child then keeps that pipe open and the pipeline never completes (libuv/libuv#1490, fixed by
10
+ * libuv/libuv#5100 but not in a released Node.js). ShellExecuteEx passes no handles, and .NET's
11
+ * ProcessStartInfo uses it with UseShellExecute, so the entry starts through it and, holding no
12
+ * stray handle, redirects itself into the log file (`relaunchWithLogFile`).
13
+ * The direct child is only the short-lived PowerShell process.
14
+ */
15
+ function windowsLauncherArgs({ entry, args, cwd, logFile, execPath = process.execPath }) {
16
+ return {
17
+ file: "powershell.exe",
18
+ args: [
19
+ "-NoProfile",
20
+ "-NonInteractive",
21
+ "-Command",
22
+ "$ErrorActionPreference = 'Stop'; $start = [System.Diagnostics.ProcessStartInfo]::new(); $start.FileName = $env:STIM_WINDOWS_LAUNCH_FILE; $start.Arguments = $env:STIM_WINDOWS_LAUNCH_ARGS; $start.WorkingDirectory = $env:STIM_WINDOWS_LAUNCH_CWD; $start.UseShellExecute = $true; $start.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden; [System.Diagnostics.Process]::Start($start) | Out-Null"
23
+ ],
24
+ env: {
25
+ STIM_WINDOWS_LAUNCH_FILE: execPath,
26
+ STIM_WINDOWS_LAUNCH_ARGS: [
27
+ entry,
28
+ ...args,
29
+ LOG_FILE_FLAG,
30
+ logFile
31
+ ].map(windowsArgument).join(" "),
32
+ STIM_WINDOWS_LAUNCH_CWD: cwd
33
+ }
34
+ };
35
+ }
36
+ function windowsArgument(value) {
37
+ return `"${value.replace(/(\\*)"/g, "$1$1\\\"").replace(/(\\+)$/, "$1$1")}"`;
38
+ }
39
+ /**
40
+ * Strip `--log-file <path>` from an entry's argv and, when present, start the entry again with
41
+ * the remaining arguments and its stdio in that file. Returns null when the flag is absent; the
42
+ * caller exits after a relaunch.
43
+ */
44
+ function relaunchWithLogFile(argv, { entry = process.argv[1], spawn = (file, args, opts) => getExecutor().spawn(file, args, opts) } = {}) {
45
+ const index = argv.indexOf(LOG_FILE_FLAG);
46
+ if (index < 0) return null;
47
+ const logFile = argv[index + 1];
48
+ if (!logFile) throw new Error(`${LOG_FILE_FLAG} needs a path.`);
49
+ const rest = [...argv.slice(0, index), ...argv.slice(index + 2)];
50
+ const fd = openSync(logFile, "a");
51
+ const child = spawn(process.execPath, [entry, ...rest], {
52
+ cwd: process.cwd(),
53
+ detached: true,
54
+ stdio: [
55
+ "ignore",
56
+ fd,
57
+ fd
58
+ ],
59
+ env: process.env
60
+ });
61
+ child.unref?.();
62
+ return child;
63
+ }
64
+ //#endregion
65
+ export { windowsLauncherArgs as n, relaunchWithLogFile as t };
@@ -1,15 +1,15 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { E as ownership_claim_exports } from "./config-DMP7L7H6.mjs";
3
- import { c as ensureWorkspaceStorage } from "./workspace-state-WVwWw_hB.mjs";
4
- import { T as removeTemporaryEntry, w as makeTemporaryDirectory } from "./worktree-DJnBbQZ9.mjs";
5
- import { i as detectIsExpo, o as isPackageResolvable } from "./project-B_SDt4ip.mjs";
6
- import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
7
- import { t as NOT_OURS_FOREIGN_CWD } from "./metro-ato6ef3J.mjs";
8
- import { V as releaseBuildLock, z as acquireBuildLock } from "./android-BkYmndPp.mjs";
9
- import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-CX-zkgWl.mjs";
10
- import { S as resolveEasCliBin } from "./teardown-sm1FwF6V.mjs";
11
- import { i as LAUNCH_BUNDLING, s as LAUNCH_UNVERIFIED } from "./app-install--PAocWvq.mjs";
12
- import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-DUF7jrXj.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { E as ownership_claim_exports } from "./config-B7iyKWkL.mjs";
3
+ import { c as ensureWorkspaceStorage } from "./workspace-state-BT5E3SA2.mjs";
4
+ import { T as removeTemporaryEntry, w as makeTemporaryDirectory } from "./worktree-FG_ZKKdb.mjs";
5
+ import { i as detectIsExpo, o as isPackageResolvable } from "./project-DDZWf_16.mjs";
6
+ import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Dl5uKE03.mjs";
7
+ import { t as NOT_OURS_FOREIGN_CWD } from "./metro-C7bcJ0uo.mjs";
8
+ import { i as releaseBuildLock, n as acquireBuildLock } from "./build-lock-CgtsB6TV.mjs";
9
+ import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-BVAA1OqJ.mjs";
10
+ import { S as resolveEasCliBin } from "./teardown-5J5UXz2P.mjs";
11
+ import { i as LAUNCH_BUNDLING, s as LAUNCH_UNVERIFIED } from "./app-install-DJg7bVv-.mjs";
12
+ import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B6YaWeg0.mjs";
13
13
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
14
14
  import { createHash } from "node:crypto";
15
15
  import { basename, join } from "node:path";
@@ -1,10 +1,10 @@
1
- import { z as validateDeviceSlot } from "./config-DMP7L7H6.mjs";
2
- import { a as findProjectRoot } from "./project-B_SDt4ip.mjs";
3
- import { r as clockTime } from "./command-output-BuIb_ZOI.mjs";
4
- import { C as memoizeEmulatorProbe, P as resolvePhysicalDevice, i as androidPoolNoCandidatesRefusal, j as probeEmulatorSerial, k as physicalDeviceModel, r as androidPoolCandidates, y as listAdbDevices } from "./android-BkYmndPp.mjs";
5
- import { f as takeLease, l as releaseWorkspaceLeases, n as fileLeaseIo, o as parseLeaseDuration } from "./device-lease-DBW-IL4p.mjs";
6
- import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-C0s_83Og.mjs";
7
- import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-DJOi9FR5.mjs";
1
+ import { B as validateDeviceSlot } from "./config-B7iyKWkL.mjs";
2
+ import { a as findProjectRoot } from "./project-DDZWf_16.mjs";
3
+ import { E as memoizeEmulatorProbe, L as resolvePhysicalDevice, M as physicalDeviceModel, P as probeEmulatorSerial, S as listAdbDevices, a as androidPoolNoCandidatesRefusal, i as androidPoolCandidates } from "./android-DWssqHQ8.mjs";
4
+ import { r as clockTime } from "./command-output-B3ycpsYv.mjs";
5
+ import { f as takeLease, l as releaseWorkspaceLeases, n as fileLeaseIo, o as parseLeaseDuration } from "./device-lease-Ffz_M5t0.mjs";
6
+ import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-DNSHL5z8.mjs";
7
+ import { c as listIosDevices, o as iosPoolCandidates, s as iosPoolNoCandidatesRefusal, u as resolveIosPhysicalDevice } from "./ios-device-CDbvn5H2.mjs";
8
8
  import chalk from "chalk";
9
9
  //#region src/commands/device.ts
10
10
  const DEFAULT_FOR = "5m";
@@ -1,15 +1,15 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { C as withConfigLock, E as ownership_claim_exports, F as deviceSlotPlatforms, L as projectDeviceSlots, T as acquireAvdClaim, _ as releaseAndroidConsolePort, b as setDevice, g as loadConfig, i as clearDevice, t as allConsolePortsAndSerials, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-DMP7L7H6.mjs";
3
- import { g as workspaceId } from "./workspace-state-WVwWw_hB.mjs";
4
- import { s as ownedDeviceLabel } from "./project-B_SDt4ip.mjs";
5
- import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
6
- import { r as pidExists } from "./metro-ato6ef3J.mjs";
7
- import { l as phaseLine } from "./command-output-BuIb_ZOI.mjs";
8
- import { A as pickDefaultSystemImage, D as ownedAvdName, E as ownedAvdMatchesConfiguration, L as waitForBoot, N as resolveOwnedAvdSerial, O as ownedAvdSystemImage, b as listAvds, c as avdPoolConfiguration, d as configureNewOwnedAvd, f as createOwnedAvd, o as assertOwnedAvdStopped, u as bootAndroidEmulator, v as getAvdNameForSerial, w as nextConsolePort, x as listInstalledSystemImages, y as listAdbDevices } from "./android-BkYmndPp.mjs";
9
- import { l as androidDataPartitionSizeGbSetting, o as androidAvdConfigSetting, v as iosSimSlimProfileSetting } from "./settings-CGHTt5vb.mjs";
10
- import { c as isLegacyDeletionClaim, d as selectParked, i as teardownParkedIosSim, l as parkedMaxSetting, o as adoptParked, r as teardownParkedAvd, s as dropParked, t as teardownOwnedAvd, u as readParked } from "./teardown-sm1FwF6V.mjs";
11
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-Bz19_R9R.mjs";
12
- import { E as readHostMemoryPressure, T as hostMemoryPressureAdvice, _ as renameIosSim, b as resolveIosCreation, c as iosRuntimeMatches, d as listIosDeviceTypes, g as parseRuntimeVersion, i as createOwnedIosSim, l as iosSimulatorFailureAdvice, m as ownedSimName, n as bootIosSim, u as listAllIosSims, v as resetIosKeychain, x as resolveOwnedIosSim, y as resetIosPrivacy } from "./ios-Deh5js5V.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { C as withConfigLock, E as ownership_claim_exports, I as deviceSlotPlatforms, R as projectDeviceSlots, T as acquireAvdClaim, _ as releaseAndroidConsolePort, b as setDevice, g as loadConfig, i as clearDevice, t as allConsolePortsAndSerials, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-B7iyKWkL.mjs";
3
+ import { g as workspaceId } from "./workspace-state-BT5E3SA2.mjs";
4
+ import { s as ownedDeviceLabel } from "./project-DDZWf_16.mjs";
5
+ import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Dl5uKE03.mjs";
6
+ import { i as pidExists } from "./metro-C7bcJ0uo.mjs";
7
+ import { l as androidDataPartitionSizeGbSetting, o as androidAvdConfigSetting, v as iosSimSlimProfileSetting } from "./settings-BXXorVM2.mjs";
8
+ import { A as ownedAvdName, B as waitForBoot, C as listAvds, D as nextConsolePort, I as resolveOwnedAvdSerial, N as pickDefaultSystemImage, S as listAdbDevices, b as getAvdNameForSerial, c as assertOwnedAvdStopped, f as bootAndroidEmulator, j as ownedAvdSystemImage, k as ownedAvdMatchesConfiguration, m as createOwnedAvd, p as configureNewOwnedAvd, u as avdPoolConfiguration, w as listInstalledSystemImages } from "./android-DWssqHQ8.mjs";
9
+ import { l as phaseLine } from "./command-output-B3ycpsYv.mjs";
10
+ import { c as isLegacyDeletionClaim, d as selectParked, i as teardownParkedIosSim, l as parkedMaxSetting, o as adoptParked, r as teardownParkedAvd, s as dropParked, t as teardownOwnedAvd, u as readParked } from "./teardown-5J5UXz2P.mjs";
11
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
12
+ import { E as readHostMemoryPressure, T as hostMemoryPressureAdvice, _ as renameIosSim, b as resolveIosCreation, c as iosRuntimeMatches, d as listIosDeviceTypes, g as parseRuntimeVersion, i as createOwnedIosSim, l as iosSimulatorFailureAdvice, m as ownedSimName, n as bootIosSim, u as listAllIosSims, v as resetIosKeychain, x as resolveOwnedIosSim, y as resetIosPrivacy } from "./ios-lEJ5pKsq.mjs";
13
13
  import { randomUUID } from "node:crypto";
14
14
  import { join } from "node:path";
15
15
  import { claimRemoveCommand, clearClaimChild, markClaimChildPending, processGroupAlive, releaseClaim, setClaimChild } from "@stim-cli/core/ownership-claim";
@@ -153,7 +153,7 @@ function simslimLaunchError(error) {
153
153
  }
154
154
  function simslimIsOnPath() {
155
155
  try {
156
- return Boolean(getExecutor().runQuiet("command -v simslim", { timeoutMs: 5e3 }));
156
+ return Boolean(getExecutor().findExecutable("simslim"));
157
157
  } catch {
158
158
  return false;
159
159
  }
@@ -311,6 +311,8 @@ async function prepareOwnedAvd({ projectPath, slot, label, previousAvdName, syst
311
311
  }
312
312
  //#endregion
313
313
  //#region src/engine/device.ts
314
+ const ANDROID_FRESH_BOOT_TIMEOUT_MS = process.platform === "win32" ? 12e5 : 12e4;
315
+ const ANDROID_BOOT_TIMEOUT_MS = process.platform === "win32" ? 12e5 : 24e4;
314
316
  function startIosBoot(udid, configure, label, out) {
315
317
  const done = (async () => {
316
318
  await bootIosSim(udid, {
@@ -793,7 +795,7 @@ async function bootOwnedAvdOnFreshPort({ avdName, metadata, projectPath, slot, d
793
795
  out(chalk.dim(phaseLine("device", `waiting for ${serial} to finish booting`)));
794
796
  const result = await waitForAndroidBoot({
795
797
  serial,
796
- timeoutMs: 12e4,
798
+ timeoutMs: ANDROID_FRESH_BOOT_TIMEOUT_MS,
797
799
  pid,
798
800
  alive,
799
801
  out
@@ -976,7 +978,7 @@ async function ensureBooted({ platform, device, timeoutMs, pollMs = BOOT_POLL_MS
976
978
  });
977
979
  if (platform === "android") return ensureAndroidBooted({
978
980
  device,
979
- timeoutMs: timeoutMs ?? 24e4,
981
+ timeoutMs: timeoutMs ?? ANDROID_BOOT_TIMEOUT_MS,
980
982
  out,
981
983
  logFile,
982
984
  alive
@@ -1,6 +1,6 @@
1
- import { D as withDirLock, I as parseDeviceSlotKey, P as deviceSlotKey, u as getConfigDir, z as validateDeviceSlot } from "./config-DMP7L7H6.mjs";
2
- import { a as withWorkspaceStateLock, n as clearWorkspaceStateKeys, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-WVwWw_hB.mjs";
3
- import { H as segment } from "./android-BkYmndPp.mjs";
1
+ import { B as validateDeviceSlot, D as withDirLock, F as deviceSlotKey, L as parseDeviceSlotKey, u as getConfigDir } from "./config-B7iyKWkL.mjs";
2
+ import { a as withWorkspaceStateLock, n as clearWorkspaceStateKeys, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
3
+ import { a as segment } from "./build-lock-CgtsB6TV.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,7 +1,7 @@
1
- import { P as deviceSlotKey } from "./config-DMP7L7H6.mjs";
2
- import { a as formatElapsed, r as clockTime } from "./command-output-BuIb_ZOI.mjs";
3
- import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install--PAocWvq.mjs";
4
- 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-DBW-IL4p.mjs";
1
+ import { F as deviceSlotKey } from "./config-B7iyKWkL.mjs";
2
+ import { a as formatElapsed, r as clockTime } from "./command-output-B3ycpsYv.mjs";
3
+ import { A as APP_READINESS_TIMEOUT_MS, l as VERIFY_TIMEOUT_MS } from "./app-install-DJg7bVv-.mjs";
4
+ 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-Ffz_M5t0.mjs";
5
5
  //#region src/engine/device-lease-run.ts
6
6
  const LEASE_STEP_FLOOR_MS = 6e4;
7
7
  const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
@@ -1,12 +1,12 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { D as withDirLock, u as getConfigDir } from "./config-DMP7L7H6.mjs";
3
- import { _ as workspaceLogsDir, h as workspaceDir, v as workspaceName, y as workspaceStateFile } from "./workspace-state-WVwWw_hB.mjs";
4
- import { a as clearRemoteSession, l as readRemoteSession, s as readMetroTunnel } from "./state-CnWzvCWP.mjs";
5
- import { r as pidExists } from "./metro-ato6ef3J.mjs";
6
- import { z as planMetroReach } from "./settings-CGHTt5vb.mjs";
7
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-Bz19_R9R.mjs";
8
- import { T as readMetroRecords, a as LAUNCH_ERROR, b as isBundleProof, p as devClientDeepLink, r as INSTALL_ERROR } from "./app-install--PAocWvq.mjs";
9
- import { S as sanitizeDeviceLabel } from "./ios-Deh5js5V.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { D as withDirLock, u as getConfigDir } from "./config-B7iyKWkL.mjs";
3
+ import { _ as workspaceLogsDir, h as workspaceDir, v as workspaceName, y as workspaceStateFile } from "./workspace-state-BT5E3SA2.mjs";
4
+ import { a as clearRemoteSession, l as readRemoteSession, s as readMetroTunnel } from "./state-DZobzxLW.mjs";
5
+ import { i as pidExists } from "./metro-C7bcJ0uo.mjs";
6
+ import { z as planMetroReach } from "./settings-BXXorVM2.mjs";
7
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
8
+ import { T as readMetroRecords, a as LAUNCH_ERROR, b as isBundleProof, p as devClientDeepLink, r as INSTALL_ERROR } from "./app-install-DJg7bVv-.mjs";
9
+ import { S as sanitizeDeviceLabel } from "./ios-lEJ5pKsq.mjs";
10
10
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
11
11
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
12
12
  import { homedir } from "node:os";
@@ -832,13 +832,13 @@ async function resolveRemoteContext({ root, label, backend, platform = "ios", ea
832
832
  }
833
833
  function binOnPath(bin) {
834
834
  try {
835
- return Boolean(getExecutor().runQuiet(`command -v ${bin}`, { timeoutMs: 5e3 }));
835
+ return Boolean(getExecutor().findExecutable(bin));
836
836
  } catch {
837
837
  return false;
838
838
  }
839
839
  }
840
840
  function defaultLookupAgentDevice() {
841
- const found = getExecutor().runQuiet("command -v agent-device", { timeoutMs: 5e3 });
841
+ const found = getExecutor().findExecutable("agent-device");
842
842
  return (String(found ?? "").split("\n")[0] ?? "").trim() || null;
843
843
  }
844
844
  const DAEMON_WAIT_MS = 18e4;