stim 1.5.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-DJWiTBkz.mjs → android-DWssqHQ8.mjs} +165 -661
  3. package/dist/{android-sobvO9ia.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-CSS8gjR7.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-BAGOnrc7.mjs → deps-oCXVNEqQ.mjs} +6 -6
  20. package/dist/detached-entry-Bpo6ZY_I.mjs +65 -0
  21. package/dist/{dev-client-BoifdqkU.mjs → dev-client-DDUkWgJL.mjs} +12 -12
  22. package/dist/{device-BUw4JBuH.mjs → device-CBSaC6BU.mjs} +7 -7
  23. package/dist/{device-DvKJ454A.mjs → device-CLeDp-KH.mjs} +17 -15
  24. package/dist/{device-lease-r7yEQ1R8.mjs → device-lease-Ffz_M5t0.mjs} +3 -3
  25. package/dist/{device-pool-DU4FQKp5.mjs → device-pool-DNSHL5z8.mjs} +4 -4
  26. package/dist/{device-remote-BTUqbl0i.mjs → device-remote-BprxZp-m.mjs} +11 -11
  27. package/dist/{doctor-Di_B26uh.mjs → doctor-CTAx9gMu.mjs} +90 -46
  28. package/dist/{error-diagnostics-CTePWAzW.mjs → error-diagnostics-D1Kaf-eT.mjs} +23 -17
  29. package/dist/{exec-CyylIdq9.mjs → exec-B29XNuhP.mjs} +14 -2
  30. package/dist/{gc-C20dWw_8.mjs → gc-CX0KRfLG.mjs} +17 -16
  31. package/dist/{guide-sAnoty2y.mjs → guide-CPmAG9me.mjs} +61 -22
  32. package/dist/{guide-status-BF6RsJJp.mjs → guide-status-Craq9z0t.mjs} +3 -3
  33. package/dist/{ios-BdpkncL6.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-BfQdIhiF.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-C_rB25f4.mjs → reclaim-D614jI6_.mjs} +11 -11
  47. package/dist/{reload-CYBJbJfI.mjs → reload-ChW46VDb.mjs} +9 -9
  48. package/dist/{server-bare-H3pAhbMs.mjs → server-bare-BQkyxa_b.mjs} +1 -1
  49. package/dist/{server-expo-Ds8_mfng.mjs → server-expo-BVAA1OqJ.mjs} +23 -11
  50. package/dist/server-expo-YDDG3eP7.mjs +2 -0
  51. package/dist/{settings-kO2ZqIKy.mjs → settings-BXXorVM2.mjs} +8 -5
  52. package/dist/{slot-launch-BpHiHH6A.mjs → slot-launch-DbLvyrup.mjs} +4 -4
  53. package/dist/{start-DiEfqEWk.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-J5LAXpag.mjs → status-DUNy_HZs.mjs} +14 -15
  58. package/dist/{stop-CM1fejKW.mjs → stop-CnUpnFT5.mjs} +2 -2
  59. package/dist/{stop-0jJNahwN.mjs → stop-ZrfODZ51.mjs} +13 -13
  60. package/dist/supervisor-run.mjs +7 -5
  61. package/dist/{teardown-CAVcWeRD.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-CeUKDAQw.mjs → worktree-BfE4lzHK.mjs} +21 -16
  65. package/dist/{worktree-DJnBbQZ9.mjs → worktree-FG_ZKKdb.mjs} +13 -9
  66. package/dist/{xcode-BqDeRkpT.mjs → xcode-B6YaWeg0.mjs} +92 -17
  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-CSwUVYOa.mjs +0 -2
