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,9 +1,9 @@
1
1
  import { n as ownership_claim_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
3
- import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-CBtzyIgF.mjs";
4
- import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, d as getConfigDir } from "./config-CgYMahz7.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-C59dqG-Z.mjs";
6
- import { r as register } from "./cache-manifest-BI7ozfmH.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
7
  import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Kqiifsk2.mjs";
8
8
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
9
9
  import { join } from "node:path";
@@ -1,7 +1,7 @@
1
- import { a as formatElapsed, r as clockTime } from "./command-output-CBtzyIgF.mjs";
2
- import { R as deviceSlotKey } from "./config-CgYMahz7.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-Co-EwifR.mjs";
4
- import { a as VERIFY_TIMEOUT_MS, m as APP_READINESS_TIMEOUT_MS } from "./launch-verify-hskNcWkZ.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-CgYMahz7.mjs";
2
- import { a as parseLease, f as selectPoolDevice, n as fileLeaseIo, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-Co-EwifR.mjs";
3
- import { i as DEVICE_WAIT_POLL_MS, n as DEVICE_BUSY, o as leaseExpiryText } from "./device-lease-run-w1xhCqIW.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-DWhCZDGm.mjs";
2
- import { a as formatElapsed } from "./command-output-CBtzyIgF.mjs";
3
- import { d as getConfigDir } from "./config-CgYMahz7.mjs";
4
- import { u as ownedDeviceLabel } from "./project-C3ChRLZy.mjs";
5
- import { o as pidExists } from "./metro-Dh8T4Ytd.mjs";
6
- import { C as workspaceStateFile, v as workspaceDir, w as withDirLock, x as workspaceLogsDir$1, y as workspaceId } from "./workspace-state-C59dqG-Z.mjs";
7
- import { Ht as readMetroTunnel, Wt as readRemoteSession, zt as clearRemoteSession } from "./budget-DIhL2BKx.mjs";
8
- import { S as probePublicHttp } from "./workspaces-xXItD8Dj.mjs";
9
- import { E as sanitizeDeviceLabel } from "./ios-B3SbOWdw.mjs";
10
- import { q as planMetroReach } from "./settings-CQyMElEP.mjs";
11
- import { a as withWorkspaceProcessLock } from "./named-ports-BFIz1Shz.mjs";
12
- import { i as INSTALL_ERROR, o as LAUNCH_ERROR, u as devClientDeepLink } from "./app-install-D-PUENug.mjs";
13
- import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-hskNcWkZ.mjs";
14
- import { t as compareStimVersions } from "./stim-installations-aR_WsNOA.mjs";
15
- import { c as nativeRunWaitNotice } from "./native-run-B06FkmZx.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,29 +1,29 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-CBtzyIgF.mjs";
3
- import { _ as loadConfig$1, p as getProject, s as configCorruptRepair, u as getConcurrencyLimits } from "./config-CgYMahz7.mjs";
4
- import { D as makeTemporaryDirectory, E as filesystemDevice, a as dirtyFingerprintFiles, h as locallyKnownUpstream, k as temporaryRoot, m as listWorktrees, s as gitCommonDir, x as resolveSourceCheckout, y as repoRoot } from "./worktree-CsKYexJM.mjs";
5
- import { i as detectIsExpo, l as isPackageResolvable, n as appProjectProblem, s as findProjectRoot$1 } from "./project-C3ChRLZy.mjs";
6
- import { _ as workspaceDerivedData, d as sharedBuildCache } from "./workspace-state-C59dqG-Z.mjs";
7
- import { St as inspectWatchmanMemory, a as inspectBudget, n as budgetLine } from "./budget-DIhL2BKx.mjs";
8
- import { M as listBuildSlots } from "./workspaces-xXItD8Dj.mjs";
9
- import { C as diffFingerprintSources, D as fingerprintProject, h as listBuildLocks } from "./device-lease-Co-EwifR.mjs";
10
- import { D as hostSystemImageArch, ft as parkedMaxSetting, o as androidHome, ot as POOL_SETTING_REMEDY } from "./android-DC3ZLuw0.mjs";
11
- import { M as readHostMemoryPressure, b as pickDefaultIosCreation, j as hostMemoryPressureAdvice, l as iosRuntimeMatches, m as listIosRuntimes } from "./ios-B3SbOWdw.mjs";
12
- import { F as resolveSettings, L as settingOrigin, M as remoteAndroidSetting, N as remoteIosSetting, Q as resolveOptimizations, U as unknownSettingKeys, V as settingsLayers, W as webSettings, X as compilerCacheFallbackMessage, i as SETTING_SHAPE_REMEDY, k as projectOptimizations, n as PATH_SETTINGS, r as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, v as iosSimSlimProfileSetting, y as mergeSettingsLayers, z as settingShapeErrors } from "./settings-CQyMElEP.mjs";
13
- import { o as offloadCheck, u as simulatorRuntime, v as inspectBuildMachines, w as realIo, x as inspectDeviceHostMachines } from "./client-DzhapoMB.mjs";
14
- import { i as countLiveOwnedDevices } from "./device-capacity-EUOOYr8T.mjs";
15
- import { N as projectCmakeLauncher, O as bundlerPin, b as detectXcodeMajor, i as macosToolchain, k as podInstallCommand, n as androidToolchain, r as iosToolchain, t as androidRequirements, v as ccacheEnabled } from "./toolchain-Bnyd_K3A.mjs";
16
- import { f as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig } from "./remote-cache-BGg7aGIZ.mjs";
17
- import { _ as easCliSupport, g as MIN_EAS_CLI_SIMULATOR_VERSION, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy } from "./device-remote-tHbd1fKy.mjs";
18
- import { n as inspectStimVersions, t as compareStimVersions } from "./stim-installations-aR_WsNOA.mjs";
19
- import { n as simslimIsOnPath, r as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-EHBQ2R4G.mjs";
20
- import { d as androidPathRoomRemedy, l as androidPathRoom, n as apkOutputsDir, t as androidSdkRefusal, u as androidPathRoomMessage } from "./gradle-C6GKnunQ.mjs";
21
- import { r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-BBFyr9CA.mjs";
22
- import { g as resolveRuntime, m as resolveDeviceType } from "./support-BaayeYCf.mjs";
23
- import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-DJnmnS5q.mjs";
24
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-xKoOypBm.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
25
  import { r as maintenanceStatus, t as maintenanceLine } from "./status-BEeL6IKz.mjs";
26
- import { n as recordDoctorRun } from "./guide-status-Bhf9SJXc.mjs";
26
+ import { a as writeIgnoreDirs, i as watchedCheckouts, n as inspectNestedWorktrees, r as nestedWorktreeFinding, s as recordDoctorRun } from "./doctor-watchman-wZhyTdp4.mjs";
27
27
  import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
28
28
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
29
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";
@@ -1149,7 +1149,8 @@ function checkAndroidSdk(projectRoot, platform) {
1149
1149
  const refusal = androidSdkRefusal({
1150
1150
  sdkPath,
1151
1151
  sdkExists: existsSync$1(sdkPath),
1152
- hasLocalProperties: existsSync$1(join$1(androidDir, "local.properties"))
1152
+ hasLocalProperties: existsSync$1(join$1(androidDir, "local.properties")),
1153
+ localPropertiesPath: "android/local.properties"
1153
1154
  });
1154
1155
  if (!refusal) return null;
1155
1156
  return {
@@ -1435,7 +1436,7 @@ function doctorSuccessLines(platform, stim, budget = null) {
1435
1436
  ...budgetLines(budget),
1436
1437
  "",
1437
1438
  "Project",
1438
- phaseLine("project", "source checkout, dependencies, local upstream"),
1439
+ phaseLine("project", "source checkout, dependencies, local upstream, nested worktrees Watchman would crawl"),
1439
1440
  phaseLine("settings", "every Stim setting type, machine config paths, companions and inert keys")
1440
1441
  ];
1441
1442
  if (platform !== "android") {
@@ -1509,8 +1510,8 @@ function applySandboxFix(root, env = process.env) {
1509
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."));
1510
1511
  }
1511
1512
  function doctorCommand(program, version, inspectVersions = inspectStimVersions, host = process.platform) {
1512
- 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) => {
1513
- 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());
1514
1515
  if (!root) {
1515
1516
  refuseNoProject({ json: Boolean(opts.json) });
1516
1517
  return;
@@ -1526,6 +1527,26 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
1526
1527
  console.error(phaseLine("cache", `CMake cleanup failed: ${error.message}`));
1527
1528
  process.exitCode = 1;
1528
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
+ }
1529
1550
  }
1530
1551
  const stim = await inspectVersions(version);
1531
1552
  const findings = runDoctor(root, {
@@ -1547,6 +1568,9 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
1547
1568
  findings.push(...budget.findings);
1548
1569
  const watchman = await inspectWatchmanMemory();
1549
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)));
1550
1574
  const checksIos = opts.platform !== "android" && host === "darwin";
1551
1575
  const checksAndroid = opts.platform === "android" || opts.platform === void 0 && (existsSync(join(root, "android")) || detectIsExpo(root));
1552
1576
  const checksMacos = host === "darwin" && opts.platform === void 0 && existsSync(join(root, "Package.swift"));
@@ -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,13 +1,13 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { v as launchErrorPreview } from "./command-output-CBtzyIgF.mjs";
3
- import { R as deviceSlotKey, p as getProject, z as deviceSlotPlatforms } from "./config-CgYMahz7.mjs";
4
- import { l as resolveProjectMetro } from "./metro-Dh8T4Ytd.mjs";
5
- import { r as readWorkspaceState$1, w as withDirLock } from "./workspace-state-C59dqG-Z.mjs";
6
- import { Kt as readWorkspaceLaunches } from "./budget-DIhL2BKx.mjs";
7
- import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-Co-EwifR.mjs";
8
- import { o as androidHome, u as androidToolCwd } from "./android-DC3ZLuw0.mjs";
9
- import { r as deviceConsoleLevel } from "./ios-device-Bn7jWDB1.mjs";
10
- import { n as parseLogcatLine, t as androidClockOffset } from "./android-CBwCNicO.mjs";
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";
11
11
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
12
  import { basename, dirname, join, resolve, sep } from "node:path";
13
13
  import { NATIVE_CRASH_LOG_PREFIX, attachExpoErrorContext, readLogRecords, readLogTimeline } from "@stim-cli/core/state";
@@ -36,7 +36,7 @@ const defaultExecutor = {
36
36
  throw nameTimeout(error, cmd, timeoutMs);
37
37
  }
38
38
  },
39
- runFile(file, args = [], { timeoutMs, killSignal, cwd, env, omitEnv, input, untrimmed } = {}) {
39
+ runFile(file, args = [], { timeoutMs, killSignal, cwd, env, omitEnv, input, untrimmed, rejectStderr } = {}) {
40
40
  const opts = {
41
41
  encoding: "utf-8",
42
42
  stdio: [
@@ -60,14 +60,14 @@ const defaultExecutor = {
60
60
  }
61
61
  const result = spawn.sync(file, args, opts);
62
62
  if (result.error) throw nameTimeout(Object.assign(result.error, result), [file, ...args].join(" "), timeoutMs);
63
- if (result.status !== 0) {
63
+ if (result.status !== 0 || rejectStderr && String(result.stderr ?? "").trim()) {
64
64
  const stderr = String(result.stderr ?? "");
65
65
  const message = `Command failed: ${[file, ...args].join(" ")}${stderr ? `\n${stderr}` : ""}`;
66
66
  throw Object.assign(new Error(message), result);
67
67
  }
68
68
  return untrimmed ? String(result.stdout) : String(result.stdout).trim();
69
69
  },
70
- runFileAsync(file, args = [], { timeoutMs, killSignal, cwd, env, omitEnv } = {}) {
70
+ runFileAsync(file, args = [], { timeoutMs, killSignal, cwd, env, omitEnv, rejectStderr, onSpawn } = {}) {
71
71
  const command = [file, ...args].join(" ");
72
72
  return new Promise((resolve, reject) => {
73
73
  const opts = { stdio: [
@@ -85,6 +85,13 @@ const defaultExecutor = {
85
85
  opts.env = childEnv;
86
86
  }
87
87
  const child = spawn(file, args, opts);
88
+ try {
89
+ onSpawn?.(child);
90
+ } catch (error) {
91
+ child.kill("SIGKILL");
92
+ reject(error);
93
+ return;
94
+ }
88
95
  const stdout = [];
89
96
  const stderr = [];
90
97
  let timedOut = false;
@@ -109,7 +116,7 @@ const defaultExecutor = {
109
116
  stderr: err
110
117
  };
111
118
  if (timedOut) reject(nameTimeout(Object.assign(new Error(command), result, { code: "ETIMEDOUT" }), command, timeoutMs));
112
- else if (status !== 0) reject(Object.assign(/* @__PURE__ */ new Error(`Command failed: ${command}${err ? `\n${err}` : ""}`), result));
119
+ else if (status !== 0 || rejectStderr && err.trim()) reject(Object.assign(/* @__PURE__ */ new Error(`Command failed: ${command}${err ? `\n${err}` : ""}`), result));
113
120
  else resolve(out.trim());
114
121
  });
115
122
  });
@@ -146,21 +153,30 @@ function outcomeOf(error) {
146
153
  ...code ? { code } : {}
147
154
  };
148
155
  }
156
+ let executionId = 0;
149
157
  function timedSync(fn, program) {
150
158
  return (...args) => {
151
159
  if (!debugLog.enabled()) return fn(...args);
160
+ const id = ++executionId;
161
+ const name = program(...args);
152
162
  const started = performance.now();
163
+ debugLog.log("exec.start", {
164
+ program: name,
165
+ executionId: id
166
+ });
153
167
  try {
154
168
  const out = fn(...args);
155
169
  debugLog.log("exec", {
156
- program: program(...args),
170
+ program: name,
171
+ executionId: id,
157
172
  ms: Math.round(performance.now() - started),
158
173
  ok: true
159
174
  });
160
175
  return out;
161
176
  } catch (error) {
162
177
  debugLog.log("exec", {
163
- program: program(...args),
178
+ program: name,
179
+ executionId: id,
164
180
  ms: Math.round(performance.now() - started),
165
181
  ...outcomeOf(error)
166
182
  });
@@ -174,18 +190,26 @@ let active = {
174
190
  runFile: timedSync((file, args, opts) => defaultExecutor.runFile(file, args, opts), (file) => basename(file)),
175
191
  async runFileAsync(file, args, opts) {
176
192
  if (!debugLog.enabled()) return defaultExecutor.runFileAsync(file, args, opts);
193
+ const id = ++executionId;
194
+ const name = basename(file);
177
195
  const started = performance.now();
196
+ debugLog.log("exec.start", {
197
+ program: name,
198
+ executionId: id
199
+ });
178
200
  try {
179
201
  const out = await defaultExecutor.runFileAsync(file, args, opts);
180
202
  debugLog.log("exec", {
181
- program: basename(file),
203
+ program: name,
204
+ executionId: id,
182
205
  ms: Math.round(performance.now() - started),
183
206
  ok: true
184
207
  });
185
208
  return out;
186
209
  } catch (error) {
187
210
  debugLog.log("exec", {
188
- program: basename(file),
211
+ program: name,
212
+ executionId: id,
189
213
  ms: Math.round(performance.now() - started),
190
214
  ...outcomeOf(error)
191
215
  });