stim 1.18.0 → 1.19.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 (140) hide show
  1. package/README.md +1 -1
  2. package/dist/{activity-BxnkDZDi.mjs → activity-BSw0x84R.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +5 -5
  4. package/dist/{android-BvwuMUJ9.mjs → android-BXc6BmEi.mjs} +507 -347
  5. package/dist/{android-DC3ZLuw0.mjs → android-BdQC6zs1.mjs} +6 -6
  6. package/dist/{android-BKA16DTf.mjs → android-BvV1gGdN.mjs} +3 -3
  7. package/dist/{android-CBwCNicO.mjs → android-DE5g_5gv.mjs} +2 -2
  8. package/dist/{android-cas-BBFyr9CA.mjs → android-cas-C87geAg-.mjs} +3 -3
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/{api-D0VtFhqk.mjs → api-DIf_s86s.mjs} +5 -7
  11. package/dist/api-run.mjs +8 -8
  12. package/dist/api.d.mts +8 -2
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-D-PUENug.mjs → app-install-CFI4ptUL.mjs} +33 -13
  15. package/dist/{web-DTU0uiWj.mjs → browser-web-CDhqQxhv.mjs} +134 -172
  16. package/dist/{budget-DIhL2BKx.mjs → budget-Dz-kyXLv.mjs} +15 -202
  17. package/dist/{build-facts-DcLv2HSd.d.mts → build-facts-B87vo-Im.d.mts} +32 -1
  18. package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-DiwKSyv9.mjs} +1 -1
  19. package/dist/cache-manifest.mjs +1 -1
  20. package/dist/{chrome-DJnmnS5q.mjs → chrome-BTUOo8p2.mjs} +1 -1
  21. package/dist/{cli-DNJMwADx.mjs → cli-C9Zvgbdc.mjs} +20 -20
  22. package/dist/cli.mjs +1 -1
  23. package/dist/{client-DzhapoMB.mjs → client-CuUo8Nvg.mjs} +248 -23
  24. package/dist/collector-run.d.mts +6 -0
  25. package/dist/collector-run.mjs +6 -6
  26. package/dist/{command-output-CBtzyIgF.mjs → command-output-Bt8ygHE7.mjs} +1 -1
  27. package/dist/{config-CgYMahz7.mjs → config-DC5jEtd1.mjs} +6 -2
  28. package/dist/{created-devices-DKbeWsiK.mjs → created-devices-D0s26Hx5.mjs} +2 -2
  29. package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
  30. package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
  31. package/dist/{dev-client-CLnIH02x.mjs → dev-client-CDY_zAmD.mjs} +2 -2
  32. package/dist/{device-D7oCHGWi.mjs → device-BHw0WlHl.mjs} +8 -8
  33. package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-BoN1jQkO.mjs} +23 -12
  34. package/dist/device-host-worker.mjs +14 -14
  35. package/dist/{gradle-C6GKnunQ.mjs → device-ios-B2ruohE-.mjs} +659 -105
  36. package/dist/{device-lease-Co-EwifR.mjs → device-lease-Cu7PtQpZ.mjs} +5 -5
  37. package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
  38. package/dist/{device-pool-F5WvRPtD.mjs → device-pool-CP4rAsHx.mjs} +3 -3
  39. package/dist/{device-remote-tHbd1fKy.mjs → device-remote-B5GiUifk.mjs} +15 -16
  40. package/dist/{doctor-B9ckYUoU.mjs → doctor-PRJH94v6.mjs} +53 -29
  41. package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
  42. package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics--v5HGOU0.mjs} +10 -10
  43. package/dist/{exec-DWhCZDGm.mjs → exec-i8GDPwq9.mjs} +32 -8
  44. package/dist/{gc-Dh6mXOKC.mjs → gc-CyHMcKcn.mjs} +19 -19
  45. package/dist/{guide-tm6igAaa.mjs → guide-dRaQJJk9.mjs} +409 -472
  46. package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
  47. package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-C5G4h_OJ.mjs} +1 -1
  48. package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-Bik035eL.mjs} +1 -1
  49. package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-CI9Az9a4.mjs} +7 -7
  50. package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-DABm3ScO.mjs} +4 -4
  51. package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-DbV2aUVw.mjs} +12 -8
  52. package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DYiMBn34.mjs} +7 -7
  53. package/dist/{ios-B3SbOWdw.mjs → ios-BWbHFZVz.mjs} +5 -5
  54. package/dist/{ios-Bvbf0SGY.mjs → ios-DCrkgXEM.mjs} +1 -1
  55. package/dist/{ios-DNpdygiv.mjs → ios-DYUr9LGc.mjs} +7 -6
  56. package/dist/ios-ITYno9rO.mjs +2241 -0
  57. package/dist/{ios-device-vOaByMhw.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
  58. package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-CrW8aMb5.mjs} +1 -1
  59. package/dist/{ios-state-B2pES6Vs.mjs → ios-state-By0XuLTQ.mjs} +1 -1
  60. package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-DCveSE6d.mjs} +4 -4
  61. package/dist/{logs-1Ylc1Ri6.mjs → logs-Bao1HOMy.mjs} +10 -10
  62. package/dist/{macos-DF6C7wUU.mjs → macos-ciyBdTY5.mjs} +108 -130
  63. package/dist/macos-nIOATJmR.mjs +2 -0
  64. package/dist/macos-run.mjs +1 -1
  65. package/dist/maintenance-run.mjs +7 -7
  66. package/dist/manifest-CX0d1IkZ.mjs +148 -0
  67. package/dist/{metro-Dh8T4Ytd.mjs → metro-DI2AjPF_.mjs} +194 -41
  68. package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BxpJLIwh.mjs} +2 -2
  69. package/dist/{plan-placement-CtxkCO54.mjs → miss-reason-CjQCOKqq.mjs} +180 -296
  70. package/dist/{named-ports-BFIz1Shz.mjs → named-ports-B4iWH4E-.mjs} +12 -5
  71. package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BGxsbfny.mjs} +6 -6
  72. package/dist/offload-worker.d.mts +1 -29
  73. package/dist/offload-worker.mjs +9 -8
  74. package/dist/{ownership-D6Se7gg_.mjs → ownership-EB0ySdGK.mjs} +2 -2
  75. package/dist/{placement-log-BcPhRwR4.mjs → placement-log-Dxe34rJm.mjs} +7 -3
  76. package/dist/plan-placement-BVY59qa8.mjs +290 -0
  77. package/dist/{ports-BLTtfBq-.mjs → ports-ByPc0_97.mjs} +3 -3
  78. package/dist/{prebuild-juCyreaR.mjs → prebuild-BKJ3wJI1.mjs} +4 -4
  79. package/dist/{preview-D5V07Nrl.mjs → preview-BbSottmO.mjs} +16 -17
  80. package/dist/project-B5eQ1USs.mjs +612 -0
  81. package/dist/{pull-request-u4vp7zmK.mjs → pull-request-IHNdMnG8.mjs} +1 -1
  82. package/dist/pull-requests.mjs +1 -1
  83. package/dist/react-native-ios-BMh2i25I.mjs +2 -0
  84. package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
  85. package/dist/{recordings-BAWltsVt.mjs → recordings-Bv8McZN4.mjs} +1 -1
  86. package/dist/{reload-DvyWzVjJ.mjs → reload-rAPdqeRR.mjs} +13 -14
  87. package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-N3hAEaAL.mjs} +4 -4
  88. package/dist/{run-vhtDgpHO.mjs → run-lAkle1-c.mjs} +2 -2
  89. package/dist/{server-bare-B9E7S1aR.mjs → server-bare-CkIjnegq.mjs} +3 -3
  90. package/dist/server-expo-DGsdUGX2.mjs +2 -0
  91. package/dist/{server-expo-DoBHhuzK.mjs → server-expo-n3tUi3Em.mjs} +3 -3
  92. package/dist/{settings-Byp2AQ_E.mjs → settings-2am7TSxp.mjs} +5 -6
  93. package/dist/{settings-CQyMElEP.mjs → settings-CxgngUZk.mjs} +767 -15
  94. package/dist/settings.schema.json +72 -6
  95. package/dist/{simslim-EHBQ2R4G.mjs → simslim-D9LkJxIO.mjs} +5 -5
  96. package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
  97. package/dist/{stage-g_WqWeaE.mjs → stage-BgaZJVZY.mjs} +1 -1
  98. package/dist/{start-NTc1Ifqs.mjs → start-D8NbxNBb.mjs} +1 -1
  99. package/dist/{start-D-IeOyoK.mjs → start-DtxthMfI.mjs} +29 -22
  100. package/dist/{state-BG-aAk4k.mjs → state-D2KtnALG.mjs} +2 -2
  101. package/dist/{state-xnqpx3AD.mjs → state-Tp4uImDS.mjs} +4 -2
  102. package/dist/{stats-DY6ekz8F.mjs → stats-8EJ5ivFT.mjs} +6 -6
  103. package/dist/{status-DCjZeE-K.mjs → status-BOyp0CUl.mjs} +25 -27
  104. package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
  105. package/dist/{stim-installations-aR_WsNOA.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
  106. package/dist/stop-D0UIpZuh.mjs +72 -0
  107. package/dist/{stop-DIJtD2GL.mjs → stop-DRipAg-e.mjs} +2 -2
  108. package/dist/{stop-BTjs3xbc.mjs → stop-zDlknFoz.mjs} +78 -31
  109. package/dist/supervisor-run.mjs +14 -14
  110. package/dist/{support-BaayeYCf.mjs → support-CNqYkV0y.mjs} +7 -7
  111. package/dist/{support-Bwvbrq5-.mjs → support-DsNaFg6D.mjs} +5 -5
  112. package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
  113. package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-C3xSoyUl.mjs} +27 -270
  114. package/dist/{trigger-CJMhwXe8.mjs → trigger-CAhmG-4s.mjs} +3 -3
  115. package/dist/trigger-CoalsMTV.mjs +2 -0
  116. package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-pFLB2e6P.mjs} +133 -36
  117. package/dist/{status-Dcr0Qexd.mjs → watchman-BL1IdOtq.mjs} +75 -7
  118. package/dist/web-DFpFeZu5.mjs +2 -0
  119. package/dist/web-DbbrPUn0.mjs +127 -0
  120. package/dist/web-run.mjs +7 -7
  121. package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CR9X86xJ.mjs} +1 -1
  122. package/dist/{workspaces-xXItD8Dj.mjs → workspaces-Djb2gfi9.mjs} +102 -18
  123. package/dist/{worktree-BSYlofkq.mjs → worktree-BL4M1rhB.mjs} +45 -42
  124. package/dist/{worktree-BJfnU6r5.mjs → worktree-DV-A0LNL.mjs} +1 -1
  125. package/package.json +5 -5
  126. package/shim/bundle-response.cjs +2 -1
  127. package/shim/bundle-response.d.cts +1 -1
  128. package/shim/expo-metro-config.cjs +1 -1
  129. package/dist/device-ios-6MewKKnc.mjs +0 -412
  130. package/dist/guide-status-Bhf9SJXc.mjs +0 -125
  131. package/dist/ios-CPdkoKaa.mjs +0 -3953
  132. package/dist/macos-Ck7OBMNY.mjs +0 -2
  133. package/dist/native-run-B06FkmZx.mjs +0 -158
  134. package/dist/project-C3ChRLZy.mjs +0 -212
  135. package/dist/projects-DD7dBTCj.mjs +0 -92
  136. package/dist/server-expo-Db9HBUoa.mjs +0 -2
  137. package/dist/stop-BGhKMOuH.mjs +0 -48
  138. package/dist/trigger-DWAq9hkw.mjs +0 -2
  139. package/dist/web-B6_bFDn7.mjs +0 -2
  140. package/dist/worktree-CsKYexJM.mjs +0 -753
