stim 1.17.2 → 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 (162) hide show
  1. package/README.md +50 -1
  2. package/dist/{activity-IRvJY_ru.mjs → activity-BSw0x84R.mjs} +4 -4
  3. package/dist/{agent-device-usage-output-BK41vnzN.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +8 -8
  4. package/dist/{android-B9yaNKwa.mjs → android-BXc6BmEi.mjs} +658 -404
  5. package/dist/{android-B_YNZy61.mjs → android-BdQC6zs1.mjs} +9 -9
  6. package/dist/android-BvV1gGdN.mjs +4 -0
  7. package/dist/{android-DE4v59Mb.mjs → android-DE5g_5gv.mjs} +2 -2
  8. package/dist/{android-cas-ZFpjJBL_.mjs → android-cas-C87geAg-.mjs} +5 -5
  9. package/dist/android-cas-compiler.mjs +2 -2
  10. package/dist/api-DIf_s86s.mjs +150 -0
  11. package/dist/api-run.d.mts +1 -0
  12. package/dist/api-run.mjs +145 -0
  13. package/dist/api.d.mts +218 -0
  14. package/dist/api.mjs +2 -0
  15. package/dist/{app-install-VPkI5WEg.mjs → app-install-CFI4ptUL.mjs} +33 -13
  16. package/dist/{attempt-Bk2ouQVL.mjs → attempt-DW-mQqM7.mjs} +14 -4
  17. package/dist/{web-Dl0KSRHf.mjs → browser-web-CDhqQxhv.mjs} +138 -176
  18. package/dist/{budget-DfcgFdQB.mjs → budget-Dz-kyXLv.mjs} +1391 -58
  19. package/dist/build-facts-B87vo-Im.d.mts +142 -0
  20. package/dist/{cache-manifest-DnUHBJaU.mjs → cache-manifest-DiwKSyv9.mjs} +3 -3
  21. package/dist/cache-manifest.mjs +1 -1
  22. package/dist/{chrome-BrcVWQyD.mjs → chrome-BTUOo8p2.mjs} +1 -1
  23. package/dist/cli-C9Zvgbdc.mjs +68 -0
  24. package/dist/cli.mjs +1 -1
  25. package/dist/{client-SvBdgObD.mjs → client-CuUo8Nvg.mjs} +381 -49
  26. package/dist/collector-run.d.mts +6 -0
  27. package/dist/collector-run.mjs +9 -9
  28. package/dist/{command-output-CDAIFD-8.mjs → command-output-Bt8ygHE7.mjs} +2 -2
  29. package/dist/{config-D0DbpZtM.mjs → config-DC5jEtd1.mjs} +9 -5
  30. package/dist/{created-devices-CpvzBL25.mjs → created-devices-D0s26Hx5.mjs} +2 -2
  31. package/dist/{dependency-state-CLcBHH2M.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
  32. package/dist/{detached-entry-CiTEgMR1.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
  33. package/dist/{dev-client-B-XC4uRH.mjs → dev-client-CDY_zAmD.mjs} +2 -2
  34. package/dist/{device-C8IOoJPv.mjs → device-BHw0WlHl.mjs} +8 -8
  35. package/dist/{device-capacity-ZC4XSZ4R.mjs → device-capacity-BoN1jQkO.mjs} +25 -14
  36. package/dist/device-host-worker.mjs +19 -19
  37. package/dist/{gradle-dJpre3Yn.mjs → device-ios-B2ruohE-.mjs} +661 -107
  38. package/dist/{device-lease-DpoS36_u.mjs → device-lease-Cu7PtQpZ.mjs} +9 -9
  39. package/dist/{device-lease-run-B8YltIH_.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
  40. package/dist/{device-pool-3o7s5lo4.mjs → device-pool-CP4rAsHx.mjs} +3 -3
  41. package/dist/{device-remote-hFSkpfQu.mjs → device-remote-B5GiUifk.mjs} +15 -16
  42. package/dist/{doctor-CFv1fCrF.mjs → doctor-PRJH94v6.mjs} +61 -34
  43. package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
  44. package/dist/{error-diagnostics-C-NMnhrk.mjs → error-diagnostics--v5HGOU0.mjs} +11 -11
  45. package/dist/{exec-CaErVv7t.mjs → exec-i8GDPwq9.mjs} +93 -6
  46. package/dist/{gc-DEmkg3Xh.mjs → gc-CyHMcKcn.mjs} +25 -471
  47. package/dist/{guide-CSmhMTf8.mjs → guide-dRaQJJk9.mjs} +681 -507
  48. package/dist/{hosted-android-E1Heoqnv.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
  49. package/dist/{hosted-client-Bp4knSwu.mjs → hosted-client-C5G4h_OJ.mjs} +2 -2
  50. package/dist/{hosted-ios-BnbeYOUD.mjs → hosted-ios-Bik035eL.mjs} +1 -1
  51. package/dist/{hosted-logs-OcgIBvCT.mjs → hosted-logs-CI9Az9a4.mjs} +9 -9
  52. package/dist/{hosted-macos-DcxKjtfH.mjs → hosted-macos-DABm3ScO.mjs} +5 -5
  53. package/dist/{hosted-native-1Ebbig4w.mjs → hosted-native-DbV2aUVw.mjs} +13 -9
  54. package/dist/{idle-shutdown-IGyNV8Cr.mjs → idle-shutdown-DYiMBn34.mjs} +7 -8
  55. package/dist/{ios-DSfnPfse.mjs → ios-BWbHFZVz.mjs} +19 -7
  56. package/dist/{ios-Cr1h5gnO.mjs → ios-DCrkgXEM.mjs} +1 -1
  57. package/dist/ios-DYUr9LGc.mjs +8 -0
  58. package/dist/ios-ITYno9rO.mjs +2241 -0
  59. package/dist/{ios-device-pAN4t54-.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
  60. package/dist/{ios-device-Ee7sDXfp.mjs → ios-device-CrW8aMb5.mjs} +1 -1
  61. package/dist/{ios-state-8L3lgum6.mjs → ios-state-By0XuLTQ.mjs} +1 -1
  62. package/dist/{launch-verify-lTnWZikR.mjs → launch-verify-DCveSE6d.mjs} +5 -5
  63. package/dist/{logs-BAaS7gS2.mjs → logs-Bao1HOMy.mjs} +13 -13
  64. package/dist/{macos-BIRQS90f.mjs → macos-ciyBdTY5.mjs} +194 -132
  65. package/dist/macos-nIOATJmR.mjs +2 -0
  66. package/dist/macos-run.mjs +1 -1
  67. package/dist/maintenance-run.mjs +349 -47
  68. package/dist/manifest-CX0d1IkZ.mjs +148 -0
  69. package/dist/{metro-g8NqiJp-.mjs → metro-DI2AjPF_.mjs} +196 -43
  70. package/dist/{metro-gateway-C-ijGI2F.mjs → metro-gateway-BxpJLIwh.mjs} +4 -4
  71. package/dist/{metro-store-CDDZHtPl.mjs → metro-store-BAHFcJm6.mjs} +16 -2
  72. package/dist/{build-plan-BDsSi09V.mjs → miss-reason-CjQCOKqq.mjs} +207 -249
  73. package/dist/{named-ports-C8m8EQs2.mjs → named-ports-B4iWH4E-.mjs} +70 -8
  74. package/dist/{native-runtime-BEK171xQ.mjs → native-runtime-BGxsbfny.mjs} +6 -6
  75. package/dist/{ndjson-PclOIwVY.mjs → ndjson-LGZAMsqa.mjs} +8 -4
  76. package/dist/offload-worker.d.mts +3 -45
  77. package/dist/offload-worker.mjs +11 -11
  78. package/dist/{ownership-DyRQru0q.mjs → ownership-EB0ySdGK.mjs} +3 -3
  79. package/dist/{page-QF_Ke10s.mjs → page-Bv9s2KwY.mjs} +1 -1
  80. package/dist/placement-log-Dxe34rJm.mjs +88 -0
  81. package/dist/plan-placement-BVY59qa8.mjs +290 -0
  82. package/dist/{ports-4nYqxPWC.mjs → ports-ByPc0_97.mjs} +3 -3
  83. package/dist/{prebuild-D7RUMkwN.mjs → prebuild-BKJ3wJI1.mjs} +5 -5
  84. package/dist/preview-BbSottmO.mjs +986 -0
  85. package/dist/{rolldown-runtime-BsOwBuO_.mjs → process-identity-Biv3arCO.mjs} +11 -1
  86. package/dist/project-B5eQ1USs.mjs +612 -0
  87. package/dist/{pull-request-pxnDCQzn.mjs → pull-request-IHNdMnG8.mjs} +1 -1
  88. package/dist/pull-requests.mjs +1 -1
  89. package/dist/react-native-ios-BMh2i25I.mjs +2 -0
  90. package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
  91. package/dist/{recordings-BNgsD1Tr.mjs → recordings-Bv8McZN4.mjs} +1 -1
  92. package/dist/{reload-DcRxj3qG.mjs → reload-rAPdqeRR.mjs} +14 -15
  93. package/dist/{remote-cache-Ci4DQYYj.mjs → remote-cache-N3hAEaAL.mjs} +5 -5
  94. package/dist/{run-CkE9y0nc.mjs → run-lAkle1-c.mjs} +5 -5
  95. package/dist/{server-bare-BkrSxSsZ.mjs → server-bare-CkIjnegq.mjs} +5 -6
  96. package/dist/server-expo-DGsdUGX2.mjs +2 -0
  97. package/dist/{server-expo-CHTyXD0G.mjs → server-expo-n3tUi3Em.mjs} +5 -6
  98. package/dist/{settings-SR9OmW9h.mjs → settings-2am7TSxp.mjs} +5 -5
  99. package/dist/{settings-Cfd-0r2d.mjs → settings-CxgngUZk.mjs} +116 -103
  100. package/dist/{settings-BBpMcDbD.mjs → settings-Djl-mpjX.mjs} +1 -1
  101. package/dist/settings.schema.json +198 -9
  102. package/dist/{simslim-BWNrc3M3.mjs → simslim-D9LkJxIO.mjs} +7 -7
  103. package/dist/{slot-launch-DmjBmpQV.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
  104. package/dist/{spawn-claims-D0XfSe8u.mjs → spawn-claims-Kqiifsk2.mjs} +1 -1
  105. package/dist/{spawn-entry-jw19m8Nl.mjs → spawn-entry-Dcb7sDUz.mjs} +1 -0
  106. package/dist/{stage-CzaiwFsI.mjs → stage-BgaZJVZY.mjs} +14 -3
  107. package/dist/{start-AlfCPRVU.mjs → start-D8NbxNBb.mjs} +1 -1
  108. package/dist/{start-DUz3mYdb.mjs → start-DtxthMfI.mjs} +34 -27
  109. package/dist/{state-PeQiJuIu.mjs → state-D2KtnALG.mjs} +4 -4
  110. package/dist/{state-DyaNTgfR.mjs → state-Tp4uImDS.mjs} +5 -3
  111. package/dist/{state-B4PQFXMW.d.mts → state-lKh8shBp.d.mts} +2 -3
  112. package/dist/{stats-Bq4fJOdB.mjs → stats-8EJ5ivFT.mjs} +6 -6
  113. package/dist/{status-DlKvVJBE.mjs → status-BEeL6IKz.mjs} +6 -4
  114. package/dist/{status-BA2pehwf.mjs → status-BOyp0CUl.mjs} +31 -34
  115. package/dist/{stim-desktop-Cnz8CPnl.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
  116. package/dist/{stim-installations-QMEI32v1.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
  117. package/dist/stop-D0UIpZuh.mjs +72 -0
  118. package/dist/{stop-zF1y04f2.mjs → stop-DRipAg-e.mjs} +2 -2
  119. package/dist/{stop-DQIasgKp.mjs → stop-zDlknFoz.mjs} +79 -33
  120. package/dist/supervisor-run.d.mts +24 -22
  121. package/dist/supervisor-run.mjs +21 -22
  122. package/dist/{support-CsJNVfOc.mjs → support-CNqYkV0y.mjs} +7 -7
  123. package/dist/{support-WvD__tSV.mjs → support-DsNaFg6D.mjs} +5 -5
  124. package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
  125. package/dist/{toolchain-DNyR3NPq.mjs → toolchain-C3xSoyUl.mjs} +475 -269
  126. package/dist/{trigger-Bemu8ytw.mjs → trigger-CAhmG-4s.mjs} +6 -6
  127. package/dist/trigger-CoalsMTV.mjs +2 -0
  128. package/dist/{warm-progress-DF4JRvYI.mjs → warm-progress-pFLB2e6P.mjs} +135 -38
  129. package/dist/{status-CzS4bPO9.mjs → watchman-BL1IdOtq.mjs} +75 -7
  130. package/dist/web-DFpFeZu5.mjs +2 -0
  131. package/dist/web-DbbrPUn0.mjs +127 -0
  132. package/dist/web-run.mjs +10 -10
  133. package/dist/{workspace-state-DqcCbpE7.mjs → workspace-state-CR9X86xJ.mjs} +3 -3
  134. package/dist/{ownership-BMLqyBgJ.mjs → workspaces-Djb2gfi9.mjs} +661 -23
  135. package/dist/{worktree-Be_7NLKy.mjs → worktree-BL4M1rhB.mjs} +252 -50
  136. package/dist/{worktree-j3IcFAI5.mjs → worktree-DV-A0LNL.mjs} +1 -1
  137. package/package.json +10 -5
  138. package/shim/bundle-response.cjs +2 -1
  139. package/shim/bundle-response.d.cts +1 -1
  140. package/shim/expo-metro-config.cjs +1 -1
  141. package/dist/build-progress-D0WkjCPd.mjs +0 -1036
  142. package/dist/build-slots-41v_d2x9.mjs +0 -142
  143. package/dist/cli-CYXb29oE.mjs +0 -51
  144. package/dist/deps-iKw0eD4P.mjs +0 -438
  145. package/dist/device-ios-C2Um-XUR.mjs +0 -412
  146. package/dist/errors-B6W7FkxQ.mjs +0 -15
  147. package/dist/guide-status-Du-ZQ3FD.mjs +0 -125
  148. package/dist/idle-BXG__1BA.mjs +0 -176
  149. package/dist/in-use-CvGOUn-x.mjs +0 -130
  150. package/dist/ios-BJ4XUSe1.mjs +0 -3867
  151. package/dist/native-run-D1Q56rAD.mjs +0 -158
  152. package/dist/preview-B-g9d7kV.mjs +0 -318
  153. package/dist/process-identity-BmRm1qV0.mjs +0 -12
  154. package/dist/project-D47Rh0ly.mjs +0 -276
  155. package/dist/server-expo-CeakhI8P.mjs +0 -2
  156. package/dist/state-BKa8wNN5.mjs +0 -148
  157. package/dist/stop-BIiM49EY.mjs +0 -48
  158. package/dist/stop-cause-rhmGfwvt.mjs +0 -97
  159. package/dist/trigger-CXts6qt1.mjs +0 -2
  160. package/dist/watchman-APYjXSQa.mjs +0 -48
  161. package/dist/workspace-process-lock-2mNzOlaB.mjs +0 -58
  162. package/dist/workspaces-Bcib97-6.mjs +0 -306
@@ -1,16 +1,16 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, d as getConfigDir } from "./config-D0DbpZtM.mjs";
3
- import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
4
- import { r as register } from "./cache-manifest-DnUHBJaU.mjs";
5
- import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-CDAIFD-8.mjs";
6
- import { c as writeWorkspaceState, d as sharedBuildCache, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState, w as withDirLock$1 } from "./workspace-state-DqcCbpE7.mjs";
7
- import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-D0XfSe8u.mjs";
8
- import { createHash, randomBytes } from "node:crypto";
1
+ import { n as ownership_claim_exports } from "./process-identity-Biv3arCO.mjs";
2
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
+ import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-Bt8ygHE7.mjs";
4
+ import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, d as getConfigDir } from "./config-DC5jEtd1.mjs";
5
+ import { c as writeWorkspaceState, d as sharedBuildCache, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState, w as withDirLock$1 } from "./workspace-state-CR9X86xJ.mjs";
6
+ import { r as register } from "./cache-manifest-DiwKSyv9.mjs";
7
+ import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Kqiifsk2.mjs";
9
8
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
10
9
  import { join } from "node:path";
11
- import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
12
10
  import { join as join$1 } from "path";
11
+ import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
13
12
  import { artifactIn, buildCacheKey, resolveArtifact, storeArtifact } from "@stim-cli/core";
13
+ import { createHash, randomBytes } from "node:crypto";
14
14
  import { isDeepStrictEqual } from "util";
15
15
  import * as expoFingerprint from "@expo/fingerprint";
16
16
  import { buildUploadTimeoutMs } from "@stim-cli/cache";
@@ -1,7 +1,7 @@
1
- import { R as deviceSlotKey } from "./config-D0DbpZtM.mjs";
2
- import { a as formatElapsed, r as clockTime } from "./command-output-CDAIFD-8.mjs";
3
- import { a as parseLease, c as raiseLease, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-DpoS36_u.mjs";
4
- import { a as VERIFY_TIMEOUT_MS, m as APP_READINESS_TIMEOUT_MS } from "./launch-verify-lTnWZikR.mjs";
1
+ import { a as formatElapsed, r as clockTime } from "./command-output-Bt8ygHE7.mjs";
2
+ import { R as deviceSlotKey } from "./config-DC5jEtd1.mjs";
3
+ import { a as parseLease, c as raiseLease, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-Cu7PtQpZ.mjs";
4
+ import { a as VERIFY_TIMEOUT_MS, m as APP_READINESS_TIMEOUT_MS } from "./launch-verify-DCveSE6d.mjs";
5
5
  //#region src/engine/device-lease-run.ts
6
6
  const LEASE_STEP_FLOOR_MS = 6e4;
7
7
  const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
@@ -1,6 +1,6 @@
1
- import { R as deviceSlotKey } from "./config-D0DbpZtM.mjs";
2
- import { a as parseLease, f as selectPoolDevice, n as fileLeaseIo, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-DpoS36_u.mjs";
3
- import { i as DEVICE_WAIT_POLL_MS, n as DEVICE_BUSY, o as leaseExpiryText } from "./device-lease-run-B8YltIH_.mjs";
1
+ import { R as deviceSlotKey } from "./config-DC5jEtd1.mjs";
2
+ import { a as parseLease, f as selectPoolDevice, n as fileLeaseIo, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-Cu7PtQpZ.mjs";
3
+ import { i as DEVICE_WAIT_POLL_MS, n as DEVICE_BUSY, o as leaseExpiryText } from "./device-lease-run-D38SnZtt.mjs";
4
4
  //#region src/engine/device-pool.ts
5
5
  function heldPoolId(root, platform, now, io = fileLeaseIo, slot = "default") {
6
6
  const record = io.readHolder(root)[deviceSlotKey(platform, slot)];
@@ -1,18 +1,17 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { d as getConfigDir } from "./config-D0DbpZtM.mjs";
3
- import { a as formatElapsed } from "./command-output-CDAIFD-8.mjs";
4
- import { K as planMetroReach } from "./settings-Cfd-0r2d.mjs";
5
- import { u as ownedDeviceLabel } from "./project-D47Rh0ly.mjs";
6
- import { o as pidExists } from "./metro-g8NqiJp-.mjs";
7
- import { C as workspaceStateFile, v as workspaceDir, w as withDirLock, x as workspaceLogsDir$1, y as workspaceId } from "./workspace-state-DqcCbpE7.mjs";
8
- import { a as clearRemoteSession, c as readMetroTunnel, u as readRemoteSession } from "./state-BKa8wNN5.mjs";
9
- import { T as sanitizeDeviceLabel } from "./ios-DSfnPfse.mjs";
10
- import { u as probePublicHttp } from "./ownership-BMLqyBgJ.mjs";
11
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
12
- import { i as INSTALL_ERROR, o as LAUNCH_ERROR, u as devClientDeepLink } from "./app-install-VPkI5WEg.mjs";
13
- import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-lTnWZikR.mjs";
14
- import { t as compareStimVersions } from "./stim-installations-QMEI32v1.mjs";
15
- import { c as nativeRunWaitNotice } from "./native-run-D1Q56rAD.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { a as formatElapsed } from "./command-output-Bt8ygHE7.mjs";
3
+ import { d as getConfigDir } from "./config-DC5jEtd1.mjs";
4
+ import { C as workspaceStateFile, v as workspaceDir, w as withDirLock, x as workspaceLogsDir$1, y as workspaceId } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { C as clearRemoteSession, E as readMetroTunnel, O as readRemoteSession, o as ownedDeviceLabel } from "./project-B5eQ1USs.mjs";
6
+ import { J as planMetroReach } from "./settings-CxgngUZk.mjs";
7
+ import { s as pidExists } from "./metro-DI2AjPF_.mjs";
8
+ import { S as probePublicHttp } from "./workspaces-Djb2gfi9.mjs";
9
+ import { E as sanitizeDeviceLabel } from "./ios-BWbHFZVz.mjs";
10
+ import { a as withWorkspaceProcessLock } from "./named-ports-B4iWH4E-.mjs";
11
+ import { v as nativeRunWaitNotice } from "./client-CuUo8Nvg.mjs";
12
+ import { i as INSTALL_ERROR, o as LAUNCH_ERROR, u as devClientDeepLink } from "./app-install-CFI4ptUL.mjs";
13
+ import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-DCveSE6d.mjs";
14
+ import { t as compareStimVersions } from "./stim-installations-DbmUjsLv.mjs";
16
15
  import { existsSync, mkdirSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
17
16
  import { dirname, join, resolve } from "node:path";
18
17
  import { easMachineStateRoot, easMachineStateRoot as easMachineStateRoot$1, easSessionLedgerFile, easSessionLedgerLock, readEasSessionLedger, readEasSessionLedger as readEasSessionLedger$1, readJsonObject, validEasSessionClaim } from "@stim-cli/core/state";
@@ -1321,4 +1320,4 @@ function bundleEntryPoint(root, isExpo) {
1321
1320
  return local ? normalized : `node_modules/${normalized}`;
1322
1321
  }
1323
1322
  //#endregion
1324
- export { listOwnedSessionsArgs as C, verifyStoppedSession as D, stopSessionArgs as E, readRemoteSimulatorArch as O, isDefinitiveMissingSessionError as S, parseSessionListPage as T, easCliSupport as _, ensureMetroReachable as a, getSessionArgs as b, remoteAndroidDeps as c, withRemoteSessionLock as d, withEasProjectLock as f, MIN_EAS_CLI_SIMULATOR_VERSION as g, removeEasSessionClaim as h, endRecordedSession as i, gateMetroOrigin as k, remoteIosDeps as l, readEasSessionLedger$1 as m, binOnPath as n, ensureRemoteBootOwned as o, easMachineStateRoot$1 as p, bundleEntryPoint as r, readInstalledEasCliVersion as s, REMOTE_SESSION_ERROR as t, resolveRemoteContext as u, easCliUpgradeRemedy as v, ownedSessionName as w, inspectSessionForTeardown as x, findOrphanedOwnedSessions as y };
1323
+ export { gateMetroOrigin as A, isDefinitiveMissingSessionError as C, stopSessionArgs as D, parseSessionListPage as E, verifyStoppedSession as O, inspectSessionForTeardown as S, ownedSessionName as T, MIN_EAS_CLI_SIMULATOR_VERSION as _, ensureMetroReachable as a, findOrphanedOwnedSessions as b, remoteAndroidDeps as c, withRemoteSessionLock as d, withEasProjectLock as f, MIN_EAS_CLI_DEVICE_VERSION as g, removeEasSessionClaim as h, endRecordedSession as i, readRemoteSimulatorArch as k, remoteIosDeps as l, readEasSessionLedger$1 as m, binOnPath as n, ensureRemoteBootOwned as o, easMachineStateRoot$1 as p, bundleEntryPoint as r, readInstalledEasCliVersion as s, REMOTE_SESSION_ERROR as t, resolveRemoteContext as u, easCliSupport as v, listOwnedSessionsArgs as w, getSessionArgs as x, easCliUpgradeRemedy as y };
@@ -1,36 +1,37 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { _ as loadConfig$1, p as getProject, s as configCorruptRepair, u as getConcurrencyLimits } from "./config-D0DbpZtM.mjs";
3
- import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-CDAIFD-8.mjs";
4
- import { B as settingsLayers, Ct as filesystemDevice, Et as temporaryRoot, H as unknownSettingKeys, I as settingOrigin, M as remoteIosSetting, O as projectOptimizations, P as resolveSettings, R as settingShapeErrors, U as webSettings, Y as compilerCacheFallbackMessage, Z as resolveOptimizations, dt as listWorktrees, ft as locallyKnownUpstream, gt as repoRoot, i as SETTING_SHAPE_REMEDY, it as gitCommonDir, j as remoteAndroidSetting, n as PATH_SETTINGS, nt as dirtyFingerprintFiles, r as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, v as iosSimSlimProfileSetting, vt as resolveSourceCheckout, wt as makeTemporaryDirectory, y as mergeSettingsLayers } from "./settings-Cfd-0r2d.mjs";
5
- import { l as isPackageResolvable, n as appProjectProblem, r as detectIsExpo, s as findProjectRoot$1 } from "./project-D47Rh0ly.mjs";
6
- import { _ as workspaceDerivedData, d as sharedBuildCache } from "./workspace-state-DqcCbpE7.mjs";
7
- import { V as inspectWatchmanMemory, i as inspectBudget, n as budgetLine } from "./budget-DfcgFdQB.mjs";
8
- import { C as diffFingerprintSources, D as fingerprintProject, h as listBuildLocks } from "./device-lease-DpoS36_u.mjs";
9
- import { n as listBuildSlots } from "./build-slots-41v_d2x9.mjs";
10
- import { D as hostSystemImageArch, ft as parkedMaxSetting, o as androidHome, ot as POOL_SETTING_REMEDY } from "./android-B_YNZy61.mjs";
11
- import { A as hostMemoryPressureAdvice, c as iosRuntimeMatches, j as readHostMemoryPressure, p as listIosRuntimes, y as pickDefaultIosCreation } from "./ios-DSfnPfse.mjs";
12
- import { C as podInstallCommand, D as projectCmakeLauncher, S as bundlerPin, f as ccacheEnabled, i as macosToolchain, m as detectXcodeMajor, n as androidToolchain, r as iosToolchain, t as androidRequirements } from "./toolchain-DNyR3NPq.mjs";
13
- import { S as realIo, g as inspectBuildMachines, o as offloadCheck, u as simulatorRuntime, y as inspectDeviceHostMachines } from "./client-SvBdgObD.mjs";
14
- import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-BrcVWQyD.mjs";
15
- import { i as countLiveOwnedDevices } from "./device-capacity-ZC4XSZ4R.mjs";
16
- import { d as androidPathRoomRemedy, l as androidPathRoom, n as apkOutputsDir, t as androidSdkRefusal, u as androidPathRoomMessage } from "./gradle-dJpre3Yn.mjs";
17
- import { g as resolveRuntime, m as resolveDeviceType } from "./support-CsJNVfOc.mjs";
18
- import { f as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig } from "./remote-cache-Ci4DQYYj.mjs";
19
- import { _ as easCliSupport, g as MIN_EAS_CLI_SIMULATOR_VERSION, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy } from "./device-remote-hFSkpfQu.mjs";
20
- import { n as inspectStimVersions, t as compareStimVersions } from "./stim-installations-QMEI32v1.mjs";
21
- import { n as simslimIsOnPath, r as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-BWNrc3M3.mjs";
22
- import { r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-ZFpjJBL_.mjs";
23
- import { r as maintenanceStatus, t as maintenanceLine } from "./status-DlKvVJBE.mjs";
24
- import { n as recordDoctorRun } from "./guide-status-Du-ZQ3FD.mjs";
25
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-CLcBHH2M.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-Bt8ygHE7.mjs";
3
+ import { _ as loadConfig$1, p as getProject, s as configCorruptRepair, u as getConcurrencyLimits } from "./config-DC5jEtd1.mjs";
4
+ import { _ as workspaceDerivedData, d as sharedBuildCache } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { f as appProjectProblem, h as isPackageResolvable, p as detectIsExpo, r as findProjectRoot } from "./project-B5eQ1USs.mjs";
6
+ import { B as settingShapeErrors, Et as compilerCacheFallbackMessage, G as webSettings, H as settingsLayers, I as resolveSettings, M as remoteAndroidSetting, Ot as resolveOptimizations, P as remoteIosSetting, R as settingOrigin, St as makeTemporaryDirectory, W as unknownSettingKeys, et as dirtyFingerprintFiles, gt as resolveSourceCheckout, i as SETTING_SHAPE_REMEDY, k as projectOptimizations, lt as listWorktrees, mt as repoRoot, n as PATH_SETTINGS, nt as gitCommonDir, r as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, ut as locallyKnownUpstream, v as iosSimSlimProfileSetting, wt as temporaryRoot, xt as filesystemDevice, y as mergeSettingsLayers } from "./settings-CxgngUZk.mjs";
7
+ import { St as inspectWatchmanMemory, a as inspectBudget, n as budgetLine } from "./budget-Dz-kyXLv.mjs";
8
+ import { N as listBuildSlots } from "./workspaces-Djb2gfi9.mjs";
9
+ import { C as diffFingerprintSources, D as fingerprintProject, h as listBuildLocks } from "./device-lease-Cu7PtQpZ.mjs";
10
+ import { D as hostSystemImageArch, ft as parkedMaxSetting, o as androidHome, ot as POOL_SETTING_REMEDY } from "./android-BdQC6zs1.mjs";
11
+ import { M as readHostMemoryPressure, b as pickDefaultIosCreation, j as hostMemoryPressureAdvice, l as iosRuntimeMatches, m as listIosRuntimes } from "./ios-BWbHFZVz.mjs";
12
+ import { L as realIo, P as inspectDeviceHostMachines, j as inspectBuildMachines, o as offloadCheck, u as simulatorRuntime } from "./client-CuUo8Nvg.mjs";
13
+ import { i as countLiveOwnedDevices } from "./device-capacity-BoN1jQkO.mjs";
14
+ import { a as projectCmakeLauncher } from "./manifest-CX0d1IkZ.mjs";
15
+ import { A as bundlerPin, i as macosToolchain, j as podInstallCommand, n as androidToolchain, r as iosToolchain, t as androidRequirements, x as detectXcodeMajor } from "./toolchain-C3xSoyUl.mjs";
16
+ import { f as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig } from "./remote-cache-N3hAEaAL.mjs";
17
+ import { _ as androidPathRoomMessage, a as apkOutputsDir, c as ccacheEnabled, g as androidPathRoom, p as androidSdkRefusal, v as androidPathRoomRemedy } from "./device-ios-B2ruohE-.mjs";
18
+ import { _ as MIN_EAS_CLI_SIMULATOR_VERSION, s as readInstalledEasCliVersion, v as easCliSupport, y as easCliUpgradeRemedy } from "./device-remote-B5GiUifk.mjs";
19
+ import { n as inspectStimVersions, t as compareStimVersions } from "./stim-installations-DbmUjsLv.mjs";
20
+ import { n as simslimIsOnPath, r as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-D9LkJxIO.mjs";
21
+ import { r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-C87geAg-.mjs";
22
+ import { g as resolveRuntime, m as resolveDeviceType } from "./support-CNqYkV0y.mjs";
23
+ import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-DKaS1OM9.mjs";
24
+ import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-BTUOo8p2.mjs";
25
+ import { r as maintenanceStatus, t as maintenanceLine } from "./status-BEeL6IKz.mjs";
26
+ import { a as writeIgnoreDirs, i as watchedCheckouts, n as inspectNestedWorktrees, r as nestedWorktreeFinding, s as recordDoctorRun } from "./doctor-watchman-wZhyTdp4.mjs";
26
27
  import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
27
28
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
28
- import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
29
- import { homedir } from "os";
30
29
  import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
31
- import { InvalidArgumentError } from "commander";
32
30
  import { isJsonObject, maintenanceNdjsonFile, readHostedAppMetadata, readHostedSessions, readJsonObject, readStats, settingDefinition } from "@stim-cli/core/state";
33
31
  import chalk from "chalk";
32
+ import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
33
+ import { InvalidArgumentError } from "commander";
34
+ import { homedir } from "os";
34
35
  import * as expoFingerprint from "@expo/fingerprint";
35
36
  //#region src/diagnostics/sandbox.ts
36
37
  /**
@@ -1148,7 +1149,8 @@ function checkAndroidSdk(projectRoot, platform) {
1148
1149
  const refusal = androidSdkRefusal({
1149
1150
  sdkPath,
1150
1151
  sdkExists: existsSync$1(sdkPath),
1151
- hasLocalProperties: existsSync$1(join$1(androidDir, "local.properties"))
1152
+ hasLocalProperties: existsSync$1(join$1(androidDir, "local.properties")),
1153
+ localPropertiesPath: "android/local.properties"
1152
1154
  });
1153
1155
  if (!refusal) return null;
1154
1156
  return {
@@ -1174,7 +1176,9 @@ function androidCcacheFindings(projectRoot, platform, lookupCcache) {
1174
1176
  function checkAppProject(projectRoot) {
1175
1177
  const problem = appProjectProblem(projectRoot);
1176
1178
  if (!problem) return null;
1177
- return finding("cost", problem.kind === "unreadable" ? "This package.json does not parse" : "This directory is not a React Native or Expo app", `${problem.message} \`stim start\`, \`stim ios\` and \`stim android\` refuse here with STIM_NO_PROJECT, so nothing below was measured against an app.`, problem.remedy);
1179
+ const result = finding("cost", problem.kind === "unreadable" ? "This package.json does not parse" : "This directory is not a React Native or Expo app", `${problem.message} \`stim start\`, \`stim ios\` and \`stim android\` refuse here with STIM_NO_PROJECT, so nothing below was measured against an app.`, problem.remedy);
1180
+ if (problem.kind === "not-an-app") result.code = "not-an-app";
1181
+ return result;
1178
1182
  }
1179
1183
  function agentDeviceIsOnPath() {
1180
1184
  try {
@@ -1432,7 +1436,7 @@ function doctorSuccessLines(platform, stim, budget = null) {
1432
1436
  ...budgetLines(budget),
1433
1437
  "",
1434
1438
  "Project",
1435
- phaseLine("project", "source checkout, dependencies, local upstream"),
1439
+ phaseLine("project", "source checkout, dependencies, local upstream, nested worktrees Watchman would crawl"),
1436
1440
  phaseLine("settings", "every Stim setting type, machine config paths, companions and inert keys")
1437
1441
  ];
1438
1442
  if (platform !== "android") {
@@ -1506,8 +1510,8 @@ function applySandboxFix(root, env = process.env) {
1506
1510
  console.error(chalk.dim("Added writes to Stim's state directory, the simulator XPC service, and local port binding. Claude Code reads project settings from the directory a session starts in, so this file only counts for sessions rooted there. Restart the session for it to take effect."));
1507
1511
  }
1508
1512
  function doctorCommand(program, version, inspectVersions = inspectStimVersions, host = process.platform) {
1509
- program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. The checkout is left untouched unless --fix is passed; --platform filters native findings. Each run in a React Native or Expo app is recorded in Stim state so guide can say when doctor is due.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance when the report names it, and stale Android .cxx configurations in this checkout; ask each remote Mac in remote.machines for build and device-host approval. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
1510
- const root = findProjectRoot$1(process.cwd());
1513
+ program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. The checkout is left untouched unless --fix is passed; --platform filters native findings. Each run in a React Native or Expo app is recorded in Stim state so guide can say when doctor is due.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance when the report names it, and stale Android .cxx configurations in this checkout; add linked worktrees nested in a checkout to its .watchmanconfig ignore_dirs; ask each remote Mac in remote.machines for build and device-host approval. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
1514
+ const root = findProjectRoot(process.cwd());
1511
1515
  if (!root) {
1512
1516
  refuseNoProject({ json: Boolean(opts.json) });
1513
1517
  return;
@@ -1523,6 +1527,26 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
1523
1527
  console.error(phaseLine("cache", `CMake cleanup failed: ${error.message}`));
1524
1528
  process.exitCode = 1;
1525
1529
  }
1530
+ const nestedToFix = inspectNestedWorktrees(root);
1531
+ const watchedToFix = await watchedCheckouts(nestedToFix.map((entry) => entry.checkout));
1532
+ for (const entry of nestedToFix) {
1533
+ let result;
1534
+ try {
1535
+ result = writeIgnoreDirs(entry);
1536
+ } catch (error) {
1537
+ result = {
1538
+ status: "refused",
1539
+ reason: `${entry.configPath} could not be written: ${error.message}`
1540
+ };
1541
+ }
1542
+ if (result.status === "refused") {
1543
+ console.error(phaseLine("checkout", `kept ${result.reason}; add ${entry.add.join(", ")} to ignore_dirs by hand`));
1544
+ process.exitCode = 1;
1545
+ } else {
1546
+ console.error(phaseLine("checkout", `${result.status} ${entry.configPath}: ignore_dirs ${entry.add.join(", ")}`));
1547
+ if (watchedToFix.has(entry.checkout)) console.error(phaseLine("checkout", `Watchman watches ${entry.checkout} and reads the file only when it adds a root: run \`watchman watch-del ${entry.checkout}\`, then restart watchman to free its memory`));
1548
+ }
1549
+ }
1526
1550
  }
1527
1551
  const stim = await inspectVersions(version);
1528
1552
  const findings = runDoctor(root, {
@@ -1544,13 +1568,16 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
1544
1568
  findings.push(...budget.findings);
1545
1569
  const watchman = await inspectWatchmanMemory();
1546
1570
  if (watchman) findings.push(watchman);
1571
+ const nestedWorktrees = inspectNestedWorktrees(root);
1572
+ const watched = await watchedCheckouts(nestedWorktrees.map((entry) => entry.checkout));
1573
+ for (const entry of nestedWorktrees) findings.push(nestedWorktreeFinding(entry, watched.has(entry.checkout)));
1547
1574
  const checksIos = opts.platform !== "android" && host === "darwin";
1548
1575
  const checksAndroid = opts.platform === "android" || opts.platform === void 0 && (existsSync(join(root, "android")) || detectIsExpo(root));
1549
1576
  const checksMacos = host === "darwin" && opts.platform === void 0 && existsSync(join(root, "Package.swift"));
1550
1577
  const offloadTargets = () => [
1551
1578
  ...checksIos ? [{
1552
1579
  platform: "ios",
1553
- local: iosToolchain(),
1580
+ local: iosToolchain(root),
1554
1581
  runtime: iosTargetRuntime(root),
1555
1582
  cocoapodsPinned: bundlerPin(root) !== null
1556
1583
  }] : [],
@@ -0,0 +1,259 @@
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { E as upsertProject, d as getConfigDir, p as getProject } from "./config-DC5jEtd1.mjs";
3
+ import { f as appProjectProblem } from "./project-B5eQ1USs.mjs";
4
+ import { lt as listWorktrees, mt as repoRoot } from "./settings-CxgngUZk.mjs";
5
+ import { o as runWatchman, r as parseWatchRoots } from "./watchman-BL1IdOtq.mjs";
6
+ import { t as compareStimVersions } from "./stim-installations-DbmUjsLv.mjs";
7
+ import { mkdirSync, readFileSync, realpathSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
8
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
9
+ //#region src/guide-status.ts
10
+ const DAY_MS = 864e5;
11
+ const DOCTOR_STALE_MS = 7 * DAY_MS;
12
+ const UPDATE_CHECK_INTERVAL_MS = DAY_MS;
13
+ const UPDATE_CHECK_TIMEOUT_MS = 2e3;
14
+ const LATEST_URL = "https://registry.npmjs.org/stim/latest";
15
+ const PLATFORMS = ["ios", "android"];
16
+ function recordDoctorRun(projectRoot, platform, version, now = /* @__PURE__ */ new Date()) {
17
+ const run = {
18
+ at: now.toISOString(),
19
+ version
20
+ };
21
+ try {
22
+ if (appProjectProblem(projectRoot)) return;
23
+ upsertProject(projectRoot, (existing) => {
24
+ const doctorRuns = { ...existing.doctorRuns };
25
+ for (const target of platform ? [platform] : PLATFORMS) doctorRuns[target] = run;
26
+ return { doctorRuns };
27
+ });
28
+ } catch {}
29
+ }
30
+ function doctorDueReason(record, running, now) {
31
+ const at = record ? Date.parse(record.at) : NaN;
32
+ if (!record || Number.isNaN(at)) return "never run";
33
+ if (record.version !== running) return `last run with stim ${record.version}`;
34
+ const age = now.getTime() - at;
35
+ if (age > DOCTOR_STALE_MS) return `last run ${Math.floor(age / DAY_MS)} days ago`;
36
+ return null;
37
+ }
38
+ function updateCacheFile() {
39
+ return join(getConfigDir(), "update-check.json");
40
+ }
41
+ function readUpdateCache() {
42
+ try {
43
+ const parsed = JSON.parse(readFileSync(updateCacheFile(), "utf-8"));
44
+ if (typeof parsed?.checkedAt !== "string") return null;
45
+ return {
46
+ checkedAt: parsed.checkedAt,
47
+ latest: typeof parsed.latest === "string" ? parsed.latest : null
48
+ };
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+ function writeUpdateCache(cache) {
54
+ const target = updateCacheFile();
55
+ const tmp = `${target}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
56
+ try {
57
+ mkdirSync(getConfigDir(), { recursive: true });
58
+ writeFileSync(tmp, `${JSON.stringify(cache)}\n`);
59
+ renameSync(tmp, target);
60
+ } catch {
61
+ try {
62
+ unlinkSync(tmp);
63
+ } catch {}
64
+ }
65
+ }
66
+ async function fetchLatest(fetchImpl) {
67
+ const res = await fetchImpl(LATEST_URL, { signal: AbortSignal.timeout(UPDATE_CHECK_TIMEOUT_MS) });
68
+ if (!res.ok) return null;
69
+ const body = await res.json();
70
+ return typeof body.version === "string" ? body.version : null;
71
+ }
72
+ async function checkForUpdate(running, { now = /* @__PURE__ */ new Date(), fetch: fetchImpl = fetch } = {}) {
73
+ if (process.env.STIM_NO_UPDATE_CHECK) return null;
74
+ const cached = readUpdateCache();
75
+ const checkedAt = cached ? Date.parse(cached.checkedAt) : NaN;
76
+ let latest = cached?.latest ?? null;
77
+ if (Number.isNaN(checkedAt) || now.getTime() - checkedAt > UPDATE_CHECK_INTERVAL_MS) {
78
+ try {
79
+ latest = await fetchLatest(fetchImpl);
80
+ } catch {
81
+ latest = null;
82
+ }
83
+ writeUpdateCache({
84
+ checkedAt: now.toISOString(),
85
+ latest
86
+ });
87
+ }
88
+ if (!latest) return null;
89
+ const comparison = compareStimVersions(latest, running);
90
+ return comparison !== null && comparison > 0 ? latest : null;
91
+ }
92
+ function renderGuideStatus({ running, doctor, latest }) {
93
+ const lines = [];
94
+ if (doctor.length) {
95
+ const named = doctor.map((due) => `${due.platform} (${due.reason})`).join(" and ");
96
+ const command = doctor.length === 1 ? `stim doctor --platform ${doctor[0]?.platform}` : "stim doctor";
97
+ lines.push(` Doctor is due for ${named}.`, ` Run before native work: ${command}`);
98
+ }
99
+ if (latest) lines.push(` stim ${latest} is available (running ${running}): npm install -g stim@latest`);
100
+ if (!lines.length) return null;
101
+ return ["STATUS", ...lines].join("\n");
102
+ }
103
+ async function guideStatus({ projectRoot, running, now = /* @__PURE__ */ new Date(), fetch: fetchImpl = fetch }) {
104
+ const doctor = [];
105
+ if (projectRoot && !appProjectProblem(projectRoot)) {
106
+ let runs = null;
107
+ try {
108
+ runs = getProject(projectRoot)?.doctorRuns ?? {};
109
+ } catch {}
110
+ if (runs) for (const platform of PLATFORMS) {
111
+ const reason = doctorDueReason(runs[platform], running, now);
112
+ if (reason) doctor.push({
113
+ platform,
114
+ reason
115
+ });
116
+ }
117
+ }
118
+ return renderGuideStatus({
119
+ running,
120
+ doctor,
121
+ latest: await checkForUpdate(running, {
122
+ now,
123
+ fetch: fetchImpl
124
+ })
125
+ });
126
+ }
127
+ //#endregion
128
+ //#region src/diagnostics/doctor-watchman.ts
129
+ const WATCHMAN_NESTED_WORKTREES = "watchman-nested-worktrees";
130
+ function isPlainObject(value) {
131
+ return !!value && typeof value === "object" && !Array.isArray(value);
132
+ }
133
+ function ignoreDirsOf(config) {
134
+ if (config.kind !== "object" || !Array.isArray(config.value.ignore_dirs)) return [];
135
+ return config.value.ignore_dirs.filter((entry) => typeof entry === "string");
136
+ }
137
+ function covered(path, ignoreDirs) {
138
+ return ignoreDirs.some((entry) => path === entry || path.startsWith(`${entry}/`));
139
+ }
140
+ /**
141
+ * Watchman joins each ignore_dirs entry to the root without normalizing it, so `.worktrees/` or `./.worktrees`
142
+ * ignores nothing; only an entry spelled exactly as the relative path, or as one of its ancestors, covers it.
143
+ */
144
+ function nestedWorktreeIgnores(checkout, worktrees, ignoreDirs, holdsSource) {
145
+ const nested = worktrees.map((path) => relative(checkout, path)).filter((rel) => rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel)).map((rel) => rel.split(sep).join("/")).filter((rel) => !covered(rel, ignoreDirs)).toSorted();
146
+ const parents = new Set(nested.map((rel) => dirname(rel)));
147
+ const [parent] = parents;
148
+ return {
149
+ nested,
150
+ add: parents.size === 1 && parent !== void 0 && parent !== "." && !holdsSource(parent) ? [parent] : nested
151
+ };
152
+ }
153
+ function mergeIgnoreDirs(config, add) {
154
+ if (config.kind === "invalid") return { refusal: config.reason };
155
+ const existing = config.kind === "object" ? config.value : {};
156
+ if ("ignore_dirs" in existing && !Array.isArray(existing.ignore_dirs)) return { refusal: "holds an ignore_dirs that is not an array" };
157
+ const current = Array.isArray(existing.ignore_dirs) ? existing.ignore_dirs : [];
158
+ return { value: {
159
+ ...existing,
160
+ ignore_dirs: [.../* @__PURE__ */ new Set([...current, ...add])]
161
+ } };
162
+ }
163
+ function readWatchmanConfig(path) {
164
+ let raw;
165
+ try {
166
+ raw = readFileSync(path, "utf-8");
167
+ } catch (error) {
168
+ const code = error.code;
169
+ return code === "ENOENT" ? { kind: "absent" } : {
170
+ kind: "invalid",
171
+ reason: `cannot be read (${code})`
172
+ };
173
+ }
174
+ let parsed;
175
+ try {
176
+ parsed = JSON.parse(raw);
177
+ } catch {
178
+ parsed = null;
179
+ }
180
+ return isPlainObject(parsed) ? {
181
+ kind: "object",
182
+ value: parsed
183
+ } : {
184
+ kind: "invalid",
185
+ reason: "is not a JSON object"
186
+ };
187
+ }
188
+ function canonical(path) {
189
+ try {
190
+ return realpathSync(path);
191
+ } catch {
192
+ return null;
193
+ }
194
+ }
195
+ function inspectNestedWorktrees(projectRoot) {
196
+ const worktrees = listWorktrees(repoRoot(projectRoot) ?? projectRoot).filter((entry) => !entry.prunable && !entry.bare).flatMap((entry) => canonical(entry.path) ?? []);
197
+ return worktrees.flatMap((checkout) => {
198
+ const configPath = join(checkout, ".watchmanconfig");
199
+ const config = readWatchmanConfig(configPath);
200
+ const { nested, add } = nestedWorktreeIgnores(checkout, worktrees, ignoreDirsOf(config), (dir) => Boolean(getExecutor().runFileQuiet("git", [
201
+ "-C",
202
+ checkout,
203
+ "ls-files",
204
+ "--",
205
+ dir
206
+ ]) ?? true));
207
+ return nested.length > 0 ? [{
208
+ checkout,
209
+ configPath,
210
+ config,
211
+ nested,
212
+ add
213
+ }] : [];
214
+ });
215
+ }
216
+ async function watchedCheckouts(checkouts, watchman = runWatchman) {
217
+ if (checkouts.length === 0) return /* @__PURE__ */ new Set();
218
+ try {
219
+ const roots = parseWatchRoots(await watchman(["watch-list"], 5e3)) ?? [];
220
+ const canonicalRoots = new Set(roots.map((root) => canonical(root) ?? root));
221
+ return new Set(checkouts.filter((checkout) => canonicalRoots.has(checkout)));
222
+ } catch {
223
+ return /* @__PURE__ */ new Set();
224
+ }
225
+ }
226
+ function list(items) {
227
+ return items.map((item) => `\`${item}\``).join(", ");
228
+ }
229
+ function nestedWorktreeFinding(entry, watched) {
230
+ const count = entry.nested.length;
231
+ const now = watched ? ` Watchman watches ${entry.checkout} now; \`watchman watch-del ${entry.checkout}\` and a watchman restart free that memory.` : "";
232
+ const merge = mergeIgnoreDirs(entry.config, entry.add);
233
+ const fix = "refusal" in merge ? `${entry.configPath} ${merge.refusal}, so Stim will not edit it. Add ${list(entry.add)} to its ignore_dirs by hand, then commit it.` : `Run \`stim doctor --fix\` to add ${list(entry.add)} to ignore_dirs in ${entry.configPath}, then commit that file. Watchman reads it only when it adds a root, so an existing root needs \`watchman watch-del ${entry.checkout}\` before the ignore applies.`;
234
+ return {
235
+ code: WATCHMAN_NESTED_WORKTREES,
236
+ level: "cost",
237
+ title: `${count} linked worktree${count === 1 ? " sits" : "s sit"} inside a checkout that Watchman would crawl`,
238
+ detail: `${list(entry.nested)} ${count === 1 ? "is" : "are"} inside ${entry.checkout}, and its .watchmanconfig does not ignore them. A Watchman root at that checkout, as Jest or a Metro started there registers, crawls every worktree's files, node_modules and build output, which grows the shared daemon's memory and its recrawls.${now}`,
239
+ fix
240
+ };
241
+ }
242
+ function writeIgnoreDirs(entry) {
243
+ const merge = mergeIgnoreDirs(entry.config, entry.add);
244
+ if ("refusal" in merge) return {
245
+ status: "refused",
246
+ reason: `${entry.configPath} ${merge.refusal}`
247
+ };
248
+ const tmp = `${entry.configPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
249
+ try {
250
+ writeFileSync(tmp, `${JSON.stringify(merge.value, null, 2)}\n`);
251
+ renameSync(tmp, entry.configPath);
252
+ } catch (error) {
253
+ rmSync(tmp, { force: true });
254
+ throw error;
255
+ }
256
+ return { status: entry.config.kind === "absent" ? "created" : "updated" };
257
+ }
258
+ //#endregion
259
+ export { writeIgnoreDirs as a, watchedCheckouts as i, inspectNestedWorktrees as n, guideStatus as o, nestedWorktreeFinding as r, recordDoctorRun as s, WATCHMAN_NESTED_WORKTREES as t };
@@ -1,18 +1,18 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { R as deviceSlotKey, p as getProject, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
3
- import { v as launchErrorPreview } from "./command-output-CDAIFD-8.mjs";
4
- import { l as resolveProjectMetro } from "./metro-g8NqiJp-.mjs";
5
- import { r as readWorkspaceState$1, w as withDirLock } from "./workspace-state-DqcCbpE7.mjs";
6
- import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-DpoS36_u.mjs";
7
- import { f as readWorkspaceLaunches } from "./state-BKa8wNN5.mjs";
8
- import { o as androidHome, u as androidToolCwd } from "./android-B_YNZy61.mjs";
9
- import { r as deviceConsoleLevel } from "./ios-device-Ee7sDXfp.mjs";
10
- import { n as parseLogcatLine, t as androidClockOffset } from "./android-DE4v59Mb.mjs";
11
- import { createHash, randomUUID } from "node:crypto";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { v as launchErrorPreview } from "./command-output-Bt8ygHE7.mjs";
3
+ import { R as deviceSlotKey, p as getProject, z as deviceSlotPlatforms } from "./config-DC5jEtd1.mjs";
4
+ import { r as readWorkspaceState$1, w as withDirLock } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { A as readWorkspaceLaunches } from "./project-B5eQ1USs.mjs";
6
+ import { u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
7
+ import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-Cu7PtQpZ.mjs";
8
+ import { o as androidHome, u as androidToolCwd } from "./android-BdQC6zs1.mjs";
9
+ import { r as deviceConsoleLevel } from "./ios-device-CrW8aMb5.mjs";
10
+ import { n as parseLogcatLine, t as androidClockOffset } from "./android-DE5g_5gv.mjs";
12
11
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
13
12
  import { basename, dirname, join, resolve, sep } from "node:path";
14
13
  import { NATIVE_CRASH_LOG_PREFIX, attachExpoErrorContext, readLogRecords, readLogTimeline } from "@stim-cli/core/state";
15
14
  import { homedir } from "node:os";
15
+ import { createHash, randomUUID } from "node:crypto";
16
16
  //#region src/diagnostics/diagnostic-store.ts
17
17
  /** Publishes an immutable diagnostic snapshot atomically; existing evidence wins. */
18
18
  function writeDiagnosticOnce(path, content) {