@@ -1,7 +1,7 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { C as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-DMP7L7H6.mjs";
3
- import { n as isPortFree } from "./ports-BZprTJRa.mjs";
4
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-Bz19_R9R.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { C as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, w as process_identity_exports, y as saveConfig } from "./config-B7iyKWkL.mjs";
3
+ import { c as isPortFree, o as signalProcessTree, r as listeningPids } from "./metro-C7bcJ0uo.mjs";
4
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
5
5
  import { realpathSync } from "node:fs";
6
6
  //#region src/named-ports.ts
7
7
  const FIRST_PORT = 8900;
@@ -10,7 +10,8 @@ function validatePortLabel(label) {
10
10
  if (label === "metro") throw new Error("metro is managed by stim start and stim stop; choose another label.");
11
11
  if (!/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/.test(label)) throw new Error("A port label must start with a letter and contain at most 64 letters, digits, underscores or hyphens.");
12
12
  }
13
- function portListeners(port) {
13
+ function portListeners(port, platform) {
14
+ if (platform === "win32") return listeningPids(port, platform);
14
15
  let out;
15
16
  try {
16
17
  out = getExecutor().runFile("lsof", [
@@ -28,10 +29,29 @@ function portListeners(port) {
28
29
  if (pids.some((pid) => !Number.isSafeInteger(pid) || pid <= 0)) throw new Error(`lsof returned an invalid listener for TCP port ${port}.`);
29
30
  return [...new Set(pids)];
30
31
  }
32
+ function processCommand(pid, platform) {
33
+ const e = getExecutor();
34
+ if (platform === "win32") {
35
+ const csv = e.runFileQuiet("tasklist", [
36
+ "/FI",
37
+ `PID eq ${pid}`,
38
+ "/FO",
39
+ "CSV",
40
+ "/NH"
41
+ ], { timeoutMs: 5e3 });
42
+ return /^"([^"]*)"/.exec((csv ?? "").trim())?.[1] ?? "";
43
+ }
44
+ return (e.runFileQuiet("ps", [
45
+ "-p",
46
+ String(pid),
47
+ "-o",
48
+ "args="
49
+ ], { timeoutMs: 5e3 }) ?? "").trim();
50
+ }
31
51
  function withPortsLock(fn) {
32
52
  return withWorkspaceProcessLock(getConfigDir(), "ports", fn, { external: true });
33
53
  }
34
- async function getNamedPort(projectPath, label, { isFree = async (port) => await isPortFree(port) && portListeners(port).length === 0, log = console.error } = {}) {
54
+ async function getNamedPort(projectPath, label, { isFree = async (port) => await isPortFree(port) && portListeners(port, process.platform).length === 0, log = console.error } = {}) {
35
55
  validatePortLabel(label);
36
56
  const root = realpathSync(projectPath);
37
57
  return withPortsLock(async () => {
@@ -61,37 +81,33 @@ async function getNamedPort(projectPath, label, { isFree = async (port) => await
61
81
  throw new Error(`No free named port between ${FIRST_PORT} and ${LAST_PORT}. Use stim ports stop or stim ports release in a workspace that no longer needs its ports.`);
62
82
  });
63
83
  }
64
- async function stopListeners(port, label, dryRun, log) {
65
- for (const pid of portListeners(port)) {
84
+ async function stopListeners(port, label, dryRun, log, platform) {
85
+ const listeners = () => portListeners(port, platform);
86
+ for (const pid of listeners()) {
66
87
  if (pid === process.pid) throw new Error(`Refusing to stop Stim itself on ${label} (${port}).`);
67
88
  const identity = (0, process_identity_exports.captureProcessIdentity)(pid);
68
89
  if (!identity.ok) {
69
- if (!portListeners(port).includes(pid)) continue;
90
+ if (!listeners().includes(pid)) continue;
70
91
  throw new Error(`Cannot identify pid ${pid} on ${label} (${port}): ${identity.reason}`);
71
92
  }
72
93
  const record = {
73
94
  pid,
74
95
  processToken: identity.token
75
96
  };
76
- const command = getExecutor().runFile("ps", [
77
- "-p",
78
- String(pid),
79
- "-o",
80
- "args="
81
- ], { timeoutMs: 5e3 }).trim();
97
+ const command = processCommand(pid, platform);
82
98
  if (dryRun) {
83
99
  log(`would stop ${label} (${port}): pid ${pid} ${command}`);
84
100
  continue;
85
101
  }
86
- if (!portListeners(port).includes(pid)) continue;
102
+ if (!listeners().includes(pid)) continue;
87
103
  const status = (0, process_identity_exports.inspectProcessIdentity)(record);
88
104
  if (status === "gone" || status === "different") continue;
89
105
  if (status !== "same") throw new Error(`Cannot verify pid ${pid} on ${label} (${port}); allocation kept.`);
90
106
  try {
91
- process.kill(pid, "SIGTERM");
107
+ signalProcessTree(pid, "SIGTERM", { platform });
92
108
  if (!await (0, process_identity_exports.waitForProcessExit)(record, 2e3)) {
93
109
  if ((0, process_identity_exports.inspectProcessIdentity)(record) !== "same") throw new Error(`Cannot verify pid ${pid} before SIGKILL.`);
94
- process.kill(pid, "SIGKILL");
110
+ signalProcessTree(pid, "SIGKILL", { platform });
95
111
  if (!await (0, process_identity_exports.waitForProcessExit)(record, 2e3)) throw new Error(`Pid ${pid} did not exit.`);
96
112
  }
97
113
  } catch (error) {
@@ -99,36 +115,35 @@ async function stopListeners(port, label, dryRun, log) {
99
115
  }
100
116
  log(`stopped ${label} (${port}): pid ${pid} ${command}`);
101
117
  }
102
- if (!dryRun && portListeners(port).length) throw new Error(`Port ${port} still has a listener; allocation kept.`);
118
+ if (!dryRun && listeners().length) throw new Error(`Port ${port} still has a listener; allocation kept.`);
103
119
  }
104
- async function clearNamedPorts(projectPath, { label, stop = false, dryRun = false, log = console.error } = {}) {
120
+ async function clearNamedPorts(projectPath, { label, stop = false, dryRun = false, log = console.error, platform = process.platform } = {}) {
105
121
  if (label !== void 0) validatePortLabel(label);
106
122
  await withPortsLock(async () => {
107
123
  const ports = getProject(projectPath)?.ports ?? {};
124
+ const selected = Object.entries(ports).filter(([name]) => label === void 0 || name === label);
125
+ if (stop && selected.length > 0 && platform !== "win32" && !getExecutor().findExecutable("lsof")) throw new Error("Cannot stop named ports: lsof is not installed.");
108
126
  const failures = [];
109
- for (const [name, port] of Object.entries(ports)) {
110
- if (label !== void 0 && name !== label) continue;
111
- try {
112
- if (!Number.isInteger(port) || port < FIRST_PORT || port > LAST_PORT) throw new Error(`Invalid named port ${name} (${port}); repair its config record before cleanup.`);
113
- if (stop) {
114
- if (Object.values(loadConfig()?.projects ?? {}).some((project) => project.metroPort === port)) throw new Error(`Port ${port} is reserved for managed Metro; allocation kept.`);
115
- await stopListeners(port, name, dryRun, log);
116
- }
117
- if (dryRun) {
118
- log(`would release ${name} (${port})`);
119
- continue;
120
- }
121
- withConfigLock(() => {
122
- const cfg = loadConfig();
123
- const current = cfg?.projects?.[projectPath]?.ports;
124
- if (!cfg || current?.[name] !== port) return;
125
- delete current[name];
126
- saveConfig(cfg);
127
- });
128
- log(`released ${name} (${port})`);
129
- } catch (error) {
130
- failures.push(`${name} (${port}): ${error.message}`);
127
+ for (const [name, port] of selected) try {
128
+ if (!Number.isInteger(port) || port < FIRST_PORT || port > LAST_PORT) throw new Error(`Invalid named port ${name} (${port}); repair its config record before cleanup.`);
129
+ if (stop) {
130
+ if (Object.values(loadConfig()?.projects ?? {}).some((project) => project.metroPort === port)) throw new Error(`Port ${port} is reserved for managed Metro; allocation kept.`);
131
+ await stopListeners(port, name, dryRun, log, platform);
131
132
  }
133
+ if (dryRun) {
134
+ log(`would release ${name} (${port})`);
135
+ continue;
136
+ }
137
+ withConfigLock(() => {
138
+ const cfg = loadConfig();
139
+ const current = cfg?.projects?.[projectPath]?.ports;
140
+ if (!cfg || current?.[name] !== port) return;
141
+ delete current[name];
142
+ saveConfig(cfg);
143
+ });
144
+ log(`released ${name} (${port})`);
145
+ } catch (error) {
146
+ failures.push(`${name} (${port}): ${error.message}`);
132
147
  }
133
148
  if (failures.length) throw new Error(failures.join("\n"));
134
149
  });
@@ -1,6 +1,6 @@
1
- import { w as process_identity_exports } from "./config-DMP7L7H6.mjs";
2
- import { a as withWorkspaceStateLock, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-WVwWw_hB.mjs";
3
- import { r as pidExists } from "./metro-ato6ef3J.mjs";
1
+ import { w as process_identity_exports } from "./config-B7iyKWkL.mjs";
2
+ import { a as withWorkspaceStateLock, o as writeWorkspaceState, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
3
+ import { i as pidExists } from "./metro-C7bcJ0uo.mjs";
4
4
  import { realpathSync } from "node:fs";
5
5
  //#region src/collector/state.ts
6
6
  function collectorRoot(root) {
@@ -1,8 +1,8 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { u as getConfigDir, w as process_identity_exports } from "./config-DMP7L7H6.mjs";
3
- import { t as createLineReader } from "./process-output-C7IlIzd7.mjs";
4
- import { r as pidExists } from "./metro-ato6ef3J.mjs";
5
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-Bz19_R9R.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
+ import { u as getConfigDir, w as process_identity_exports } from "./config-B7iyKWkL.mjs";
3
+ import { t as createLineReader } from "./process-output-Dl5uKE03.mjs";
4
+ import { i as pidExists, o as signalProcessTree } from "./metro-C7bcJ0uo.mjs";
5
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BYfZz_S-.mjs";
6
6
  import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync } from "node:fs";
7
7
  import { createHash, randomUUID } from "node:crypto";
8
8
  import { basename, join, resolve, sep } from "node:path";
@@ -324,13 +324,14 @@ function resumeChildPipes(child) {
324
324
  child.stdout?.resume?.();
325
325
  child.stderr?.resume?.();
326
326
  }
327
- async function signalAndWaitForExit(child, signal, { timeoutMs, now, sleep, isAlive }) {
327
+ async function signalAndWaitForExit(child, signal, { timeoutMs, now, sleep, isAlive, platform }) {
328
328
  let exited = false;
329
329
  const onExit = () => {
330
330
  exited = true;
331
331
  };
332
332
  child.once("exit", onExit);
333
333
  try {
334
+ if (platform === "win32" && child.pid) signalProcessTree(child.pid, signal, { platform });
334
335
  child.kill(signal);
335
336
  } catch (err) {
336
337
  child.removeListener("exit", onExit);
@@ -343,7 +344,7 @@ async function signalAndWaitForExit(child, signal, { timeoutMs, now, sleep, isAl
343
344
  child.removeListener("exit", onExit);
344
345
  return hasExited();
345
346
  }
346
- async function terminateChild(child, { alreadyExited, timeoutMs, now, sleep, isAlive }) {
347
+ async function terminateChild(child, { alreadyExited, timeoutMs, now, sleep, isAlive, platform = process.platform }) {
347
348
  if (alreadyExited) {
348
349
  closeChildPipes(child);
349
350
  return true;
@@ -352,7 +353,8 @@ async function terminateChild(child, { alreadyExited, timeoutMs, now, sleep, isA
352
353
  timeoutMs,
353
354
  now,
354
355
  sleep,
355
- isAlive
356
+ isAlive,
357
+ platform
356
358
  })) {
357
359
  closeChildPipes(child);
358
360
  return true;
@@ -361,7 +363,8 @@ async function terminateChild(child, { alreadyExited, timeoutMs, now, sleep, isA
361
363
  timeoutMs,
362
364
  now,
363
365
  sleep,
364
- isAlive
366
+ isAlive,
367
+ platform
365
368
  });
366
369
  closeChildPipes(child);
367
370
  return killed;
@@ -371,13 +374,10 @@ function describe(err) {
371
374
  }
372
375
  const STOP_TIMEOUT_MS = 5e3;
373
376
  const STOP_POLL_MS = 100;
374
- function defaultKill(pid) {
375
- process.kill(pid, "SIGTERM");
376
- }
377
377
  function isEsrch(err) {
378
378
  return err?.code === "ESRCH";
379
379
  }
380
- async function stopTunnel(record, { isAlive = pidExists, inspectIdentity = process_identity_exports.inspectProcessIdentity, kill = defaultKill, now = Date.now, sleep = defaultSleep, timeoutMs = STOP_TIMEOUT_MS } = {}) {
380
+ async function stopTunnel(record, { isAlive = pidExists, inspectIdentity = process_identity_exports.inspectProcessIdentity, platform = process.platform, kill = (pid) => signalProcessTree(pid, "SIGTERM", { platform }), now = Date.now, sleep = defaultSleep, timeoutMs = STOP_TIMEOUT_MS } = {}) {
381
381
  const missing = () => {
382
382
  removeRecordedTunnelLogFile(record?.logFile);
383
383
  return { status: "missing" };
@@ -1,6 +1,6 @@
1
- import { f as getProject } from "./config-DMP7L7H6.mjs";
2
- import { a as findProjectRoot } from "./project-B_SDt4ip.mjs";
3
- import { n as getNamedPort, t as clearNamedPorts } from "./named-ports-DH9SXd0f.mjs";
1
+ import { f as getProject } from "./config-B7iyKWkL.mjs";
2
+ import { a as findProjectRoot } from "./project-DDZWf_16.mjs";
3
+ import { n as getNamedPort, t as clearNamedPorts } from "./named-ports-DzMOlmaX.mjs";
4
4
  //#region src/commands/ports.ts
5
5
  async function inProject(action) {
6
6
  try {
@@ -10,7 +10,7 @@ function createLineReader(onLine) {
10
10
  buffered += String(chunk);
11
11
  const parts = buffered.split("\n");
12
12
  buffered = parts.pop() ?? "";
13
- for (const part of parts) onLine(part);
13
+ for (const part of parts) onLine(part.endsWith("\r") ? part.slice(0, -1) : part);
14
14
  },
15
15
  flush() {
16
16
  if (!buffered) return;
@@ -1,9 +1,9 @@
1
- import { c as findEnclosingWorktreeRoot, f as getProject } from "./config-DMP7L7H6.mjs";
2
- import { g as repoRoot } from "./worktree-DJnBbQZ9.mjs";
1
+ import { c as findEnclosingWorktreeRoot, f as getProject } from "./config-B7iyKWkL.mjs";
2
+ import { g as repoRoot } from "./worktree-FG_ZKKdb.mjs";
3
3
  import { existsSync, readFileSync, readdirSync, realpathSync } from "fs";
4
4
  import { basename, dirname, join, resolve } from "path";
5
5
  import { createRequire } from "module";
6
- //#region src/project.ts
6
+ //#region src/workspace/project.ts
7
7
  const requireFromHere = createRequire(import.meta.url);
8
8
  function resolvePackageJson(projectRoot, name) {
9
9
  try {
@@ -1,15 +1,15 @@
1
- import { E as ownership_claim_exports, L as projectDeviceSlots, T as acquireAvdClaim, f as getProject, v as removeProject, w as process_identity_exports } from "./config-DMP7L7H6.mjs";
2
- import { h as workspaceDir, r as readWorkspaceState } from "./workspace-state-WVwWw_hB.mjs";
3
- import { a as clearRemoteSession, i as clearManagedMetroTunnel, s as readMetroTunnel, u as readRemoteSessionId } from "./state-CnWzvCWP.mjs";
4
- import { i as resolveProjectMetro, n as killMetroTree, r as pidExists } from "./metro-ato6ef3J.mjs";
5
- import { n as verifyCollectorOwnership } from "./ownership-CD_XnpDu.mjs";
6
- import { S as resolveEasCliBin, l as parkedMaxSetting, n as teardownOwnedIosSim, t as teardownOwnedAvd } from "./teardown-CAVcWeRD.mjs";
7
- import { l as releaseWorkspaceLeases } from "./device-lease-r7yEQ1R8.mjs";
8
- import { i as endRecordedSession } from "./device-remote-BTUqbl0i.mjs";
9
- import { t as clearNamedPorts } from "./named-ports-DH9SXd0f.mjs";
10
- import { r as stopTunnel, t as resolveSupervisorTarget } from "./ownership-CVY9cqCr.mjs";
1
+ import { E as ownership_claim_exports, R as projectDeviceSlots, T as acquireAvdClaim, f as getProject, v as removeProject, w as process_identity_exports } from "./config-B7iyKWkL.mjs";
2
+ import { h as workspaceDir, r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
3
+ import { a as clearRemoteSession, i as clearManagedMetroTunnel, s as readMetroTunnel, u as readRemoteSessionId } from "./state-DZobzxLW.mjs";
4
+ import { a as resolveProjectMetro, i as pidExists, n as killMetroTree } from "./metro-C7bcJ0uo.mjs";
5
+ import { n as verifyCollectorOwnership } from "./ownership-Cp52QAK1.mjs";
6
+ import { S as resolveEasCliBin, l as parkedMaxSetting, n as teardownOwnedIosSim, t as teardownOwnedAvd } from "./teardown-5J5UXz2P.mjs";
7
+ import { l as releaseWorkspaceLeases } from "./device-lease-Ffz_M5t0.mjs";
8
+ import { i as endRecordedSession } from "./device-remote-BprxZp-m.mjs";
9
+ import { t as clearNamedPorts } from "./named-ports-DzMOlmaX.mjs";
10
+ import { r as stopTunnel, t as resolveSupervisorTarget } from "./ownership-D5vkdm8H.mjs";
11
11
  import { existsSync, rmSync } from "node:fs";
12
- //#region src/reclaim.ts
12
+ //#region src/devices/reclaim.ts
13
13
  async function reapCollectors(root, { verify = verifyCollectorOwnership, collectors }) {
14
14
  const skippedDevices = [];
15
15
  const failedDevices = [];
@@ -1,12 +1,12 @@
1
- import { F as deviceSlotPlatforms, I as parseDeviceSlotKey, f as getProject } from "./config-DMP7L7H6.mjs";
2
- import { a as findProjectRoot } from "./project-B_SDt4ip.mjs";
3
- import { d as readWorkspaceLaunches } from "./state-CnWzvCWP.mjs";
4
- import { i as resolveProjectMetro } from "./metro-ato6ef3J.mjs";
5
- import { l as phaseLine } from "./command-output-BuIb_ZOI.mjs";
6
- import { N as resolveOwnedAvdSerial } from "./android-DJWiTBkz.mjs";
7
- import { u as androidAppProcess, y as iosAppProcess } from "./app-install--PAocWvq.mjs";
8
- import { x as resolveOwnedIosSim } from "./ios-Deh5js5V.mjs";
9
- import { n as nativeRunCommand } from "./slot-launch-BpHiHH6A.mjs";
1
+ import { I as deviceSlotPlatforms, L as parseDeviceSlotKey, f as getProject } from "./config-B7iyKWkL.mjs";
2
+ import { a as findProjectRoot } from "./project-DDZWf_16.mjs";
3
+ import { d as readWorkspaceLaunches } from "./state-DZobzxLW.mjs";
4
+ import { a as resolveProjectMetro } from "./metro-C7bcJ0uo.mjs";
5
+ import { I as resolveOwnedAvdSerial } from "./android-DWssqHQ8.mjs";
6
+ import { l as phaseLine } from "./command-output-B3ycpsYv.mjs";
7
+ import { u as androidAppProcess, y as iosAppProcess } from "./app-install-DJg7bVv-.mjs";
8
+ import { x as resolveOwnedIosSim } from "./ios-lEJ5pKsq.mjs";
9
+ import { n as nativeRunCommand } from "./slot-launch-DbLvyrup.mjs";
10
10
  import chalk from "chalk";
11
11
  import { WebSocket } from "ws";
12
12
  //#region src/engine/reload.ts
@@ -1,6 +1,6 @@
1
1
  import { i as __require, t as __commonJSMin } from "./rolldown-runtime-BsOwBuO_.mjs";
2
2
  import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
3
- import { C as projectMetroSharedCache } from "./settings-kO2ZqIKy.mjs";
3
+ import { C as projectMetroSharedCache } from "./settings-BXXorVM2.mjs";
4
4
  import { a as metroStoreRoot, o as registerMetroStore, t as appendCacheStore } from "./metro-store-CDDZHtPl.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import { isAbsolute, join, relative, sep } from "node:path";
@@ -1,9 +1,9 @@
1
- import { t as getExecutor } from "./exec-CyylIdq9.mjs";
1
+ import { t as getExecutor } from "./exec-B29XNuhP.mjs";
2
2
  import { r as createNdjsonWriter } from "./ndjson-BZwI1NBv.mjs";
3
- import { l as resolvePackageJson } from "./project-B_SDt4ip.mjs";
3
+ import { l as resolvePackageJson } from "./project-DDZWf_16.mjs";
4
4
  import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
5
- import { n as stripAnsi, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
6
- import { C as projectMetroSharedCache } from "./settings-kO2ZqIKy.mjs";
5
+ import { n as stripAnsi, t as createLineReader } from "./process-output-Dl5uKE03.mjs";
6
+ import { C as projectMetroSharedCache } from "./settings-BXXorVM2.mjs";
7
7
  import { a as metroStoreRoot, i as metroStoreConfirmedRoot, n as expoMetroConfigPath, o as registerMetroStore, r as expoMetroStoreEnv } from "./metro-store-CDDZHtPl.mjs";
8
8
  import { accessSync, constants, existsSync, readFileSync } from "node:fs";
9
9
  import { dirname, join, parse } from "node:path";
@@ -14,10 +14,20 @@ function delay(ms) {
14
14
  if (typeof timer.unref === "function") timer.unref();
15
15
  });
16
16
  }
17
- function expoBinPath(root) {
17
+ function resolveExpoBin(root) {
18
18
  const fromPackage = expoBinFromPackage(resolvePackageJson(root, "expo"));
19
- if (fromPackage) return fromPackage;
20
- return findBinUpward(root, "expo");
19
+ if (fromPackage) return {
20
+ path: fromPackage,
21
+ source: "package"
22
+ };
23
+ const shim = findBinUpward(root, "expo");
24
+ return shim ? {
25
+ path: shim,
26
+ source: "shim"
27
+ } : null;
28
+ }
29
+ function expoBinPath(root) {
30
+ return resolveExpoBin(root)?.path ?? null;
21
31
  }
22
32
  function expoSdkMajor(root) {
23
33
  const packageJsonPath = resolvePackageJson(root, "expo");
@@ -192,12 +202,13 @@ function resolveMetroStoreInjection(root, { log, env }) {
192
202
  });
193
203
  return additions;
194
204
  }
195
- async function startExpoServer({ root, port, logsDir, writer = null, spawnFn = null, killTimeoutMs = 5e3, tunnel = false, resetCache = false, onTunnelUrl = null }) {
196
- const bin = expoBinPath(root);
197
- if (!bin) {
205
+ async function startExpoServer({ root, port, logsDir, writer = null, spawnFn = null, killTimeoutMs = 5e3, tunnel = false, resetCache = false, onTunnelUrl = null, platform = process.platform }) {
206
+ const resolved = resolveExpoBin(root);
207
+ if (!resolved) {
198
208
  const refusal = expoBinRefusal(root);
199
209
  throw supervisorError("STIM_EXPO_BIN", refusal.message, refusal.remedy);
200
210
  }
211
+ const bin = resolved.path;
201
212
  const log = writer || createNdjsonWriter(join(logsDir, "metro.ndjson"));
202
213
  const spawn = spawnFn || ((cmd, args, opts) => getExecutor().spawn(cmd, args, opts));
203
214
  const args = [
@@ -211,7 +222,8 @@ async function startExpoServer({ root, port, logsDir, writer = null, spawnFn = n
211
222
  log,
212
223
  env: process.env
213
224
  });
214
- const child = spawn(bin, args, {
225
+ const [command, commandArgs] = platform === "win32" && resolved.source === "package" ? [process.execPath, [bin, ...args]] : [bin, args];
226
+ const child = spawn(command, commandArgs, {
215
227
  cwd: root,
216
228
  stdio: [
217
229
  "ignore",
@@ -0,0 +1,2 @@
1
+ import { p as startExpoServer } from "./server-expo-BVAA1OqJ.mjs";
2
+ export { startExpoServer };
@@ -1,5 +1,5 @@
1
- import { d as getConfigPath, g as loadConfig, m as getRepoSettings, p as getProjectSettings } from "./config-DMP7L7H6.mjs";
2
- import { g as repoRoot, s as gitCommonDir } from "./worktree-DJnBbQZ9.mjs";
1
+ import { d as getConfigPath, g as loadConfig, m as getRepoSettings, p as getProjectSettings } from "./config-B7iyKWkL.mjs";
2
+ import { g as repoRoot, s as gitCommonDir } from "./worktree-FG_ZKKdb.mjs";
3
3
  import { createHash } from "node:crypto";
4
4
  import { isAbsolute } from "node:path";
5
5
  import { existsSync, readFileSync, realpathSync, statSync } from "fs";
@@ -29,7 +29,10 @@ function compilerCacheFallbackMessage({ fallback, compilerCache, file = null })
29
29
  return `${fallback.key}${origin ? ` in ${origin}` : ""} ${fallback.reason}. ${backend}`;
30
30
  }
31
31
  function optimizationBuildProfile(platform, options) {
32
- const selected = platform === "ios" ? options.ios : { pch: options.android.pch };
32
+ const selected = platform === "ios" ? {
33
+ ...options.ios,
34
+ swiftCompilationCache: options.ios.swiftCompilationCache ?? false
35
+ } : { pch: options.android.pch };
33
36
  const defaults = platform === "ios" ? {
34
37
  compilationCache: true,
35
38
  swiftCompilationCache: false,
@@ -82,7 +85,7 @@ function resolveOptimizations(settings = {}, env = process.env) {
82
85
  metroWarmup: optimizationBoolean(settings, "metroWarmup"),
83
86
  ios: {
84
87
  compilationCache: optimizationBoolean(settings, "ios.compilationCache"),
85
- swiftCompilationCache: optimizationBoolean(settings, "ios.swiftCompilationCache", false),
88
+ swiftCompilationCache: optimizationValue(settings, "ios.swiftCompilationCache") === void 0 ? null : optimizationBoolean(settings, "ios.swiftCompilationCache"),
86
89
  prefixMapping: optimizationBoolean(settings, "ios.prefixMapping")
87
90
  },
88
91
  android: {
@@ -174,7 +177,7 @@ function detectProviders(onPath) {
174
177
  return MANAGED_PROVIDERS.filter((p) => onPath(p));
175
178
  }
176
179
  //#endregion
177
- //#region src/settings.ts
180
+ //#region src/workspace/settings.ts
178
181
  function isPlainObject(v) {
179
182
  return v !== null && typeof v === "object" && !Array.isArray(v);
180
183
  }
@@ -1,7 +1,7 @@
1
- import { f as getProject } from "./config-DMP7L7H6.mjs";
2
- import { r as readWorkspaceState } from "./workspace-state-WVwWw_hB.mjs";
3
- import { h as deviceShellArg } from "./app-install--PAocWvq.mjs";
4
- import { n as fileLeaseIo } from "./device-lease-r7yEQ1R8.mjs";
1
+ import { f as getProject } from "./config-B7iyKWkL.mjs";
2
+ import { r as readWorkspaceState } from "./workspace-state-BT5E3SA2.mjs";
3
+ import { h as deviceShellArg } from "./app-install-DJg7bVv-.mjs";
4
+ import { n as fileLeaseIo } from "./device-lease-Ffz_M5t0.mjs";
5
5
  //#region src/engine/slot-launch.ts
6
6
  function launchSlotScope(root, slot = "default") {
7
7
  if (slot !== "default") return slot;