@@ -1,14 +1,19 @@
1
- import { n as debugLog, t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { _ as loadConfig$1, d as getConfigDir } from "./config-CgYMahz7.mjs";
3
- import { w as withDirLock } from "./workspace-state-C59dqG-Z.mjs";
4
- import { a as toolchainMismatches, d as readRubyVersion, h as COMPILATION_CACHE_UNAVAILABLE, j as CCACHE_UNAVAILABLE, s as manifestDigest } from "./toolchain-Bnyd_K3A.mjs";
1
+ import { n as debugLog, t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { a as formatElapsed } from "./command-output-Bt8ygHE7.mjs";
3
+ import { _ as loadConfig$1, d as getConfigDir } from "./config-DC5jEtd1.mjs";
4
+ import { a as updateWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey, v as workspaceDir, w as withDirLock } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { i as signalDeclaredSpawns, r as refuseDeclaredSpawns, t as allowDeclaredSpawns } from "./spawn-claims-Kqiifsk2.mjs";
6
+ import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
7
+ import { r as CCACHE_UNAVAILABLE, t as manifestDigest } from "./manifest-CX0d1IkZ.mjs";
8
+ import { a as toolchainMismatches, m as COMPILATION_CACHE_UNAVAILABLE, u as readRubyVersion } from "./toolchain-C3xSoyUl.mjs";
5
9
  import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, writeFileSync, writeSync } from "node:fs";
6
10
  import { basename, dirname, join, relative } from "node:path";
7
- import { OFFLOAD_MODES, acceptsShape, buildMachinesFile, buildMachinesLock, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, endpoint, findPeer as findPeer$1, isJsonObject, parseMachine, parseMachine as parseMachine$1, pinnedEndpoint, readBuildMachines, readDeviceHostMachines, runId, saturation, settingDefinition } from "@stim-cli/core/state";
11
+ import { OFFLOAD_MODES, acceptsShape, automaticMachineEnabled, buildMachinesFile, buildMachinesLock, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, endpoint, findPeer as findPeer$1, isJsonObject, parseMachine, parseMachine as parseMachine$1, pinnedEndpoint, readBuildMachines, readDeviceHostMachines, requireAutomaticMachine, runId, saturation, settingDefinition } from "@stim-cli/core/state";
8
12
  import { hostname } from "node:os";
9
13
  import { InvalidArgumentError } from "commander";
10
14
  import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
11
15
  import { createHash } from "node:crypto";
16
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
12
17
  import { WebSocket } from "ws";
13
18
  //#region src/offload/access-ticket.ts
14
19
  function readAccessTicket() {
@@ -689,6 +694,9 @@ function parseBuildMachineOption(value) {
689
694
  throw new InvalidArgumentError(error.message);
690
695
  }
691
696
  }
697
+ function requireLocalBuild(selected) {
698
+ if (selected === "auto" && !automaticMachineEnabled("build", "local")) throw new OffloadRefusal("auto", "local is disabled in remote.buildPoolDisabled; enable it or select a machine explicitly");
699
+ }
692
700
  function namedBuildMachine(selected) {
693
701
  return selected !== "auto" && selected !== "local";
694
702
  }
@@ -758,6 +766,159 @@ function reportRemoteFailure(event, fields) {
758
766
  } catch {}
759
767
  }
