stim 1.16.0 → 1.17.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 (107) hide show
  1. package/dist/{activity-BxwdD81S.mjs → activity-IRvJY_ru.mjs} +23 -3
  2. package/dist/{agent-device-usage-output-Dpih1Tfa.mjs → agent-device-usage-output-BK41vnzN.mjs} +3 -3
  3. package/dist/{android-Ift4kVvt.mjs → android--GorydsK.mjs} +679 -317
  4. package/dist/{android-B_NumVyQ.mjs → android-B_YNZy61.mjs} +7 -43
  5. package/dist/{android-r2rBL8kV.mjs → android-DE4v59Mb.mjs} +12 -3
  6. package/dist/{android-cas-8U4DPqeR.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
  7. package/dist/{app-install-CKWdbXIX.mjs → app-install-VPkI5WEg.mjs} +6 -5
  8. package/dist/{budget-DjrURfQn.mjs → budget-DM984mnd.mjs} +34 -18
  9. package/dist/{build-plan-DjeSb2Xl.mjs → build-plan-CmQCoyT-.mjs} +345 -86
  10. package/dist/{build-slots-rUk77xqh.mjs → build-slots-41v_d2x9.mjs} +35 -25
  11. package/dist/{cli-BkYZ_6hy.mjs → cli-Daxug5-K.mjs} +17 -17
  12. package/dist/cli.mjs +1 -1
  13. package/dist/collector-run.mjs +3 -3
  14. package/dist/{command-output-DnJMdEY-.mjs → command-output-CDAIFD-8.mjs} +3 -3
  15. package/dist/{created-devices-D5owjN4C.mjs → created-devices-CpvzBL25.mjs} +1 -1
  16. package/dist/{dependency-state-B6cMXZab.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
  17. package/dist/{deps-urbmfXig.mjs → deps-DNWaQs4V.mjs} +1 -1
  18. package/dist/{dev-client-CroAIjjj.mjs → dev-client-B-XC4uRH.mjs} +2 -2
  19. package/dist/{device-DZQjF7H5.mjs → device-C8IOoJPv.mjs} +7 -7
  20. package/dist/device-capacity-D0GWHnTM.mjs +580 -0
  21. package/dist/device-host-worker.mjs +436 -154
  22. package/dist/{device-ios-BadmeL2V.mjs → device-ios-Bc7vbGwl.mjs} +75 -44
  23. package/dist/{device-lease-D-hLqx1b.mjs → device-lease-DpoS36_u.mjs} +2 -2
  24. package/dist/{device-lease-run-CqjShqWW.mjs → device-lease-run-B8YltIH_.mjs} +3 -3
  25. package/dist/{device-pool-CUaEWMMm.mjs → device-pool-3o7s5lo4.mjs} +2 -2
  26. package/dist/{device-remote-D5WVWqOq.mjs → device-remote-hFSkpfQu.mjs} +12 -12
  27. package/dist/{doctor-Cimf-gGB.mjs → doctor-Cnk9d7Hm.mjs} +32 -51
  28. package/dist/{error-diagnostics-B9L4Ae0x.mjs → error-diagnostics-C-NMnhrk.mjs} +7 -7
  29. package/dist/{gc-Bqy4bjEu.mjs → gc-DxCL2A46.mjs} +308 -26
  30. package/dist/{gradle-BsO1MdsH.mjs → gradle-D7-L2Th3.mjs} +3 -3
  31. package/dist/{guide-B_uyKTxW.mjs → guide-DjrTQGik.mjs} +1662 -565
  32. package/dist/{guide-status-CjEZMAD4.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
  33. package/dist/hosted-android-DwLS4Mse.mjs +32 -0
  34. package/dist/{hosted-client-a-WmqE2L.mjs → hosted-client-wk1W_CNW.mjs} +2 -3
  35. package/dist/hosted-ios-aMo7Cljf.mjs +15 -0
  36. package/dist/{hosted-logs-D5g041Q3.mjs → hosted-logs-DqYmWtXc.mjs} +16 -16
  37. package/dist/{hosted-macos-BSZyIb3y.mjs → hosted-macos-dlHXEeF5.mjs} +4 -4
  38. package/dist/{hosted-ios-CIWelIqf.mjs → hosted-native-C9xJ9rpA.mjs} +77 -42
  39. package/dist/{idle-DYVymG92.mjs → idle-B2m-Ovod.mjs} +122 -58
  40. package/dist/{idle-shutdown-CTsDnAde.mjs → idle-shutdown-_3oOV1V_.mjs} +25 -17
  41. package/dist/{in-use-DvBw0Kxo.mjs → in-use-CvGOUn-x.mjs} +11 -11
  42. package/dist/{ios-aq3QoGI3.mjs → ios-DE6duQoz.mjs} +170 -88
  43. package/dist/{ios-BaInn3sW.mjs → ios-DSfnPfse.mjs} +4 -4
  44. package/dist/{ios-device-FfCN_C8p.mjs → ios-device-pAN4t54-.mjs} +1 -1
  45. package/dist/ios-state-8L3lgum6.mjs +89 -0
  46. package/dist/{launch-verify-2DBRizjo.mjs → launch-verify-lTnWZikR.mjs} +2 -2
  47. package/dist/{logs-CHEVK8zD.mjs → logs-DUoKlDoS.mjs} +36 -23
  48. package/dist/{client-BTY686R6.mjs → machines-C2XiNwh9.mjs} +278 -20
  49. package/dist/{macos-CSYEAFmF.mjs → macos-32po3kUq.mjs} +14 -14
  50. package/dist/macos-run.mjs +1 -1
  51. package/dist/maintenance-run.mjs +2 -2
  52. package/dist/{metro-BeK1ZPz1.mjs → metro-g8NqiJp-.mjs} +1 -1
  53. package/dist/{metro-gateway-BJ-rxQAB.mjs → metro-gateway-DmslUM30.mjs} +22 -3
  54. package/dist/{named-ports-Bk_YXEmE.mjs → named-ports-C8m8EQs2.mjs} +2 -2
  55. package/dist/{native-run-NaBrRFtQ.mjs → native-run-D1Q56rAD.mjs} +17 -6
  56. package/dist/{native-runtime-DBzRnEKS.mjs → native-runtime-DhJI3IVQ.mjs} +6 -6
  57. package/dist/offload-worker.mjs +8 -8
  58. package/dist/{teardown-CL6vDs2Y.mjs → ownership-BMLqyBgJ.mjs} +603 -26
  59. package/dist/{ownership-DiA16AsN.mjs → ownership-DyRQru0q.mjs} +2 -2
  60. package/dist/{ports-R2k4Knz3.mjs → ports-4nYqxPWC.mjs} +2 -2
  61. package/dist/{prebuild-D2fsca_Z.mjs → prebuild-D7RUMkwN.mjs} +3 -3
  62. package/dist/{preview-DhVbvPAZ.mjs → preview-CxPRIEht.mjs} +7 -7
  63. package/dist/{project-Du91Ilvc.mjs → project-D47Rh0ly.mjs} +7 -2
  64. package/dist/{recordings-BIXOzVnr.mjs → recordings-BNgsD1Tr.mjs} +1 -1
  65. package/dist/{reload-rM9jV1fz.mjs → reload-qZei6iWn.mjs} +62 -35
  66. package/dist/{remote-cache-C8-V13XN.mjs → remote-cache-Ci4DQYYj.mjs} +3 -3
  67. package/dist/{run-f4vI6EnK.mjs → run-CkE9y0nc.mjs} +1 -1
  68. package/dist/{server-bare-CpPGmnmO.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
  69. package/dist/{server-expo-MC0rHlOC.mjs → server-expo-CHTyXD0G.mjs} +2 -2
  70. package/dist/server-expo-CeakhI8P.mjs +2 -0
  71. package/dist/{settings-oTSkkNrM.mjs → settings-Cfd-0r2d.mjs} +10 -9
  72. package/dist/{settings-ZkDzkzvB.mjs → settings-SR9OmW9h.mjs} +3 -3
  73. package/dist/settings.schema.json +42 -13
  74. package/dist/{simslim-B8-7AoTI.mjs → simslim-BWNrc3M3.mjs} +3 -3
  75. package/dist/{slot-launch-B8VrHxn1.mjs → slot-launch-DmjBmpQV.mjs} +8 -8
  76. package/dist/{start-CX8Ig-U2.mjs → start-BopZcr4n.mjs} +1 -1
  77. package/dist/{start-ClDfwXa4.mjs → start-uee1wWjY.mjs} +11 -11
  78. package/dist/{state-DcW6vOd_.mjs → state-BKa8wNN5.mjs} +1 -1
  79. package/dist/{state-3DwSQIBK.mjs → state-DyaNTgfR.mjs} +1 -1
  80. package/dist/{state-C1jB7Q8q.mjs → state-PeQiJuIu.mjs} +2 -2
  81. package/dist/{stats-CEZ_i5je.mjs → stats-Bq4fJOdB.mjs} +7 -4
  82. package/dist/{status-BuvBFeII.mjs → status-CzS4bPO9.mjs} +4 -4
  83. package/dist/{status-Cs7VLg9D.mjs → status-dXX2JX1C.mjs} +125 -35
  84. package/dist/{stop-Dt_dM16A.mjs → stop-BCwvvs7F.mjs} +2 -2
  85. package/dist/{stop-Bffozsac.mjs → stop-BjizrQwv.mjs} +48 -27
  86. package/dist/{stop-B0Yxtmiy.mjs → stop-Cr1d8DSE.mjs} +4 -4
  87. package/dist/{stop-cause-CidxIqup.mjs → stop-cause-rhmGfwvt.mjs} +1 -1
  88. package/dist/supervisor-run.d.mts +7 -4
  89. package/dist/supervisor-run.mjs +26 -28
  90. package/dist/{support-D4aYJniO.mjs → support-BJPgYCu-.mjs} +44 -19
  91. package/dist/{support-CAP8qDUF.mjs → support-F9-sr0Oi.mjs} +6 -6
  92. package/dist/{toolchain-DkUflduf.mjs → toolchain-CNIBTIOv.mjs} +7 -7
  93. package/dist/{warm-progress-CpGv3Wb6.mjs → warm-progress-DF4JRvYI.mjs} +3 -3
  94. package/dist/watchman-APYjXSQa.mjs +48 -0
  95. package/dist/{web-DWUaMp8P.mjs → web-exQtGkoc.mjs} +12 -13
  96. package/dist/web-run.mjs +4 -4
  97. package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
  98. package/dist/{workspace-state-B8-aJ1_5.mjs → workspace-state-DqcCbpE7.mjs} +2 -2
  99. package/dist/{workspaces-BV4pdHFz.mjs → workspaces-Bcib97-6.mjs} +3 -3
  100. package/dist/{worktree-jnG8Iph5.mjs → worktree-Dc98cE6_.mjs} +1 -1
  101. package/dist/{worktree-K-xj9Db0.mjs → worktree-ZpZR3S1k.mjs} +141 -40
  102. package/package.json +5 -5
  103. package/dist/device-capacity-BHwxNBlu.mjs +0 -136
  104. package/dist/ios-state-DS5UpYTH.mjs +0 -48
  105. package/dist/machines-BIBUdhpj.mjs +0 -265
  106. package/dist/ownership-hCkPzGmr.mjs +0 -571
  107. package/dist/server-expo-CVqO2c35.mjs +0 -2
@@ -1,10 +1,10 @@
1
- import { h as shortUdid, l as phaseLine } from "./command-output-DnJMdEY-.mjs";
2
- import { x as workspaceLogsDir } from "./workspace-state-B8-aJ1_5.mjs";
3
- import { k as parseIosSimulatorApp } from "./ios-BaInn3sW.mjs";
4
- import { x as describeDiagnostic } from "./toolchain-DkUflduf.mjs";
5
- import { c as unknownIosDeviceTypeRefusal, l as unknownIosRuntimeRefusal, r as layerNote } from "./device-capacity-BHwxNBlu.mjs";
6
- import { l as parseDeviceWait } from "./device-lease-run-CqjShqWW.mjs";
7
- import { t as IosDeviceMismatchError } from "./device-ios-BadmeL2V.mjs";
1
+ import { h as shortUdid, l as phaseLine } from "./command-output-CDAIFD-8.mjs";
2
+ import { x as workspaceLogsDir } from "./workspace-state-DqcCbpE7.mjs";
3
+ import { k as parseIosSimulatorApp } from "./ios-DSfnPfse.mjs";
4
+ import { x as describeDiagnostic } from "./toolchain-CNIBTIOv.mjs";
5
+ import { d as unknownIosDeviceTypeRefusal, f as unknownIosRuntimeRefusal, o as layerNote, t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-D0GWHnTM.mjs";
6
+ import { l as parseDeviceWait } from "./device-lease-run-B8YltIH_.mjs";
7
+ import { t as IosDeviceMismatchError } from "./device-ios-Bc7vbGwl.mjs";
8
8
  import { basename, join } from "node:path";
9
9
  import chalk from "chalk";
10
10
  function buildLogFile(root) {
@@ -44,7 +44,7 @@ function resolveDeviceType(flag, settings) {
44
44
  function resolveRuntime(flag, settings) {
45
45
  return (typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null) || iosStringSetting(settings, "runtime");
46
46
  }
47
- function resolveSimulatorAppFlag(flag, physical, remoteBackend) {
47
+ function resolveSimulatorAppFlag(flag, physical, remoteBackend, automatic = false) {
48
48
  if (flag === void 0) return {};
49
49
  let simulatorApp;
50
50
  try {
@@ -55,7 +55,7 @@ function resolveSimulatorAppFlag(flag, physical, remoteBackend) {
55
55
  message: error.message
56
56
  } };
57
57
  }
58
- if (physical || remoteBackend) return { refusal: {
58
+ if (physical || remoteBackend && !automatic) return { refusal: {
59
59
  code: "STIM_BAD_ARG",
60
60
  message: "--simulator-app only applies to a local owned iOS simulator.",
61
61
  remedy: "Drop --simulator-app when using a physical or remote device."
@@ -175,27 +175,52 @@ function printDiagnostics(note, result) {
175
175
  }
176
176
  function resolveIosWait(opts, physical) {
177
177
  const noWait = opts.wait === false;
178
- const waitFlagged = opts.wait !== void 0;
179
178
  if (opts.waitConflict) return { failure: {
180
179
  code: "STIM_BAD_ARG",
181
180
  message: "--wait and --no-wait ask for opposite things.",
182
- remedy: "Pass `--wait <seconds>` to wait for the lease, or `--no-wait` to install without one."
183
- } };
184
- if (waitFlagged && !physical) return { failure: {
185
- code: "STIM_BAD_ARG",
186
- message: "--wait and --no-wait only apply to a `--device` run.",
187
- remedy: "This workspace owns its simulator, so nothing contends for it. Drop the flag, or pass `--device`."
181
+ remedy: "Pass only one of `--wait <seconds>` and `--no-wait`."
188
182
  } };
189
183
  const waitParsed = parseDeviceWait(noWait ? void 0 : opts.wait);
190
184
  if ("error" in waitParsed) return { failure: {
191
185
  code: "STIM_BAD_ARG",
192
186
  message: waitParsed.error,
193
- remedy: "Pass a whole number of seconds, e.g. --wait 90. `--wait 0` refuses a leased device at once."
187
+ remedy: "Pass a whole number of seconds, e.g. --wait 90. `--wait 0` refuses a busy lease or device slot at once."
194
188
  } };
195
189
  return {
196
190
  waitSeconds: waitParsed.seconds,
197
- noWait
191
+ noWait,
192
+ checkCapacity: !physical && (noWait || waitParsed.seconds === 0),
193
+ deviceSlotWaitMs: noWait ? 0 : opts.wait === void 0 && !physical ? DEFAULT_DEVICE_SLOT_WAIT_MS : waitParsed.seconds * 1e3
194
+ };
195
+ }
196
+ function createIosDeviceWaitRun(stats, progress, signal) {
197
+ const controller = new AbortController();
198
+ let waiting = false;
199
+ let boot;
200
+ let outcome;
201
+ return {
202
+ policy: {
203
+ signal: signal ? AbortSignal.any([controller.signal, signal]) : controller.signal,
204
+ waitingFor(info) {
205
+ waiting = info !== null;
206
+ progress.waitingFor(info, "device-slot");
207
+ },
208
+ onWait: stats.addDeviceSlotWaitMs
209
+ },
210
+ record(next) {
211
+ if (waiting) outcome = next;
212
+ else stats.record(next);
213
+ },
214
+ booting(pending) {
215
+ boot ??= pending?.done;
216
+ },
217
+ async finish() {
218
+ const queued = waiting;
219
+ controller.abort();
220
+ if (queued) await boot?.catch(() => {});
221
+ if (outcome) stats.record(outcome);
222
+ }
198
223
  };
199
224
  }
200
225
  //#endregion
201
- export { simulatorBuildArch as _, deviceShortName as a, isReleaseConfiguration as c, printDiagnostics as d, resolveConfiguration as f, resolveSimulatorAppFlag as g, resolveRuntime as h, deviceModelRefusal as i, ownedSimFailure as l, resolveIosWait as m, buildLogFile as n, iosConfigurationSetting as o, resolveDeviceType as p, deviceLabel as r, iosProviderRunOptions as s, appNameFromPath as t, podAction as u, xcodeFailureReport as v };
226
+ export { resolveSimulatorAppFlag as _, deviceModelRefusal as a, iosProviderRunOptions as c, podAction as d, printDiagnostics as f, resolveRuntime as g, resolveIosWait as h, deviceLabel as i, isReleaseConfiguration as l, resolveDeviceType as m, buildLogFile as n, deviceShortName as o, resolveConfiguration as p, createIosDeviceWaitRun as r, iosConfigurationSetting as s, appNameFromPath as t, ownedSimFailure as u, simulatorBuildArch as v, xcodeFailureReport as y };
@@ -1,8 +1,8 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { C as emulatorFailureRemedy, D as hostSystemImageArch, K as profileNeedsFoldFeature, N as memoizeEmulatorProbe, S as emulatorDiskSpaceRemedy, T as findBuildTool, W as pickDefaultSystemImage, c as androidPoolNoCandidatesRefusal, l as androidSystemImageAbi, o as androidHome, s as androidPoolCandidates, w as extractEmulatorFailure } from "./android-B_NumVyQ.mjs";
3
- import { C as pickDevClientScheme } from "./app-install-CKWdbXIX.mjs";
4
- import { o as unknownAndroidDeviceProfileRefusal, r as layerNote, s as unknownAndroidSystemImageRefusal } from "./device-capacity-BHwxNBlu.mjs";
5
- import { t as devClientScheme } from "./dev-client-CroAIjjj.mjs";
2
+ import { C as emulatorFailureRemedy, D as hostSystemImageArch, K as profileNeedsFoldFeature, N as memoizeEmulatorProbe, S as emulatorDiskSpaceRemedy, T as findBuildTool, W as pickDefaultSystemImage, c as androidPoolNoCandidatesRefusal, l as androidSystemImageAbi, o as androidHome, s as androidPoolCandidates, w as extractEmulatorFailure } from "./android-B_YNZy61.mjs";
3
+ import { l as unknownAndroidDeviceProfileRefusal, o as layerNote, u as unknownAndroidSystemImageRefusal } from "./device-capacity-D0GWHnTM.mjs";
4
+ import { T as pickDevClientScheme } from "./app-install-VPkI5WEg.mjs";
5
+ import { t as devClientScheme } from "./dev-client-B-XC4uRH.mjs";
6
6
  import { existsSync, readFileSync, readdirSync } from "node:fs";
7
7
  import { relative } from "node:path";
8
8
  //#region src/commands/android/support.ts
@@ -297,8 +297,8 @@ async function pooledAndroidDevice({ root, selectPool, listDevices, isEmulatorDe
297
297
  owned: false
298
298
  } };
299
299
  }
300
- function androidBuildOptions({ release, physical, device, variant, deviceAbi, compiler, buildProfile, targetAbiOnly = true }) {
301
- let abi = null;
300
+ function androidBuildOptions({ release, physical, device, variant, deviceAbi, compiler, buildProfile, targetAbiOnly = true, hostedAbi = null }) {
301
+ let abi = targetAbiOnly ? hostedAbi : null;
302
302
  if (targetAbiOnly && !release && physical && device.serial) abi = deviceAbi(device.serial);
303
303
  if (targetAbiOnly && !release && !physical) abi = androidSystemImageAbi(device.systemImage);
304
304
  const runOptions = {};
@@ -1,13 +1,13 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { r as register } from "./cache-manifest-DnUHBJaU.mjs";
3
3
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { a as formatElapsed, l as phaseLine } from "./command-output-DnJMdEY-.mjs";
5
- import { Z as resolveOptimizations } from "./settings-oTSkkNrM.mjs";
6
- import { p as resolvePackageJson } from "./project-Du91Ilvc.mjs";
7
- import { _ as workspaceDerivedData, f as sharedCcache$1, p as sharedCompilationCache$1, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
4
+ import { a as formatElapsed, l as phaseLine } from "./command-output-CDAIFD-8.mjs";
5
+ import { Z as resolveOptimizations } from "./settings-Cfd-0r2d.mjs";
6
+ import { m as resolvePackageJson } from "./project-D47Rh0ly.mjs";
7
+ import { _ as workspaceDerivedData, f as sharedCcache$1, p as sharedCompilationCache$1, x as workspaceLogsDir$1 } from "./workspace-state-DqcCbpE7.mjs";
8
8
  import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
9
- import { o as androidHome } from "./android-B_NumVyQ.mjs";
10
- import { t as cleanLine } from "./server-expo-MC0rHlOC.mjs";
9
+ import { o as androidHome } from "./android-B_YNZy61.mjs";
10
+ import { t as cleanLine } from "./server-expo-CHTyXD0G.mjs";
11
11
  import { createRequire } from "node:module";
12
12
  import { createHash } from "node:crypto";
13
13
  import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
@@ -452,7 +452,7 @@ function compilationPrefixMappings(workspaceRoot, derivedDataPath) {
452
452
  const mappings = [prefixMapping(source)];
453
453
  const rel = relative(source, derived);
454
454
  if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) mappings.push(`${derived}=/^derived-data`);
455
- return mappings.join(" ");
455
+ return mappings.map((mapping) => /[\s"\\]/.test(mapping) ? `"${mapping.replace(/["\\]/g, "\\$&")}"` : mapping).join(" ");
456
456
  }
457
457
  function ccacheEnabled(podfileProperties) {
458
458
  if (!podfileProperties || typeof podfileProperties !== "object") return false;
@@ -1,9 +1,9 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
3
3
  import { o as pullRequestLookups } from "./pull-request-pxnDCQzn.mjs";
4
- import { at as gitCommonDirOnDisk } from "./settings-oTSkkNrM.mjs";
5
- import { D as discoverAgentSessions, E as attributeAgentSessions, T as agentKey, a as updateWorkspaceState, u as ensureWorkspaceStorage, v as workspaceDir, w as withDirLock } from "./workspace-state-B8-aJ1_5.mjs";
6
- import { I as ownedAvdDirectory } from "./android-B_NumVyQ.mjs";
4
+ import { at as gitCommonDirOnDisk } from "./settings-Cfd-0r2d.mjs";
5
+ import { D as discoverAgentSessions, E as attributeAgentSessions, T as agentKey, a as updateWorkspaceState, u as ensureWorkspaceStorage, v as workspaceDir, w as withDirLock } from "./workspace-state-DqcCbpE7.mjs";
6
+ import { I as ownedAvdDirectory } from "./android-B_YNZy61.mjs";
7
7
  import { randomUUID } from "node:crypto";
8
8
  import { existsSync, mkdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
9
9
  import { basename, dirname, join } from "node:path";
@@ -0,0 +1,48 @@
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ //#region src/watchman.ts
3
+ /** Runs one watchman command with `--no-spawn`, so Stim never starts a daemon, and parses its JSON answer. */
4
+ const runWatchman = async (args, timeoutMs) => JSON.parse(await getExecutor().runFileAsync("watchman", ["--no-spawn", ...args], { timeoutMs }));
5
+ function parseWatchRoots(payload) {
6
+ const roots = payload?.roots;
7
+ if (!Array.isArray(roots)) return null;
8
+ return roots.filter((root) => typeof root === "string");
9
+ }
10
+ function parseSubscriberNames(payload) {
11
+ if (!payload || typeof payload !== "object" || "error" in payload) return null;
12
+ const subscribers = payload.subscribers;
13
+ if (subscribers === void 0) return [];
14
+ if (!Array.isArray(subscribers)) return null;
15
+ const names = [];
16
+ for (const subscriber of subscribers) {
17
+ const name = subscriber?.info?.name;
18
+ if (typeof name !== "string") return null;
19
+ names.push(name);
20
+ }
21
+ return names;
22
+ }
23
+ function parseTriggerCount(payload) {
24
+ const triggers = payload?.triggers;
25
+ return Array.isArray(triggers) ? triggers.length : null;
26
+ }
27
+ function parseWatchmanPid(payload) {
28
+ const pid = payload?.pid;
29
+ return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : null;
30
+ }
31
+ /** The connected clients in a `debug-status` answer, or null when the answer does not list them. */
32
+ function parseWatchmanClients(payload) {
33
+ if (!payload || typeof payload !== "object" || "error" in payload) return null;
34
+ const clients = payload.clients;
35
+ if (!Array.isArray(clients)) return null;
36
+ const parsed = [];
37
+ for (const client of clients) {
38
+ const peer = client?.peer;
39
+ if (typeof peer?.pid !== "number") return null;
40
+ parsed.push({
41
+ pid: peer.pid,
42
+ name: typeof peer.name === "string" ? peer.name : null
43
+ });
44
+ }
45
+ return parsed;
46
+ }
47
+ //#endregion
48
+ export { parseWatchmanPid as a, parseWatchmanClients as i, parseTriggerCount as n, runWatchman as o, parseWatchRoots as r, parseSubscriberNames as t };
@@ -1,23 +1,22 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { E as upsertProject, p as getProject } from "./config-D0DbpZtM.mjs";
3
3
  import { n as windowsLauncherArgs } from "./detached-entry-CiTEgMR1.mjs";
4
- import { f as refuseNoProject, l as phaseLine } from "./command-output-DnJMdEY-.mjs";
5
- import { P as resolveSettings, R as settingShapeErrors, S as metroPortSetting, U as webSettings, a as SETTING_SHAPE_REMEDY, gt as repoRoot, it as gitCommonDir } from "./settings-oTSkkNrM.mjs";
6
- import { a as findCommandWorkspace, c as isPackageResolvable, r as detectIsExpo } from "./project-Du91Ilvc.mjs";
7
- import { l as resolveProjectMetro } from "./metro-BeK1ZPz1.mjs";
8
- import { i as recordWorkspaceUse, r as readWorkspaceState, v as workspaceDir, x as workspaceLogsDir } from "./workspace-state-B8-aJ1_5.mjs";
9
- import { d as webLogFile, o as readWebRecord, p as webSupervisorLogFile, r as cdpEndpoint, s as updateWebRecord } from "./state-C1jB7Q8q.mjs";
4
+ import { f as refuseNoProject, l as phaseLine } from "./command-output-CDAIFD-8.mjs";
5
+ import { P as resolveSettings, R as settingShapeErrors, U as webSettings, gt as repoRoot, i as SETTING_SHAPE_REMEDY, it as gitCommonDir, x as metroPortSetting } from "./settings-Cfd-0r2d.mjs";
6
+ import { l as isPackageResolvable, o as findCommandWorkspace, r as detectIsExpo } from "./project-D47Rh0ly.mjs";
7
+ import { l as resolveProjectMetro } from "./metro-g8NqiJp-.mjs";
8
+ import { i as recordWorkspaceUse, r as readWorkspaceState, v as workspaceDir, x as workspaceLogsDir } from "./workspace-state-DqcCbpE7.mjs";
9
+ import { d as webLogFile, o as readWebRecord, p as webSupervisorLogFile, r as cdpEndpoint, s as updateWebRecord } from "./state-PeQiJuIu.mjs";
10
10
  import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
11
- import { r as teardownBrowserHeld } from "./teardown-CL6vDs2Y.mjs";
12
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
13
- import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-Bk_YXEmE.mjs";
14
- import { t as resolveSupervisorTarget } from "./ownership-hCkPzGmr.mjs";
11
+ import { p as teardownBrowserHeld, t as resolveSupervisorTarget } from "./ownership-BMLqyBgJ.mjs";
12
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
13
+ import { i as reserveBrowserPort, n as getNamedPort } from "./named-ports-C8m8EQs2.mjs";
15
14
  import { o as readNdjsonGenerations } from "./ndjson-PclOIwVY.mjs";
16
15
  import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-BrcVWQyD.mjs";
17
16
  import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
18
- import { c as readMetroRecords } from "./launch-verify-2DBRizjo.mjs";
19
- import { o as resolveWorkspaceMetroPort } from "./start-ClDfwXa4.mjs";
20
- import { a as sleep, n as ensureWorkspaceStorageSafely } from "./native-runtime-DBzRnEKS.mjs";
17
+ import { c as readMetroRecords } from "./launch-verify-lTnWZikR.mjs";
18
+ import { o as resolveWorkspaceMetroPort } from "./start-uee1wWjY.mjs";
19
+ import { a as sleep, n as ensureWorkspaceStorageSafely } from "./native-runtime-DhJI3IVQ.mjs";
21
20
  import { n as sendToOwnedPage, t as liveWebRecord } from "./page-QF_Ke10s.mjs";
22
21
  import { randomUUID } from "node:crypto";
23
22
  import { mkdirSync, openSync } from "node:fs";
package/dist/web-run.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
3
3
  import { t as relaunchWithLogFile } from "./detached-entry-CiTEgMR1.mjs";
4
- import { u as signalProcessTree } from "./metro-BeK1ZPz1.mjs";
5
- import { _ as removeSingletonFiles, c as webClaimRoot, d as webLogFile, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, l as webDir, m as writeWebRecord, n as browserLogFile, s as updateWebRecord } from "./state-C1jB7Q8q.mjs";
6
- import { c as probeWebDrivers } from "./activity-BxwdD81S.mjs";
7
- import { r as recordCreatedDevice } from "./created-devices-D5owjN4C.mjs";
4
+ import { u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
5
+ import { _ as removeSingletonFiles, c as webClaimRoot, d as webLogFile, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, l as webDir, m as writeWebRecord, n as browserLogFile, s as updateWebRecord } from "./state-PeQiJuIu.mjs";
6
+ import { c as probeWebDrivers } from "./activity-IRvJY_ru.mjs";
7
+ import { r as recordCreatedDevice } from "./created-devices-CpvzBL25.mjs";
8
8
  import { r as createNdjsonWriter } from "./ndjson-PclOIwVY.mjs";
9
9
  import { t as connectOwnedBrowser } from "./cdp-Dq_ypAlJ.mjs";
10
10
  import { i as chromeArgs, n as DESKTOP_PAGE, r as PHONE_SCREEN } from "./chrome-BrcVWQyD.mjs";
@@ -1,10 +1,10 @@
1
1
  import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
2
2
  import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-D0XfSe8u.mjs";
3
3
  import { join } from "node:path";
4
+ import { setTimeout } from "node:timers/promises";
4
5
  //#region src/engine/workspace-process-lock.ts
5
6
  const DEFAULT_WAIT_MS = 6e4;
6
7
  const POLL_MS = 25;
7
- const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8
8
  function workspaceProcessLockError(err) {
9
9
  const code = err?.code;
10
10
  if (code === "STIM_LOCK_REFUSED") return "refused";
@@ -14,10 +14,11 @@ function workspaceProcessLockError(err) {
14
14
  function workspaceProcessLockPath(root, name, external) {
15
15
  return external ? join(root, `${name}.lock`) : join(root, ".stim", `${name}.lock`);
16
16
  }
17
- async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, sleep = defaultSleep, waitMs = DEFAULT_WAIT_MS, ownerPurpose, details = {}, onHeld, rejectOwnerPurposes = [], external = false, declareSpawns = false } = {}) {
17
+ async function withWorkspaceProcessLock(root, name, fn, { now = Date.now, signal, sleep = (ms) => setTimeout(ms, void 0, { signal }), waitMs = DEFAULT_WAIT_MS, ownerPurpose, details = {}, onHeld, rejectOwnerPurposes = [], external = false, declareSpawns = false } = {}) {
18
18
  const path = workspaceProcessLockPath(root, name, external);
19
19
  const deadline = now() + waitMs;
20
20
  for (;;) {
21
+ signal?.throwIfAborted();
21
22
  const attempt = (0, ownership_claim_exports.tryAcquireClaim)({
22
23
  root: path,
23
24
  mode: "exclusive",
@@ -3,7 +3,7 @@ import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname, isAbsolute, join, relative } from "node:path";
5
5
  import { join as join$1, resolve as resolve$1 } from "path";
6
- import { buildCacheRoot as sharedBuildCache, withDirLock as withDirLock$1, workspaceId, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
6
+ import { buildCacheRoot as sharedBuildCache, withDirLock as withDirLock$1, workspaceId as workspaceId$1, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
7
7
  import { WORKSPACE_AGENT_KEY, emulatorLogFile, readJsonObject, readWorkspaceState, readWorkspaceState as readWorkspaceState$1, sharedCcache as sharedCcache$1, sharedCompilationCache as sharedCompilationCache$1, supervisorLogFile, supervisorPidFile, workspaceAgentDeviceDir, workspaceDerivedData, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir as workspaceLogsDir$1, workspaceMetadataFile, workspaceStateFile, workspaceStateLock } from "@stim-cli/core/state";
8
8
  import { homedir } from "node:os";
9
9
  import { readFile, readdir } from "node:fs/promises";
@@ -368,4 +368,4 @@ function recordWorkspaceUse(root, now = /* @__PURE__ */ new Date(), env = proces
368
368
  } catch {}
369
369
  }
370
370
  //#endregion
371
- export { workspaceStateFile as C, discoverAgentSessions as D, attributeAgentSessions as E, workspaceName$1 as S, agentKey as T, workspaceDerivedData as _, updateWorkspaceState as a, workspaceLogErrorIndex as b, writeWorkspaceState as c, sharedBuildCache as d, sharedCcache$1 as f, workspaceAgentDeviceDir as g, supervisorPidFile as h, recordWorkspaceUse as i, emulatorLogFile as l, supervisorLogFile as m, clearWorkspaceStateKeys as n, withWorkspaceStateLock as o, sharedCompilationCache$1 as p, readWorkspaceState$1 as r, workspaceLastUsed as s, clearWorkspaceStateKey as t, ensureWorkspaceStorage as u, workspaceDir as v, withDirLock$1 as w, workspaceLogsDir$1 as x, workspaceId as y };
371
+ export { workspaceStateFile as C, discoverAgentSessions as D, attributeAgentSessions as E, workspaceName$1 as S, agentKey as T, workspaceDerivedData as _, updateWorkspaceState as a, workspaceLogErrorIndex as b, writeWorkspaceState as c, sharedBuildCache as d, sharedCcache$1 as f, workspaceAgentDeviceDir as g, supervisorPidFile as h, recordWorkspaceUse as i, emulatorLogFile as l, supervisorLogFile as m, clearWorkspaceStateKeys as n, withWorkspaceStateLock as o, sharedCompilationCache$1 as p, readWorkspaceState$1 as r, workspaceLastUsed as s, clearWorkspaceStateKey as t, ensureWorkspaceStorage as u, workspaceDir as v, withDirLock$1 as w, workspaceLogsDir$1 as x, workspaceId$1 as y };
@@ -1,7 +1,7 @@
1
1
  import { M as isOnMountedVolume, N as listMountedVolumes, P as measuredDirectorySize, _ as loadConfig$1, d as getConfigDir, g as isPathPrefix, j as formatBytes } from "./config-D0DbpZtM.mjs";
2
- import { S as workspaceName, s as workspaceLastUsed } from "./workspace-state-B8-aJ1_5.mjs";
3
- import { i as recordGcResult, n as withIdleWorkspace, o as canonicalPath, r as workspaceInUse, t as emptyWorkspaceDir } from "./in-use-DvBw0Kxo.mjs";
4
- import { a as teardownOwnedBrowser } from "./teardown-CL6vDs2Y.mjs";
2
+ import { S as workspaceName, s as workspaceLastUsed } from "./workspace-state-DqcCbpE7.mjs";
3
+ import { i as recordGcResult, n as withIdleWorkspace, o as canonicalPath, r as workspaceInUse, t as emptyWorkspaceDir } from "./in-use-CvGOUn-x.mjs";
4
+ import { h as teardownOwnedBrowser } from "./ownership-BMLqyBgJ.mjs";
5
5
  import { existsSync, lstatSync, readdirSync, rmSync, statSync } from "fs";
6
6
  import { basename, isAbsolute, join, relative } from "path";
7
7
  import { isJsonObject, readJsonFile } from "@stim-cli/core/state";
@@ -1,2 +1,2 @@
1
- import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-K-xj9Db0.mjs";
1
+ import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-ZpZR3S1k.mjs";
2
2
  export { worktreeCommand as default, dependencyInstallCommand, excludePodChurn, excludeWatchmanCookies, matchWorktreeEntry, porcelainPath, reclaimKeys, registerRemove, registerWarm, removalBlockers, removalPath, removalRemedy, removeWorktreeTarget, warmedWorkspace };
@@ -2,33 +2,33 @@ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { E as upsertProject, H as projectDeviceSlots, S as removeProject, _ as loadConfig$1, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject } from "./config-D0DbpZtM.mjs";
3
3
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
4
  import { a as pullRequestLookup, r as endedPullRequest } from "./pull-request-pxnDCQzn.mjs";
5
- import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-DnJMdEY-.mjs";
6
- import { $ as cloneIgnoredEntries, A as readCommittedSettings, H as unknownSettingKeys, P as resolveSettings, Q as branchExists, R as settingShapeErrors, St as warmWorktreePaths, _t as resolveFullRef, a as SETTING_SHAPE_REMEDY, at as gitCommonDirOnDisk, bt as sourceCheckoutOf, ct as hasUncommittedWork, dt as listWorktrees, et as deleteBranch, ft as locallyKnownUpstream, ht as removeWorktree, it as gitCommonDir, lt as isPodInstallChurn, mt as readWorktreeExclude, ot as hasPopulatedSubmodules, pt as podsOutOfSync, rt as dirtyPaths, st as hasRemote, tt as depsOutOfSync, xt as unpushedCommits, yt as restoreFile } from "./settings-oTSkkNrM.mjs";
7
- import { n as appProjectProblem, o as findProjectRoot$1 } from "./project-Du91Ilvc.mjs";
8
- import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-BeK1ZPz1.mjs";
9
- import { g as workspaceAgentDeviceDir, i as recordWorkspaceUse, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-B8-aJ1_5.mjs";
10
- import { o as readWebRecord } from "./state-C1jB7Q8q.mjs";
11
- import { a as machineNumber } from "./budget-DjrURfQn.mjs";
12
- import { n as withIdleWorkspace, t as emptyWorkspaceDir } from "./in-use-DvBw0Kxo.mjs";
13
- import { t as agentDeviceDaemon } from "./activity-BxwdD81S.mjs";
14
- import { u as releaseWorkspaceLeases } from "./device-lease-D-hLqx1b.mjs";
15
- import { a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, u as readRemoteSession } from "./state-DcW6vOd_.mjs";
16
- import { ft as parkedMaxSetting, ot as POOL_SETTING_REMEDY } from "./android-B_NumVyQ.mjs";
5
+ import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CDAIFD-8.mjs";
6
+ import { $ as cloneIgnoredEntries, A as readCommittedSettings, H as unknownSettingKeys, P as resolveSettings, Q as branchExists, R as settingShapeErrors, St as warmWorktreePaths, _t as resolveFullRef, at as gitCommonDirOnDisk, bt as sourceCheckoutOf, ct as hasUncommittedWork, dt as listWorktrees, et as deleteBranch, ft as locallyKnownUpstream, ht as removeWorktree, i as SETTING_SHAPE_REMEDY, it as gitCommonDir, lt as isPodInstallChurn, mt as readWorktreeExclude, ot as hasPopulatedSubmodules, pt as podsOutOfSync, rt as dirtyPaths, st as hasRemote, tt as depsOutOfSync, xt as unpushedCommits, yt as restoreFile } from "./settings-Cfd-0r2d.mjs";
7
+ import { n as appProjectProblem, s as findProjectRoot$1 } from "./project-D47Rh0ly.mjs";
8
+ import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
9
+ import { g as workspaceAgentDeviceDir, i as recordWorkspaceUse, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-DqcCbpE7.mjs";
10
+ import { o as readWebRecord } from "./state-PeQiJuIu.mjs";
11
+ import { a as machineNumber } from "./budget-DM984mnd.mjs";
12
+ import { n as withIdleWorkspace, t as emptyWorkspaceDir } from "./in-use-CvGOUn-x.mjs";
13
+ import { t as agentDeviceDaemon } from "./activity-IRvJY_ru.mjs";
14
+ import { u as releaseWorkspaceLeases } from "./device-lease-DpoS36_u.mjs";
15
+ import { a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, u as readRemoteSession } from "./state-BKa8wNN5.mjs";
16
+ import { ft as parkedMaxSetting, ot as POOL_SETTING_REMEDY } from "./android-B_YNZy61.mjs";
17
17
  import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
18
- import { a as teardownOwnedBrowser, i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-CL6vDs2Y.mjs";
19
- import { t as clearNamedPorts } from "./named-ports-Bk_YXEmE.mjs";
20
- import { i as stopTunnel, l as withManagedTunnelRemovalLock, s as withManagedRemoteWorktreeRemovalLock, t as resolveSupervisorTarget } from "./ownership-hCkPzGmr.mjs";
21
- import { l as withdrawDevServerStopRequest, s as requestDevServerStop } from "./stop-cause-CidxIqup.mjs";
22
- import { C as podInstallCommand, u as HEARTBEAT_INTERVAL_MS } from "./toolchain-DkUflduf.mjs";
23
- import { n as verifyCollectorOwnership } from "./ownership-DiA16AsN.mjs";
24
- import { t as stopMacosApp } from "./stop-B0Yxtmiy.mjs";
25
- import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-urbmfXig.mjs";
26
- import { f as resolveEasCliBin } from "./remote-cache-C8-V13XN.mjs";
27
- import { i as endRecordedSession } from "./device-remote-D5WVWqOq.mjs";
28
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-B6cMXZab.mjs";
29
- import { a as forgetStatusMeasures, s as mergeState, t as startWarmProgress } from "./warm-progress-CpGv3Wb6.mjs";
30
- import { r as workspaceRecordingEnabled } from "./recordings-BIXOzVnr.mjs";
31
- import { r as stopHostedIos } from "./hosted-ios-CIWelIqf.mjs";
18
+ import { g as teardownOwnedIosSim, h as teardownOwnedBrowser, i as stopTunnel, l as withManagedTunnelRemovalLock, m as teardownOwnedAvd, s as withManagedRemoteWorktreeRemovalLock, t as resolveSupervisorTarget } from "./ownership-BMLqyBgJ.mjs";
19
+ import { t as clearNamedPorts } from "./named-ports-C8m8EQs2.mjs";
20
+ import { l as withdrawDevServerStopRequest, s as requestDevServerStop } from "./stop-cause-rhmGfwvt.mjs";
21
+ import { C as podInstallCommand, u as HEARTBEAT_INTERVAL_MS } from "./toolchain-CNIBTIOv.mjs";
22
+ import { n as verifyCollectorOwnership } from "./ownership-DyRQru0q.mjs";
23
+ import { t as stopMacosApp } from "./stop-Cr1d8DSE.mjs";
24
+ import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-DNWaQs4V.mjs";
25
+ import { i as stopHostedAndroid } from "./hosted-android-DwLS4Mse.mjs";
26
+ import { f as resolveEasCliBin } from "./remote-cache-Ci4DQYYj.mjs";
27
+ import { i as endRecordedSession } from "./device-remote-hFSkpfQu.mjs";
28
+ import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-CLcBHH2M.mjs";
29
+ import { a as forgetStatusMeasures, s as mergeState, t as startWarmProgress } from "./warm-progress-DF4JRvYI.mjs";
30
+ import { r as workspaceRecordingEnabled } from "./recordings-BNgsD1Tr.mjs";
31
+ import { r as stopHostedIos } from "./hosted-ios-aMo7Cljf.mjs";
32
32
  import { createHash, randomUUID } from "node:crypto";
33
33
  import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, utimesSync, writeFileSync } from "node:fs";
34
34
  import { basename, dirname, join, relative } from "node:path";
@@ -37,6 +37,7 @@ import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$
37
37
  import { withDirLock, workspaceName } from "@stim-cli/core";
38
38
  import { LAST_BUILD_KEYS, archiveDir, archiveEnabled, archiveLock, archiveRoot, archivedUsage, countErrorEntries, endedAgentSessionOf, listRecordedDevices, loadConfig, queryLogs, readArchives, readBuildHistory, readJsonObject, readLastBuilds, readMacosRecord, readPullRequestCache, readWorkspaceState, recordingEnabled, sortByTs } from "@stim-cli/core/state";
39
39
  import { claimRemoveCommand, clearFreeClaimSet, readClaimSet, releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
40
+ import { homedir } from "node:os";
40
41
  import chalk from "chalk";
41
42
  //#region src/archive.ts
42
43
  const DAY = 864e5;
@@ -183,7 +184,7 @@ function gitFacts(root) {
183
184
  merged: null,
184
185
  pullRequest: null
185
186
  };
186
- if (!existsSync(root)) return empty;
187
+ if (!existsSync(root)) return cachedFacts(root) ?? empty;
187
188
  const exec = getExecutor();
188
189
  const run = (args) => exec.runFileQuiet("git", [
189
190
  "-C",
@@ -229,14 +230,32 @@ function gitFacts(root) {
229
230
  head: summary?.[0] ?? null,
230
231
  subject: summary?.[1] ?? null,
231
232
  merged,
232
- pullRequest: pr ? {
233
- number: pr.number,
234
- state: pr.state,
235
- title: pr.title,
236
- url: pr.url
237
- } : null
233
+ pullRequest: archivedPullRequest(pr)
238
234
  };
239
235
  }
236
+ function archivedPullRequest(pr) {
237
+ return pr ? {
238
+ number: pr.number,
239
+ state: pr.state,
240
+ title: pr.title,
241
+ url: pr.url
242
+ } : null;
243
+ }
244
+ function cachedFacts(root) {
245
+ for (let path = root; !existsSync(path); path = dirname(path)) {
246
+ const cached = readPullRequestCache(path);
247
+ if (!cached) continue;
248
+ return {
249
+ repository: null,
250
+ branch: cached.branch,
251
+ head: cached.head,
252
+ subject: null,
253
+ merged: cached.pullRequest?.state === "merged" ? true : null,
254
+ pullRequest: archivedPullRequest(cached.pullRequest)
255
+ };
256
+ }
257
+ return null;
258
+ }
240
259
  function archiveWorkspace(root, removedBy, state = readWorkspaceState(root)) {
241
260
  writeArchive(root, removedBy, state);
242
261
  try {
@@ -825,12 +844,12 @@ async function reclaimIdleProject(path, workspaceExisted, { archive, deleteOwned
825
844
  };
826
845
  skippedDevices.push(...skippedCollectors);
827
846
  failedDevices.push(...failedCollectors);
828
- try {
829
- await stopHostedIos(path);
847
+ for (const platform of ["ios", "android"]) try {
848
+ await (platform === "ios" ? stopHostedIos : stopHostedAndroid)(path);
830
849
  } catch (error) {
831
850
  const failed = {
832
- platform: "ios",
833
- name: "hosted iOS simulator",
851
+ platform,
852
+ name: `hosted ${platform} device`,
834
853
  reason: error.message
835
854
  };
836
855
  failedDevices.push(failed);
@@ -920,6 +939,66 @@ async function reclaimIdleProject(path, workspaceExisted, { archive, deleteOwned
920
939
  };
921
940
  }
922
941
  //#endregion
942
+ //#region src/workspace/service-guard.ts
943
+ const SERVICE_IN_USE = { code: "STIM_WORKTREE_SERVICE" };
944
+ function serviceUseOf(plist, file, folder, canonical) {
945
+ if (typeof plist !== "object" || plist === null) return null;
946
+ const job = plist;
947
+ if (typeof job.StimService !== "object" || job.StimService === null || !Array.isArray(job.ProgramArguments)) return null;
948
+ const argument = job.ProgramArguments.find((value) => typeof value === "string" && value.startsWith("/") && isPathPrefix(folder, canonical(value)));
949
+ if (argument === void 0) return null;
950
+ return {
951
+ label: typeof job.Label === "string" ? job.Label : file,
952
+ plist: file,
953
+ argument
954
+ };
955
+ }
956
+ /** The first installed stim-server service that runs from inside `folder`, or null. macOS only. */
957
+ function serviceRunningFrom(folder, canonical, agentsDir = join(homedir(), "Library", "LaunchAgents")) {
958
+ if (process.platform !== "darwin") return null;
959
+ let names;
960
+ try {
961
+ names = readdirSync(agentsDir).filter((name) => name.endsWith(".plist"));
962
+ } catch (error) {
963
+ return error.code === "ENOENT" ? null : {
964
+ label: "unknown",
965
+ plist: agentsDir,
966
+ argument: null
967
+ };
968
+ }
969
+ for (const name of names) {
970
+ const file = join(agentsDir, name);
971
+ const label = name.replace(/\.plist$/, "");
972
+ try {
973
+ if (!readFileSync(file).includes("StimService")) continue;
974
+ } catch {
975
+ return {
976
+ label,
977
+ plist: file,
978
+ argument: null
979
+ };
980
+ }
981
+ try {
982
+ const json = getExecutor().runFile("plutil", [
983
+ "-convert",
984
+ "json",
985
+ "-o",
986
+ "-",
987
+ file
988
+ ], { timeoutMs: 5e3 });
989
+ const use = serviceUseOf(JSON.parse(json), file, folder, canonical);
990
+ if (use) return use;
991
+ } catch {
992
+ return {
993
+ label,
994
+ plist: file,
995
+ argument: null
996
+ };
997
+ }
998
+ }
999
+ return null;
1000
+ }
1001
+ //#endregion
923
1002
  //#region src/engine/warm-claim.ts
924
1003
  const WARM_CLAIM_LABEL = "worktree warm";
925
1004
  const WARM_CLAIM_POLL_MS = 250;
@@ -2078,9 +2157,13 @@ function hasRegisteredProjectUnder(rootPath) {
2078
2157
  const cfg = loadConfig$1();
2079
2158
  return Object.keys(cfg?.projects ?? {}).some((key) => isPathPrefix(rootPath, key));
2080
2159
  }
2160
+ function projectAtOrAbove(root, path) {
2161
+ const here = nativeCanonicalPath(path);
2162
+ return Object.keys(loadConfig$1()?.projects ?? {}).filter((key) => isPathPrefix(nativeCanonicalPath(root), nativeCanonicalPath(key)) && isPathPrefix(nativeCanonicalPath(key), here)).toSorted((a, b) => b.length - a.length)[0] ?? null;
2163
+ }
2081
2164
  async function reclaimEnvironment(root, why) {
2082
2165
  await withManagedRemoteWorktreeRemovalLock(root, () => withReclaimLocks(root, async (lockedKeys) => {
2083
- const result = await reclaimAll(root, lockedKeys);
2166
+ const result = await reclaimAll(root, lockedKeys, { removedBy: "worktree-remove" });
2084
2167
  for (const line of poolLines(result)) console.error(line);
2085
2168
  for (const device of result.deletedDevices) console.error(chalk.dim(phaseLine("device", `deleted ${device}`)));
2086
2169
  for (const session of result.stoppedSessions) console.error(chalk.dim(phaseLine("device", `stopped remote session ${session}`)));
@@ -2255,7 +2338,18 @@ async function runRemove(target, opts, onRemoved) {
2255
2338
  return;
2256
2339
  }
2257
2340
  if (entry.path === source.path) {
2258
- if (entry.path !== path) console.error(chalk.dim(`${path} is inside the source checkout ${entry.path}; reclaiming its environment.`));
2341
+ if (nativeCanonicalPath(entry.path) !== nativeCanonicalPath(path)) {
2342
+ const project = projectAtOrAbove(entry.path, path);
2343
+ if (!project) {
2344
+ console.error(chalk.red(`Refusing to reclaim from ${path}: no Stim project is registered at or above it.`));
2345
+ console.error(chalk.dim(` Run it from the project folder, or from ${entry.path} to reclaim every project under it.`));
2346
+ process.exitCode = 1;
2347
+ return;
2348
+ }
2349
+ console.error(chalk.dim(`${path} is inside the source checkout ${entry.path}; reclaiming only the project ${project}.`));
2350
+ await reclaimEnvironment(project, "it is the source checkout");
2351
+ return;
2352
+ }
2259
2353
  await reclaimEnvironment(entry.path, "it is the source checkout");
2260
2354
  return;
2261
2355
  }
@@ -2269,6 +2363,13 @@ async function runRemove(target, opts, onRemoved) {
2269
2363
  process.exitCode = 1;
2270
2364
  return;
2271
2365
  }
2366
+ const service = serviceRunningFrom(path, nativeCanonicalPath);
2367
+ if (service) {
2368
+ console.error(chalk.red(service.argument ? `Refusing to remove ${path}: it runs the stim-server service ${service.label} (${service.argument}). ${SERVICE_IN_USE.code}` : `Refusing to remove ${path}: could not read ${service.plist} to check whether the stim-server service ${service.label} runs from it. ${SERVICE_IN_USE.code}`));
2369
+ console.error(chalk.dim(`Reinstall the service from another build with \`stim-server service install --label ${service.label}\`, or remove it with \`stim-server service uninstall --label ${service.label}\`, then retry.`));
2370
+ process.exitCode = 1;
2371
+ return;
2372
+ }
2272
2373
  const project = getProject(path);
2273
2374
  const branch = entry.branch;
2274
2375
  const ownsBranch = Boolean(branch && project?.worktreeBranchOwned === true && project.worktreeBranch === branch);
@@ -2371,7 +2472,7 @@ async function runRemove(target, opts, onRemoved) {
2371
2472
  }));
2372
2473
  }
2373
2474
  function registerRemove(worktree) {
2374
- worktree.command("remove [target]").description("Remove a worktree, its unused Stim-created branch, build artifacts, owned devices, and Metro port. Defaults to the current workspace. On the source checkout it reclaims the environment only and leaves the tree in place.").option("--force", "remove even when the worktree holds uncommitted or unpushed work or initialized submodules").action(async (target, opts) => {
2475
+ worktree.command("remove [target]").description("Remove a worktree, its unused Stim-created branch, build artifacts, owned devices, and Metro port. Defaults to the current workspace. On the source checkout it reclaims the environment only and leaves the tree in place; from a subfolder it reclaims only the project at or above that folder, with the projects nested under it.").option("--force", "remove even when the worktree holds uncommitted or unpushed work or initialized submodules").action(async (target, opts) => {
2375
2476
  await removeWorktreeTarget(target, { force: opts.force });
2376
2477
  });
2377
2478
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stim",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "Stim: fast, isolated React Native environments for coding agents",
5
5
  "keywords": [
6
6
  "agent",
@@ -48,9 +48,9 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@expo/fingerprint": "^0.20.10",
51
- "@stim-cli/cache": "^1.16.0",
52
- "@stim-cli/core": "^1.16.0",
53
- "@stim-cli/metro": "^1.16.0",
51
+ "@stim-cli/cache": "^1.17.0",
52
+ "@stim-cli/core": "^1.17.0",
53
+ "@stim-cli/metro": "^1.17.0",
54
54
  "chalk": "^6.0.0",
55
55
  "commander": "^15.0.0",
56
56
  "cross-spawn": "^7.0.6",
@@ -58,7 +58,7 @@
58
58
  "ws": "^8.21.3"
59
59
  },
60
60
  "devDependencies": {
61
- "@stim-cli/expo-build-cache": "1.16.0",
61
+ "@stim-cli/expo-build-cache": "1.17.0",
62
62
  "@types/cross-spawn": "^6.0.6",
63
63
  "@types/which": "^3.0.4",
64
64
  "@types/ws": "^8.18.1",