760
768
  //#endregion
769
+ //#region src/engine/native-run.ts
770
+ const NATIVE_RUN_LOCK = "native-run";
771
+ const NATIVE_RUN_WAIT_MS = 18e5;
772
+ const WAIT_HEARTBEAT_MS = 3e4;
773
+ const CANCEL_REQUEST_KEY = "nativeRunCancel";
774
+ function nativeRunHolder(holder) {
775
+ const { command, platform, slot } = holder.details;
776
+ return {
777
+ command: typeof command === "string" ? command : null,
778
+ platform: typeof platform === "string" ? platform : null,
779
+ slot: typeof slot === "string" ? slot : "default"
780
+ };
781
+ }
782
+ function describeNativeRunHolder(holder, now) {
783
+ const { command, slot } = nativeRunHolder(holder);
784
+ const started = Date.parse(holder.startedAt);
785
+ const facts = [`pid ${holder.owner.pid}`];
786
+ if (Number.isFinite(started)) facts.push(`running for ${formatElapsed(now - started)}`);
787
+ if (command === null) return `another Stim run (${facts.join(", ")})`;
788
+ return `\`stim ${command}${slot === "default" ? "" : ` --slot ${slot}`}\` (${facts.join(", ")})`;
789
+ }
790
+ /**
791
+ * Report a wait on the native-run lock: one line as soon as a holder is seen, a line for each new
792
+ * holder, and a heartbeat every WAIT_HEARTBEAT_MS while the same holder keeps it.
793
+ */
794
+ function nativeRunWaitNotice({ write, now = Date.now, describe = describeNativeRunHolder }) {
795
+ let claimId = null;
796
+ let lastAt = 0;
797
+ return (holder, firstLine) => {
798
+ const at = now();
799
+ if (holder.claimId !== claimId) {
800
+ claimId = holder.claimId;
801
+ lastAt = at;
802
+ write(firstLine ?? `waiting for ${describe(holder, at)} in this workspace to finish`);
803
+ return;
804
+ }
805
+ if (at - lastAt < WAIT_HEARTBEAT_MS) return;
806
+ lastAt = at;
807
+ write(`still waiting for ${describe(holder, at)}`);
808
+ };
809
+ }
810
+ /**
811
+ * What `stop` does about the run holding the native-run lock. A build is interrupted only when the stop
812
+ * leaves it nothing to deploy to: the whole workspace stops, the build targets the stopped slot, or the
813
+ * stopped slot is the workspace's only device. A build for another slot that stays is left running and
814
+ * the stop proceeds without the lock. Only an owner whose identity is proven live is signalled.
815
+ */
816
+ function decideStopAction({ stopSlot, holder, ownerIdentity, deviceSlots }) {
817
+ if (holder.command === "macos") {
818
+ if (stopSlot !== void 0) return { action: "proceed" };
819
+ return ownerIdentity === "same" ? { action: "interrupt" } : { action: "refuse" };
820
+ }
821
+ if (holder.command !== "ios" && holder.command !== "android") return { action: "wait" };
822
+ if (!(stopSlot === void 0 || holder.slot === stopSlot || deviceSlots.includes(stopSlot) && deviceSlots.every((slot) => slot === stopSlot))) return { action: "proceed" };
823
+ return ownerIdentity === "same" ? { action: "interrupt" } : { action: "refuse" };
824
+ }
825
+ function requestNativeRunCancel(root, claimId, pid = process.pid) {
826
+ updateWorkspaceState(root, (state) => ({
827
+ ...state,
828
+ [CANCEL_REQUEST_KEY]: {
829
+ claimId,
830
+ pid,
831
+ at: (/* @__PURE__ */ new Date()).toISOString()
832
+ }
833
+ }));
834
+ }
835
+ function cancelRequestFor(root, claimId) {
836
+ const request = readWorkspaceState$1(root)?.[CANCEL_REQUEST_KEY];
837
+ if (request?.claimId !== claimId || typeof request.pid !== "number") return null;
838
+ return { pid: request.pid };
839
+ }
840
+ function clearNativeRunCancel(root, claimId) {
841
+ try {
842
+ clearWorkspaceStateKey(root, CANCEL_REQUEST_KEY, (value) => value?.claimId === claimId);
843
+ } catch {}
844
+ }
845
+ let cancelled = null;
846
+ let cancellationSignal;
847
+ /** The active native run aborts this signal when it is cancelled. */
848
+ function runCancellationSignal() {
849
+ return cancellationSignal;
850
+ }
851
+ /** Why this process's native run was cancelled, or null while it was not. */
852
+ function runCancellation() {
853
+ return cancelled;
854
+ }
855
+ function cancelledFailure(platform, { code, message }) {
856
+ if (cancelled === null) return null;
857
+ return {
858
+ code: "STIM_CANCELLED",
859
+ message: `The ${platform} run was ${cancelled} before it finished.`,
860
+ remedy: `Run \`stim ${platform}\` again when you want the app on a device.`,
861
+ lines: [`it stopped at ${code ?? "an unfinished step"}${message ? `: ${message}` : ""}`]
862
+ };
863
+ }
864
+ function cancelOnInterrupt({ root, claim, write, exit, controller }) {
865
+ let signals = 0;
866
+ const onInterrupt = () => {
867
+ signals += 1;
868
+ if (signals > 1) {
869
+ exit(130);
870
+ return;
871
+ }
872
+ const request = cancelRequestFor(root, claim.claimId);
873
+ cancelled = request ? `cancelled by \`stim stop\` (pid ${request.pid})` : "cancelled by an interrupt";
874
+ controller.abort();
875
+ refuseDeclaredSpawns(`the run was ${cancelled}`);
876
+ const signalled = signalDeclaredSpawns("SIGINT");
877
+ write(signalled > 0 ? `${cancelled}; stopping the running build tool` : request ? `${cancelled}; stopping before the next build tool or install` : cancelled);
878
+ if (signalled === 0 && !request) exit(130);
879
+ };
880
+ process.on("SIGINT", onInterrupt);
881
+ return () => {
882
+ process.off("SIGINT", onInterrupt);
883
+ allowDeclaredSpawns();
884
+ clearNativeRunCancel(root, claim.claimId);
885
+ };
886
+ }
887
+ /**
888
+ * Run an `ios`, `android` or `macos` invocation under the workspace's native-run lock: the claim records the
889
+ * command, platform and slot, and a wait for another holder is reported on `write`. The first SIGINT
890
+ * forwards the interrupt to the running declared build tool; a run `stim stop` cancelled between build
891
+ * tools starts no further one; a terminal interrupt with no build tool running, or a second SIGINT, exits
892
+ * with 130 at once.
893
+ */
894
+ function withNativeBuildRun(root, details, fn, { write, exit = (code) => process.exit(code) }) {
895
+ const notice = nativeRunWaitNotice({ write });
896
+ return withWorkspaceProcessLock(workspaceDir(root), NATIVE_RUN_LOCK, async (claim) => {
897
+ cancelled = null;
898
+ const controller = new AbortController();
899
+ cancellationSignal = controller.signal;
900
+ const dispose = cancelOnInterrupt({
901
+ root,
902
+ claim,
903
+ write,
904
+ exit,
905
+ controller
906
+ });
907
+ try {
908
+ return await fn(claim);
909
+ } finally {
910
+ dispose();
911
+ cancellationSignal = void 0;
912
+ }
913
+ }, {
914
+ external: true,
915
+ waitMs: NATIVE_RUN_WAIT_MS,
916
+ declareSpawns: true,
917
+ details: { ...details },
918
+ onHeld: (holder) => notice(holder)
919
+ });
920
+ }
921
+ //#endregion
761
922
  //#region src/offload/client.ts
762
923
  const CONNECT_TIMEOUT_MS = 1e4;
763
924
  const OFFER_TIMEOUT_MS = 2e4;
@@ -785,9 +946,11 @@ function offloadMode(env = process.env) {
785
946
  return OFFLOAD_MODES.includes(raw) ? raw : "auto";
786
947
  }
787
948
  function buildPlacementCandidates(selected) {
949
+ const config = loadConfig$1();
788
950
  return {
951
+ localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local", config),
789
952
  mode: selected === "local" ? "off" : offloadMode(),
790
- machines: selected === "local" ? [] : namedBuildMachine(selected) ? pairedMachines([selected]).slice(0, 1) : pairedMachines()
953
+ machines: selected === "local" ? [] : namedBuildMachine(selected) ? pairedMachines([selected]).slice(0, 1) : pairedMachines().filter((entry) => automaticMachineEnabled("build", entry.machine, config))
791
954
  };
792
955
  }
793
956
  function remotePhaseText(name, msg, machine) {
@@ -813,7 +976,7 @@ function placementLoad(choice) {
813
976
  * this Mac has a free `concurrency.maxBuilds` slot and its load per core is under `server.maxLoadPerCore`.
814
977
  * A named selection ignores local capacity and mode, and refuses an unsupported build or missing pairing.
815
978
  */
816
- function offloadPlacement({ mode, machines, here, unsupported, selected = "auto" }) {
979
+ function offloadPlacement({ mode, machines, here, unsupported, localEnabled = true, selected = "auto" }) {
817
980
  if (namedBuildMachine(selected)) {
818
981
  if (unsupported) throw new OffloadRefusal(selected, `${unsupported}, so a named remote Mac cannot take it`);
819
982
  if (machines === 0) throw new OffloadRefusal(selected, "no remote Mac is paired");
@@ -828,6 +991,15 @@ function offloadPlacement({ mode, machines, here, unsupported, selected = "auto"
828
991
  code: "local-selected",
829
992
  reason: "--remote-build local"
830
993
  };
994
+ if (!localEnabled) {
995
+ const reason = mode === "off" ? "remote.buildMode is off" : unsupported ?? (machines === 0 ? "no enabled remote Mac is paired" : null);
996
+ if (reason) throw new OffloadRefusal("auto", `${reason}; local is disabled in remote.buildPoolDisabled`);
997
+ return {
998
+ offload: true,
999
+ code: "local-disabled",
1000
+ reason: "local is disabled in remote.buildPoolDisabled"
1001
+ };
1002
+ }
831
1003
  if (mode === "off") return {
832
1004
  offload: false,
833
1005
  code: "mode-off",
@@ -891,7 +1063,7 @@ function offerProblems(offer, target) {
891
1063
  * A machine that reports no load (a stim-server older than capacity) takes an `auto` build only while
892
1064
  * every local slot is busy. The rest rank warmest first, then least loaded.
893
1065
  */
894
- function pickOffer({ mode, here, offers, target, selected = "auto" }) {
1066
+ function pickOffer({ mode, here, offers, target, localEnabled = true, selected = "auto" }) {
895
1067
  const slotsFull = here.maxBuilds > 0 && here.builds >= here.maxBuilds;
896
1068
  const reasons = [];
897
1069
  const candidates = [];
@@ -911,7 +1083,7 @@ function pickOffer({ mode, here, offers, target, selected = "auto" }) {
911
1083
  const problems = offerProblems(offer, target);
912
1084
  if (problems.length) return skip(machine, problemCode(problems[0]), problems.map((problem) => problem.reason).join("; "), problems.map((problem) => problem.code));
913
1085
  const load = offer.capacity.loadPerCore;
914
- if (selected === "auto" && mode === "auto" && !slotsFull) {
1086
+ if (selected === "auto" && localEnabled && mode === "auto" && !slotsFull) {
915
1087
  if (typeof load !== "number") return skip(machine, "load", "capacity unknown (older stim-server) while this Mac has a free slot");
916
1088
  if (load >= here.loadPerCore) return skip(machine, "load", `no less loaded (load ${load}/core there, ${here.loadPerCore}/core here)`);
917
1089
  }
@@ -1146,6 +1318,7 @@ var BuildConnection = class BuildConnection {
1146
1318
  });
1147
1319
  }
1148
1320
  async sendBinary(frame) {
1321
+ if (this.closed) return;
1149
1322
  this.socket.send(frame, { binary: true });
1150
1323
  while (this.socket.bufferedAmount > MAX_BUFFERED && !this.closed) await new Promise((resolve) => setTimeout(resolve, 5));
1151
1324
  }
@@ -1183,6 +1356,14 @@ var BuildConnection = class BuildConnection {
1183
1356
  }
1184
1357
  forget() {
1185
1358
  this.ended = true;
1359
+ this.closed ??= "the connection was closed by this client";
1360
+ for (const resolve of this.pending.values()) resolve({ error: {
1361
+ code: "closed",
1362
+ message: this.closed
1363
+ } });
1364
+ this.pending.clear();
1365
+ this.progress = null;
1366
+ this.binary = null;
1186
1367
  clearInterval(this.keepalive);
1187
1368
  this.socket.removeAllListeners("close");
1188
1369
  openSockets.delete(this.socket);
@@ -1317,12 +1498,14 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1317
1498
  return `this app is not in a git checkout (${error.message.split("\n")[0]})`;
1318
1499
  }
1319
1500
  if (namedBuildMachine(selected)) machines = machines.filter((each) => each.machine === selected).slice(0, 1);
1501
+ else machines = machines.filter((each) => automaticMachineEnabled("build", each.machine));
1320
1502
  const rubyVersion = readRubyVersion(projectRoot) ?? void 0;
1321
1503
  const asked = await Promise.all(machines.map((credential) => probeMachine(credential, {
1322
1504
  ...identity,
1323
1505
  rubyVersion
1324
1506
  })));
1325
1507
  const { order, reasons, candidates } = pickOffer({
1508
+ localEnabled: selected !== "auto" || automaticMachineEnabled("build", "local"),
1326
1509
  selected,
1327
1510
  mode,
1328
1511
  here,
@@ -1353,7 +1536,8 @@ async function chooseBuildMachine({ projectRoot, target, mode, here, note, machi
1353
1536
  target,
1354
1537
  offerMs: Date.now() - started,
1355
1538
  identity,
1356
- runnersUp: rest
1539
+ runnersUp: rest,
1540
+ automatic: selected === "auto"
1357
1541
  };
1358
1542
  }
1359
1543
  const ARTIFACT_NAME = {
@@ -1366,7 +1550,7 @@ const ARTIFACT_NAME = {
1366
1550
  * `RESUME_WINDOW_MS`, shorter than the machine's grace for a dropped connection, has passed. Returns why it
1367
1551
  * could not.
1368
1552
  */
1369
- async function resumeJob(credential, job, abandoned) {
1553
+ async function resumeJob(credential, job, abandoned, signal) {
1370
1554
  const deadline = Date.now() + RESUME_WINDOW_MS;
1371
1555
  let delay = RESUME_DELAY_MS;
1372
1556
  let last = "no attempt";
@@ -1380,9 +1564,20 @@ async function resumeJob(credential, job, abandoned) {
1380
1564
  if (connection.refused) return `the machine turned this Mac away (${connection.failure})`;
1381
1565
  last = connection.failure;
1382
1566
  } else {
1567
+ if (abandoned()) {
1568
+ connection.close();
1569
+ break;
1570
+ }
1383
1571
  const early = [];
1384
1572
  connection.onProgress((event) => early.push(event));
1573
+ const cancel = () => connection.close();
1574
+ signal?.addEventListener("abort", cancel, { once: true });
1385
1575
  const reply = await connection.request("build.attach", { job }, OFFER_TIMEOUT_MS);
1576
+ signal?.removeEventListener("abort", cancel);
1577
+ if (abandoned()) {
1578
+ connection.close();
1579
+ break;
1580
+ }
1386
1581
  if ("result" in reply) {
1387
1582
  const outcome = isJsonObject(reply.result) ? reply.result.outcome : null;
1388
1583
  return {
@@ -1398,8 +1593,8 @@ async function resumeJob(credential, job, abandoned) {
1398
1593
  }
1399
1594
  connection.drop();
1400
1595
  }
1401
- if (Date.now() + delay > deadline) break;
1402
- await new Promise((resolve) => setTimeout(resolve, delay));
1596
+ if (abandoned() || Date.now() + delay > deadline) break;
1597
+ await setTimeout$1(delay, void 0, { signal }).catch(() => {});
1403
1598
  delay = Math.min(delay * 2, RESUME_MAX_DELAY_MS);
1404
1599
  }
1405
1600
  return `no connection to it within ${RESUME_WINDOW_MS / 6e4} min (${last})`;
@@ -1467,23 +1662,36 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1467
1662
  reason: reason.split("\n")[0].slice(0, 300)
1468
1663
  };
1469
1664
  };
1665
+ const signal = runCancellationSignal();
1666
+ const throwIfCancelled = () => {
1667
+ if (signal?.aborted) throw Object.assign(/* @__PURE__ */ new Error("The offloaded build was cancelled."), { code: "STIM_CANCELLED" });
1668
+ };
1669
+ let settle;
1670
+ let settled = false;
1671
+ const outcome = new Promise((resolve) => {
1672
+ settle = (value) => {
1673
+ settled = true;
1674
+ resolve(value);
1675
+ };
1676
+ });
1677
+ const cancel = () => {
1678
+ settle({
1679
+ ok: false,
1680
+ code: "cancelled"
1681
+ });
1682
+ closeOffload(choice);
1683
+ };
1684
+ signal?.addEventListener("abort", cancel, { once: true });
1470
1685
  try {
1686
+ throwIfCancelled();
1471
1687
  let job = null;
1472
1688
  let early = [];
1473
- let settle;
1474
- let settled = false;
1475
- const outcome = new Promise((resolve) => {
1476
- settle = (value) => {
1477
- settled = true;
1478
- resolve(value);
1479
- };
1480
- });
1481
1689
  let resuming = false;
1482
1690
  const reattach = async (why) => {
1483
1691
  if (resuming || settled) return;
1484
1692
  resuming = true;
1485
1693
  note(`offload: the connection to ${choice.machine} dropped (${why}); reattaching to the build there`);
1486
- const resumed = await resumeJob(choice.credential, job, () => settled);
1694
+ const resumed = await resumeJob(choice.credential, job, () => settled, signal);
1487
1695
  resuming = false;
1488
1696
  if (settled) {
1489
1697
  if (typeof resumed !== "string") resumed.connection.close();
@@ -1526,7 +1734,13 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1526
1734
  return true;
1527
1735
  };
1528
1736
  for (;;) {
1737
+ if (choice.automatic && !automaticMachineEnabled("build", choice.machine)) {
1738
+ const reason = `${choice.machine} is disabled in remote.buildPoolDisabled`;
1739
+ if (moveOn(reason)) continue;
1740
+ return fail(reason);
1741
+ }
1529
1742
  const synced = await syncSource(choice.connection, identity, onEnter);
1743
+ throwIfCancelled();
1530
1744
  if ("failure" in synced) {
1531
1745
  if (moveOn(synced.failure)) continue;
1532
1746
  return fail(synced.failure);
@@ -1536,6 +1750,8 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1536
1750
  workerStarted = Date.now();
1537
1751
  early = [];
1538
1752
  choice.connection.onProgress((event) => job === null ? early.push(event) : handle(event));
1753
+ if (choice.automatic) requireAutomaticMachine("build", choice.machine);
1754
+ throwIfCancelled();
1539
1755
  const reply = await choice.connection.request("build.start", {
1540
1756
  repo: identity.repo,
1541
1757
  project: identity.project,
@@ -1558,6 +1774,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1558
1774
  },
1559
1775
  stimBuild: choice.target.local.stimBuild
1560
1776
  });
1777
+ throwIfCancelled();
1561
1778
  if ("result" in reply) {
1562
1779
  job = reply.result.job;
1563
1780
  break;
@@ -1575,6 +1792,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1575
1792
  }), JOB_TIMEOUT_MS);
1576
1793
  const result = await outcome;
1577
1794
  clearTimeout(timer);
1795
+ throwIfCancelled();
1578
1796
  const { connection, machine } = choice;
1579
1797
  connection.onProgress(null);
1580
1798
  const workerMs = Date.now() - workerStarted;
@@ -1583,6 +1801,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1583
1801
  const name = typeof artifact?.name === "string" ? artifact.name : "";
1584
1802
  if (!ARTIFACT_NAME[request.platform].test(name) || typeof artifact.sha256 !== "string") return fail(`the machine reported no .${request.platform === "android" ? "apk" : "app"} artifact`);
1585
1803
  onEnter("fetch");
1804
+ throwIfCancelled();
1586
1805
  const fetchStarted = Date.now();
1587
1806
  rmSync(stagingDir, {
1588
1807
  recursive: true,
@@ -1612,6 +1831,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1612
1831
  const fetched = await connection.request("build.artifact", { job }, 9e5);
1613
1832
  connection.onBinary(null);
1614
1833
  closeSync(fd);
1834
+ throwIfCancelled();
1615
1835
  const fetchFailure = replyError(fetched);
1616
1836
  if (fetchFailure || !("result" in fetched)) return fail(`fetch: ${fetchFailure ?? "no reply"}`);
1617
1837
  const digest = hash.digest("hex");
@@ -1624,6 +1844,7 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1624
1844
  "-C",
1625
1845
  stagingDir
1626
1846
  ], { timeoutMs: 6e5 });
1847
+ throwIfCancelled();
1627
1848
  rmSync(archive, { force: true });
1628
1849
  const artifactPath = join(stagingDir, name);
1629
1850
  if (request.platform === "ios" && !existsSync(join(artifactPath, "Info.plist"))) return fail(`fetch: ${name} has no Info.plist`);
@@ -1660,7 +1881,11 @@ async function offloadBuild({ choice, expectedFingerprint, request, stagingDir,
1660
1881
  }
1661
1882
  };
1662
1883
  } catch (error) {
1884
+ closeOffload(choice);
1885
+ throwIfCancelled();
1663
1886
  return fail(error.message.split("\n")[0] ?? String(error));
1887
+ } finally {
1888
+ signal?.removeEventListener("abort", cancel);
1664
1889
  }
1665
1890
  }
1666
1891
  function packageName(projectRoot) {
@@ -1769,4 +1994,4 @@ function offloadCheck(projectRoot, targets) {
1769
1994
  };
1770
1995
  }
1771
1996
  //#endregion
1772
- export { pinnedEndpoint$1 as C, parseMachine$1 as S, resolveBuildPlacement as _, offloadBuild as a, hostingMachines as b, placementLoad as c, setRemoteLogSink as d, OffloadRefusal as f, resolveBuildMachine as g, parseBuildMachineOption as h, closeOffload as i, remotePhaseText as l, namedBuildMachine as m, buildPlacementCandidates as n, offloadCheck as o, buildPlacementSettings as p, chooseBuildMachine as r, offloadPlacement as s, BuildConnection as t, simulatorRuntime as u, inspectBuildMachines as v, realIo as w, inspectDeviceHostMachines as x, configuredMachines as y };
1997
+ export { resolveBuildPlacement as A, setRemoteLogSink as C, parseBuildMachineOption as D, namedBuildMachine as E, parseMachine$1 as F, pinnedEndpoint$1 as I, realIo as L, configuredMachines as M, hostingMachines as N, requireLocalBuild as O, inspectDeviceHostMachines as P, withNativeBuildRun as S, buildPlacementSettings as T, nativeRunHolder as _, offloadBuild as a, runCancellation as b, placementLoad as c, NATIVE_RUN_LOCK as d, NATIVE_RUN_WAIT_MS as f, describeNativeRunHolder as g, decideStopAction as h, closeOffload as i, inspectBuildMachines as j, resolveBuildMachine as k, remotePhaseText as l, clearNativeRunCancel as m, buildPlacementCandidates as n, offloadCheck as o, cancelledFailure as p, chooseBuildMachine as r, offloadPlacement as s, BuildConnection as t, simulatorRuntime as u, nativeRunWaitNotice as v, OffloadRefusal as w, runCancellationSignal as x, requestNativeRunCancel as y };
@@ -10,8 +10,14 @@ interface ExecOptions {
10
10
  omitEnv?: readonly string[];
11
11
  /** Text written to the child's stdin; `runFile` only. */
12
12
  input?: string;
13
+ /** `runFileAsync` only: called with the child right after it starts; a throw kills the child and rejects the call. */
14
+ onSpawn?: (child: ChildProcess) => void;
13
15
  /** `runFile` only: return stdout as written, without trimming surrounding whitespace. */
14
16
  untrimmed?: boolean;
17
+ /**
18
+ * `runFile` and `runFileAsync`: reject nonempty stderr even when the command exits successfully.
19
+ */
20
+ rejectStderr?: boolean;
15
21
  }
16
22
  interface Executor {
17
23
  run(cmd: string, opts?: ExecOptions): string;
@@ -1,12 +1,12 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
2
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
3
- import { R as deviceSlotKey, W as validateDeviceSlot } from "./config-CgYMahz7.mjs";
4
- import { x as workspaceLogsDir } from "./workspace-state-C59dqG-Z.mjs";
3
+ import { R as deviceSlotKey, W as validateDeviceSlot } from "./config-DC5jEtd1.mjs";
4
+ import { x as workspaceLogsDir } from "./workspace-state-CR9X86xJ.mjs";
5
5
  import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
6
- import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-Bn7jWDB1.mjs";
7
- import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-D6Se7gg_.mjs";
8
- import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-CBwCNicO.mjs";
9
- import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-Bvbf0SGY.mjs";
6
+ import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-CrW8aMb5.mjs";
7
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-EB0ySdGK.mjs";
8
+ import { a as waitForAppPid, i as startAndroidLogcat, n as parseLogcatLine, o as watchAppPid, t as androidClockOffset } from "./android-DE5g_5gv.mjs";
9
+ import { n as parseLogStreamLine, r as startIosLogStream, t as appNameFromBundleId } from "./ios-DCrkgXEM.mjs";
10
10
  import { existsSync } from "node:fs";
11
11
  import { isAbsolute, join, resolve } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
@@ -1,5 +1,5 @@
1
1
  import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
2
- import { t as NO_PROJECT_REFUSAL } from "./project-C3ChRLZy.mjs";
2
+ import { t as NO_PROJECT_REFUSAL } from "./project-B5eQ1USs.mjs";
3
3
  import chalk from "chalk";
4
4
  import { quotedPath as quotedPath$1 } from "@stim-cli/core";
5
5
  //#region src/diagnostics/launch-error-preview.ts
@@ -1,8 +1,8 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
3
  import { join } from "node:path";
4
4
  import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, normalize, parse as parse$1, sep as sep$1 } from "path";
5
- import { allMetroPorts, configCorruptRepair, findEnclosingWorktreeRoot, getConcurrencyLimits, getConfigPath, getConfigPath as getConfigPath$1, getProject, getProjectSettings, getRepoSettings, isPathPrefix, loadConfig, loadConfig as loadConfig$1, withConfigLock, withConfigLock as withConfigLock$1 } from "@stim-cli/core/state";
5
+ import { allMetroPorts, configCorruptRepair, findEnclosingWorktreeRoot, getConcurrencyLimits, getConfigPath, getConfigPath as getConfigPath$1, getProject, getProjectSettings, getRepoSettings, isPathPrefix, loadConfig, loadConfig as loadConfig$1, validateAutomaticPool, withConfigLock, withConfigLock as withConfigLock$1 } from "@stim-cli/core/state";
6
6
  import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
7
7
  import { InvalidArgumentError } from "commander";
8
8
  import { configDir } from "@stim-cli/core";
@@ -460,6 +460,10 @@ function writeConfigSetting(target, dottedKey, value) {
460
460
  if (value === void 0) {
461
461
  if (!deleteNested(settings, dottedKey)) return false;
462
462
  } else writeNested(settings, dottedKey, value);
463
+ if (target.scope === "machine") {
464
+ if (dottedKey === "remote.buildPoolDisabled" || dottedKey === "remote.machines") validateAutomaticPool("build", cfg);
465
+ if (dottedKey === "remote.devicePoolDisabled" || dottedKey === "remote.machines") validateAutomaticPool("device", cfg);
466
+ }
463
467
  saveConfig(cfg);
464
468
  return true;
465
469
  });
@@ -1,5 +1,5 @@
1
- import { d as getConfigDir } from "./config-CgYMahz7.mjs";
2
- import { w as withDirLock } from "./workspace-state-C59dqG-Z.mjs";
1
+ import { d as getConfigDir } from "./config-DC5jEtd1.mjs";
2
+ import { w as withDirLock } from "./workspace-state-CR9X86xJ.mjs";
3
3
  import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { createdDevicesFile, createdDevicesLock, readCreatedDevices, readCreatedDevices as readCreatedDevices$1 } from "@stim-cli/core/state";
5
5
  //#region src/devices/created-devices.ts
@@ -1,5 +1,5 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { y as repoRoot } from "./worktree-CsKYexJM.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { mt as repoRoot } from "./settings-CxgngUZk.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,4 +1,4 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
2
  import { openSync } from "node:fs";
3
3
  //#region src/detached-entry.ts
4
4
  const LOG_FILE_FLAG = "--log-file";
@@ -1,5 +1,5 @@
1
- import { h as resolvePackageJson, l as isPackageResolvable } from "./project-C3ChRLZy.mjs";
2
- import { E as readBundleSchemes, T as pickDevClientScheme } from "./app-install-D-PUENug.mjs";
1
+ import { h as isPackageResolvable, v as resolvePackageJson } from "./project-B5eQ1USs.mjs";
2
+ import { E as readBundleSchemes, T as pickDevClientScheme } from "./app-install-CFI4ptUL.mjs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { isJsonObject, readJsonObject } from "@stim-cli/core/state";
5
5
  //#region src/commands/dev-client.ts
@@ -1,11 +1,11 @@
1
- import { r as clockTime } from "./command-output-CBtzyIgF.mjs";
2
- import { H as projectDeviceSlots, R as deviceSlotKey, V as parseDeviceSlotOption, p as getProject } from "./config-CgYMahz7.mjs";
3
- import { s as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-C3ChRLZy.mjs";
4
- import { n as fileLeaseIo, o as parseLeaseDuration, p as takeLease, u as releaseWorkspaceLeases } from "./device-lease-Co-EwifR.mjs";
5
- import { E as getAvdNameForSerial, G as probeEmulatorSerial, N as memoizeEmulatorProbe, O as listAdbDevices, U as physicalDeviceModel, Y as resolvePhysicalDevice, c as androidPoolNoCandidatesRefusal, s as androidPoolCandidates } from "./android-DC3ZLuw0.mjs";
6
- import { l as parseDeviceWait, p as waitForDevice } from "./device-lease-run-w1xhCqIW.mjs";
7
- import { t as selectFromPool } from "./device-pool-F5WvRPtD.mjs";
8
- import { a as iosPoolCandidates, c as isWirelessIosDevice, f as resolveIosPhysicalDevice, l as listIosDevices, o as iosPoolNoCandidatesRefusal } from "./ios-device-vOaByMhw.mjs";
1
+ import { r as clockTime } from "./command-output-Bt8ygHE7.mjs";
2
+ import { H as projectDeviceSlots, R as deviceSlotKey, V as parseDeviceSlotOption, p as getProject } from "./config-DC5jEtd1.mjs";
3
+ import { r as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-B5eQ1USs.mjs";
4
+ import { n as fileLeaseIo, o as parseLeaseDuration, p as takeLease, u as releaseWorkspaceLeases } from "./device-lease-Cu7PtQpZ.mjs";
5
+ import { E as getAvdNameForSerial, G as probeEmulatorSerial, N as memoizeEmulatorProbe, O as listAdbDevices, U as physicalDeviceModel, Y as resolvePhysicalDevice, c as androidPoolNoCandidatesRefusal, s as androidPoolCandidates } from "./android-BdQC6zs1.mjs";
6
+ import { l as parseDeviceWait, p as waitForDevice } from "./device-lease-run-D38SnZtt.mjs";
7
+ import { t as selectFromPool } from "./device-pool-CP4rAsHx.mjs";
8
+ import { a as iosPoolCandidates, c as isWirelessIosDevice, f as resolveIosPhysicalDevice, l as listIosDevices, o as iosPoolNoCandidatesRefusal } from "./ios-device-CJ_ZOGky.mjs";
9
9
  import chalk from "chalk";
10
10
  //#region src/commands/device.ts
11
11
  const DEFAULT_FOR = "5m";