stim 1.14.0 → 1.15.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 (130) hide show
  1. package/README.md +2 -0
  2. package/dist/{activity-CYVDcrt3.mjs → activity-B2-kb7k0.mjs} +281 -41
  3. package/dist/{android-XpvCrV7q.mjs → android-CYmq0jNi.mjs} +2 -2
  4. package/dist/{android-LbPFRWVL.mjs → android-Cu_L4RpL.mjs} +502 -407
  5. package/dist/{android-d6rGq1pA.mjs → android-Db2eEMaf.mjs} +152 -65
  6. package/dist/android-cas-PnKfAdB2.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{app-install-BpgSgkJj.mjs → app-install-CAAplXAt.mjs} +95 -161
  9. package/dist/{budget-CGDkhvv_.mjs → budget-CMiqghig.mjs} +1038 -73
  10. package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-aeGMFX7e.mjs} +193 -653
  11. package/dist/build-progress-C2Jv1AtA.mjs +872 -0
  12. package/dist/build-slots-Df1ApSuH.mjs +127 -0
  13. package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  14. package/dist/cache-manifest.mjs +1 -1
  15. package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
  16. package/dist/cli-0cX5s4NM.mjs +45 -0
  17. package/dist/cli.mjs +6 -42
  18. package/dist/client-C2IS36Qf.mjs +1333 -0
  19. package/dist/collector-run.mjs +8 -7
  20. package/dist/{command-output-DVcpw6eE.mjs → command-output-CliHHn7a.mjs} +1 -1
  21. package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
  22. package/dist/{created-devices-CllH_8eb.mjs → created-devices-BwVb3liH.mjs} +2 -2
  23. package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
  24. package/dist/{deps-D9IcKqXS.mjs → deps-BFlKbOIp.mjs} +3 -3
  25. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  26. package/dist/dev-client-CjzLoNs0.mjs +80 -0
  27. package/dist/{device-CjuuAJjQ.mjs → device-BZ1IyS5A.mjs} +7 -7
  28. package/dist/device-capacity-DMuKC7nx.mjs +136 -0
  29. package/dist/device-host-worker.d.mts +1 -0
  30. package/dist/device-host-worker.mjs +769 -0
  31. package/dist/device-ios-DMQBUPus.mjs +381 -0
  32. package/dist/{device-lease-5c3WrVRm.mjs → device-lease-W5Pi1q38.mjs} +43 -36
  33. package/dist/{device-pool-BiyDyPP-.mjs → device-pool-B2r38YjS.mjs} +4 -4
  34. package/dist/{device-remote-D87zEzaq.mjs → device-remote-9ulPsdhY.mjs} +68 -162
  35. package/dist/{doctor-x9pnU9fq.mjs → doctor-BcE5xsBn.mjs} +191 -99
  36. package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
  37. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  38. package/dist/{gc-ko6mUAYD.mjs → gc-BuL1Genr.mjs} +429 -101
  39. package/dist/{android-cas-iZK3DOCr.mjs → gradle-CmdOBq1d.mjs} +8 -294
  40. package/dist/{guide-6R0VNFqI.mjs → guide-cCSGRFd3.mjs} +1959 -222
  41. package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CIoWK6mG.mjs} +3 -3
  42. package/dist/hosted-macos-DwowNU7W.mjs +447 -0
  43. package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
  44. package/dist/in-use-CndPMilN.mjs +110 -0
  45. package/dist/{ios-BwDPrnYQ.mjs → ios-3CtCRhwr.mjs} +201 -10
  46. package/dist/{ios-P1f5nm2n.mjs → ios-Chob8ny7.mjs} +512 -263
  47. package/dist/{ios-device-DGglU3E_.mjs → ios-device-DERmMmk-.mjs} +12 -7
  48. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  49. package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-CLlofxRt.mjs} +4 -4
  50. package/dist/{logs-Civ4gbBH.mjs → logs-h9h6MUvE.mjs} +95 -13
  51. package/dist/machine-usage-D_YYMzfR.mjs +283 -0
  52. package/dist/machines-CYtOCqcj.mjs +259 -0
  53. package/dist/macos-BwtbUtTN.mjs +468 -0
  54. package/dist/macos-run.d.mts +5 -0
  55. package/dist/macos-run.mjs +2 -0
  56. package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
  57. package/dist/{metro-CcEo8Fl8.mjs → metro-Di8EN2Tb.mjs} +20 -120
  58. package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Dj_XBNaL.mjs} +6 -59
  59. package/dist/native-run-DFDoIRbY.mjs +147 -0
  60. package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-i6OkVg-w.mjs} +9 -5
  61. package/dist/offload-worker.d.mts +121 -0
  62. package/dist/offload-worker.mjs +601 -0
  63. package/dist/{ownership-DyYDF5ww.mjs → ownership-BkYxUtuj.mjs} +3 -2
  64. package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
  65. package/dist/{ports-BguS83ex.mjs → ports-DddwttKM.mjs} +3 -3
  66. package/dist/prebuild-BvxDlD6C.mjs +213 -0
  67. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  68. package/dist/{project-CWlvEaeN.mjs → project-CV3tDFHl.mjs} +9 -18
  69. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  70. package/dist/pull-requests.d.mts +120 -0
  71. package/dist/pull-requests.mjs +2 -0
  72. package/dist/recordings-GEXp4iBT.mjs +37 -0
  73. package/dist/{reload-BiniwsSZ.mjs → reload-ChPiwvot.mjs} +70 -22
  74. package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-CO2elm_b.mjs} +4 -4
  75. package/dist/run-B-xqRrsg.mjs +119 -0
  76. package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-X7PUgizL.mjs} +33 -15
  77. package/dist/{server-expo-BVuwQ65v.mjs → server-expo-DhtX6bom.mjs} +6 -10
  78. package/dist/server-expo-KJeD109I.mjs +2 -0
  79. package/dist/{settings-D61iNOsB.mjs → settings-CduVcoxj.mjs} +77 -26
  80. package/dist/{settings-B-fsC-Om.mjs → settings-DbL6uhH8.mjs} +16 -10
  81. package/dist/settings.schema.json +357 -2
  82. package/dist/{simslim-DrDN4WuV.mjs → simslim-Ciluxlq4.mjs} +8 -132
  83. package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-BY0BrOLh.mjs} +6 -6
  84. package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  85. package/dist/spawn-entry-DncpJvWL.mjs +16 -0
  86. package/dist/stage-CzaiwFsI.mjs +143 -0
  87. package/dist/start-CPO4wRg7.mjs +2 -0
  88. package/dist/{start-s4RXp1wy.mjs → start-CUD9nasA.mjs} +108 -61
  89. package/dist/state-B4PQFXMW.d.mts +12 -0
  90. package/dist/state-BxCgeTQu.mjs +41 -0
  91. package/dist/{state-DHqvsbqC.mjs → state-CaeaHbDA.mjs} +7 -4
  92. package/dist/{state-Dk9RVXI7.mjs → state-DFm77wRn.mjs} +67 -5
  93. package/dist/stats-DBLLFmKd.mjs +66 -0
  94. package/dist/{status-BsPAnfOI.mjs → status-DYXxNOT0.mjs} +423 -268
  95. package/dist/{status-BgAuxESg.mjs → status-l84Gbvp2.mjs} +116 -20
  96. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  97. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  98. package/dist/stim-footprint.swift +32 -0
  99. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  100. package/dist/{stop-BzreOWJp.mjs → stop-Bad61z_2.mjs} +38 -12
  101. package/dist/stop-Bvf1MflS.mjs +48 -0
  102. package/dist/{stop-BWIF_6BK.mjs → stop-CceYh1yG.mjs} +2 -2
  103. package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
  104. package/dist/supervisor-run.d.mts +43 -11
  105. package/dist/supervisor-run.mjs +227 -19
  106. package/dist/support-CDQbDkL5.mjs +315 -0
  107. package/dist/support-WLOzVKUv.mjs +176 -0
  108. package/dist/teardown-BYuQafiA.mjs +718 -0
  109. package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DmeYjXD9.mjs} +363 -13
  110. package/dist/warm-progress-DVHLN4uC.mjs +463 -0
  111. package/dist/{idle-DXtx3RbX.mjs → watchman-Bx0wceoF.mjs} +55 -8
  112. package/dist/{web-BsQs1WlO.mjs → web-k6w8-HnE.mjs} +37 -20
  113. package/dist/web-run.mjs +309 -12
  114. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  115. package/dist/workspace-state-CL2V2Ons.mjs +371 -0
  116. package/dist/worktree-BT_uULFx.mjs +2 -0
  117. package/dist/{worktree-BVrHsYZG.mjs → worktree-C0c5Udwa.mjs} +55 -54
  118. package/dist/{worktree-UrQWXSeb.mjs → worktree-qXKzADSC.mjs} +154 -252
  119. package/package.json +10 -5
  120. package/shim/bundle-response.cjs +28 -12
  121. package/dist/build-progress-DxKpwnaS.mjs +0 -247
  122. package/dist/in-use-DlqBDKqY.mjs +0 -249
  123. package/dist/server-expo-DIHDhvGg.mjs +0 -2
  124. package/dist/start-Cetfvy8l.mjs +0 -2
  125. package/dist/stats-CFpFGlJV.mjs +0 -62
  126. package/dist/stats-CX1Z8Tca.mjs +0 -368
  127. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  128. package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
  129. package/dist/worktree-CHWWvm5v.mjs +0 -2
  130. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -1,29 +1,37 @@
1
- import { A as ownership_claim_exports, O as process_identity_exports, T as upsertProject, U as projectDeviceSlots, _ as loadConfig, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject, x as removeProject } from "./config-lvc7d3C2.mjs";
2
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { a as pidExists, c as resolveProjectMetro, g as recordWorkspaceUse, h as readWorkspaceState, k as workspaceDir, l as signalProcessTree, n as killMetroTree } from "./metro-CcEo8Fl8.mjs";
4
- import { C as sourceCheckoutOf, S as restoreFile, T as warmWorktreePaths, _ as readWorktreeExclude, b as resolveFullRef, d as hasUncommittedWork, f as isPodInstallChurn, g as podsOutOfSync, h as locallyKnownUpstream, i as depsOutOfSync, l as hasPopulatedSubmodules, m as listWorktrees, n as cloneIgnoredEntries, o as dirtyPaths, r as deleteBranch, s as gitCommonDir, t as branchExists, u as hasRemote, v as removeWorktree, w as unpushedCommits } from "./worktree-BVrHsYZG.mjs";
5
- import { a as findProjectRoot } from "./project-CWlvEaeN.mjs";
6
- import { a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, u as readRemoteSession } from "./state-DHqvsbqC.mjs";
7
- import { t as clearNamedPorts } from "./named-ports-Blg8IxOh.mjs";
8
- import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-DVcpw6eE.mjs";
9
- import { u as releaseWorkspaceLeases } from "./device-lease-5c3WrVRm.mjs";
10
- import { ct as parkedMaxSetting, rt as POOL_SETTING_REMEDY } from "./android-d6rGq1pA.mjs";
11
- import { L as unknownSettingKeys, P as settingShapeErrors, a as SETTING_SHAPE_REMEDY, j as resolveSettings } from "./settings-D61iNOsB.mjs";
12
- import { C as teardownOwnedIosSim, S as teardownOwnedBrowser, g as withManagedRemoteWorktreeRemovalLock, l as withdrawDevServerStopRequest, p as stopTunnel, s as requestDevServerStop, u as resolveSupervisorTarget, v as withManagedTunnelRemovalLock, x as teardownOwnedAvd } from "./stop-cause-hjGBOZTG.mjs";
13
- import { a as readWebRecord } from "./state-Dk9RVXI7.mjs";
14
- import { n as withIdleWorkspace, t as emptyWorkspaceDir } from "./in-use-DlqBDKqY.mjs";
15
- import { n as verifyCollectorOwnership } from "./ownership-DyYDF5ww.mjs";
16
- import { f as resolveEasCliBin } from "./remote-cache-CcR6o6lI.mjs";
17
- import { i as endRecordedSession } from "./device-remote-D87zEzaq.mjs";
18
- import { h as podInstallCommand, n as HEARTBEAT_INTERVAL_MS } from "./xcode-Cp5KvK9x.mjs";
19
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-DsT7aKeo.mjs";
20
- import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-D9IcKqXS.mjs";
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { E as upsertProject, H as projectDeviceSlots, S as removeProject, _ as loadConfig$1, a as clearDevice, d as getConfigDir, g as isPathPrefix, k as acquireAvdClaim, p as getProject } from "./config-D0DbpZtM.mjs";
3
+ import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
+ import { a as pullRequestLookup, r as endedPullRequest } from "./pull-request-pxnDCQzn.mjs";
5
+ import { b as workspaceDir, i as recordWorkspaceUse, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
6
+ import { C as sourceCheckoutOf, S as restoreFile, T as warmWorktreePaths, _ as readWorktreeExclude, b as resolveFullRef, d as hasUncommittedWork, f as isPodInstallChurn, g as podsOutOfSync, h as locallyKnownUpstream, i as depsOutOfSync, l as hasPopulatedSubmodules, m as listWorktrees, n as cloneIgnoredEntries, o as dirtyPaths, r as deleteBranch, s as gitCommonDir, t as branchExists, u as hasRemote, v as removeWorktree, w as unpushedCommits } from "./worktree-C0c5Udwa.mjs";
7
+ import { a as findProjectRoot$1, n as appProjectProblem } from "./project-CV3tDFHl.mjs";
8
+ import { a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, u as readRemoteSession } from "./state-CaeaHbDA.mjs";
9
+ import { a as formatElapsed, h as shortUdid, i as formatDuration, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CliHHn7a.mjs";
10
+ import { u as releaseWorkspaceLeases } from "./device-lease-W5Pi1q38.mjs";
11
+ import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
12
+ import { at as POOL_SETTING_REMEDY, dt as parkedMaxSetting } from "./android-Db2eEMaf.mjs";
13
+ import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-Di8EN2Tb.mjs";
14
+ import { B as unknownSettingKeys, L as settingShapeErrors, N as resolveSettings, a as SETTING_SHAPE_REMEDY } from "./settings-CduVcoxj.mjs";
15
+ import { a as teardownOwnedBrowser, i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-BYuQafiA.mjs";
16
+ import { t as clearNamedPorts } from "./named-ports-Dj_XBNaL.mjs";
17
+ import { o as readWebRecord } from "./state-DFm77wRn.mjs";
18
+ import { n as withIdleWorkspace, t as emptyWorkspaceDir } from "./in-use-CndPMilN.mjs";
19
+ import { g as withManagedRemoteWorktreeRemovalLock, l as withdrawDevServerStopRequest, p as stopTunnel, s as requestDevServerStop, u as resolveSupervisorTarget, v as withManagedTunnelRemovalLock } from "./stop-cause-CZ_Mr-v9.mjs";
20
+ import { n as verifyCollectorOwnership } from "./ownership-BkYxUtuj.mjs";
21
+ import { C as podInstallCommand, u as HEARTBEAT_INTERVAL_MS } from "./toolchain-DmeYjXD9.mjs";
22
+ import { t as stopMacosApp } from "./stop-Bvf1MflS.mjs";
23
+ import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-BFlKbOIp.mjs";
24
+ import { f as resolveEasCliBin } from "./remote-cache-CO2elm_b.mjs";
25
+ import { i as endRecordedSession } from "./device-remote-9ulPsdhY.mjs";
26
+ import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-BmsjKZ2H.mjs";
27
+ import { a as forgetStatusMeasures, t as startWarmProgress } from "./warm-progress-DVHLN4uC.mjs";
28
+ import { createHash, randomUUID } from "node:crypto";
21
29
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
22
- import { existsSync as existsSync$1, realpathSync as realpathSync$1 } from "fs";
23
- import { basename, dirname, isAbsolute, relative, resolve } from "path";
30
+ import { join, relative } from "node:path";
31
+ import { existsSync as existsSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1 } from "fs";
32
+ import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
24
33
  import { workspaceName } from "@stim-cli/core";
25
- import { join as join$1, relative as relative$1 } from "node:path";
26
- import { createHash, randomUUID } from "node:crypto";
34
+ import { LAST_BUILD_KEYS, readMacosRecord } from "@stim-cli/core/state";
27
35
  import chalk from "chalk";
28
36
  //#region src/devices/reclaim.ts
29
37
  async function reapCollectors(root, { verify = verifyCollectorOwnership, collectors }) {
@@ -166,14 +174,22 @@ function describeDereferenced(project) {
166
174
  }
167
175
  return devices;
168
176
  }
169
- function parkRequest(projectPath, slot, simslimManaged) {
177
+ function lastBuildCacheKey(projectPath, platform) {
178
+ const build = readWorkspaceState$1(projectPath)?.[LAST_BUILD_KEYS[platform]];
179
+ if (build === null || typeof build !== "object" || Array.isArray(build)) return null;
180
+ const { cacheKey } = build;
181
+ return typeof cacheKey === "string" ? cacheKey : null;
182
+ }
183
+ function parkRequest(project, projectPath, slot, simslimManaged) {
170
184
  const { max, error } = parkedMaxSetting("ios");
171
185
  if (error || max <= 0) return void 0;
172
186
  return {
173
187
  projectPath,
174
188
  max,
175
189
  simslimManaged,
176
- slot
190
+ slot,
191
+ appId: typeof project?.bundleId === "string" ? project.bundleId : null,
192
+ cacheKey: lastBuildCacheKey(projectPath, "ios")
177
193
  };
178
194
  }
179
195
  function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
@@ -191,7 +207,7 @@ function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
191
207
  const r = teardownOwnedIosSim(udid, {
192
208
  del: true,
193
209
  label,
194
- ...park ? { park: parkRequest(projectPath, slot, Boolean(ios.simslimManaged)) } : {}
210
+ ...park ? { park: parkRequest(project, projectPath, slot, Boolean(ios.simslimManaged)) } : {}
195
211
  });
196
212
  if (r.parkFallback) poolNotes.push(`could not park ${label}: ${r.parkFallback} -- deleted it instead`);
197
213
  for (const failure of r.evictionFailures ?? []) poolNotes.push(failure);
@@ -230,7 +246,9 @@ function reclaimOwnedDevices(project, projectPath, { park = false } = {}) {
230
246
  projectPath,
231
247
  slot,
232
248
  max: bound.max,
233
- configuration: typeof android.poolConfiguration === "string" ? android.poolConfiguration : void 0
249
+ configuration: typeof android.poolConfiguration === "string" ? android.poolConfiguration : void 0,
250
+ appId: typeof project?.androidPackage === "string" ? project.androidPackage : null,
251
+ cacheKey: lastBuildCacheKey(projectPath, "android")
234
252
  } } : {}
235
253
  });
236
254
  if (r.parkFallback) poolNotes.push(`could not park ${android.avdName}: ${r.parkFallback} -- deleted it instead`);
@@ -303,7 +321,7 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
303
321
  const project = getProject(path);
304
322
  for (const { platforms } of projectDeviceSlots(project)) if (platforms.android?.owned && platforms.android.avdName) (0, ownership_claim_exports.releaseClaim)(acquireAvdClaim(platforms.android.avdName));
305
323
  const dereferenced = describeDereferenced(project);
306
- const initialState = readWorkspaceState(path);
324
+ const initialState = readWorkspaceState$1(path);
307
325
  let killedPid = null;
308
326
  let skippedMetro = null;
309
327
  let supervisorHeld = false;
@@ -359,7 +377,7 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
359
377
  failedCollectors.push(entry);
360
378
  }
361
379
  function retainReplacementProcesses() {
362
- const currentState = readWorkspaceState(path);
380
+ const currentState = readWorkspaceState$1(path);
363
381
  const currentProject = getProject(path);
364
382
  if (Boolean(currentState?.supervisor && !(0, process_identity_exports.sameProcessRecord)(currentState.supervisor, initialState?.supervisor) || currentProject?.supervisor && !(0, process_identity_exports.sameProcessRecord)(currentProject.supervisor, project?.supervisor) || readWebRecord(path) !== null || Object.entries(currentState?.collectors ?? {}).some(([platform, record]) => !(0, process_identity_exports.sameProcessRecord)(record, initialState?.collectors?.[platform])))) {
365
383
  supervisorHeld = true;
@@ -382,6 +400,17 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
382
400
  skippedDevices.push(remote.failed);
383
401
  failedDevices.push(remote.failed);
384
402
  }
403
+ const hosted = readMacosRecord(path)?.host;
404
+ if (hosted) try {
405
+ await stopMacosApp(path);
406
+ } catch (error) {
407
+ const failed = {
408
+ name: `hosted macOS session ${hosted.session} on ${hosted.machine}`,
409
+ reason: String(error?.message ?? error)
410
+ };
411
+ skippedDevices.push(failed);
412
+ failedDevices.push(failed);
413
+ }
385
414
  const tunnel = await reclaimMetroTunnel(path, { stopMetroTunnel });
386
415
  if (tunnel.failed) {
387
416
  skippedDevices.push(tunnel.failed);
@@ -428,192 +457,6 @@ async function reclaimIdleProject(path, workspaceExisted, { deleteOwnedDevices =
428
457
  };
429
458
  }
430
459
  //#endregion
431
- //#region src/workspace/pull-request.ts
432
- const GH_TIMEOUT_MS = 2e4;
433
- const GH_ENV = {
434
- GH_PROMPT_DISABLED: "1",
435
- GH_NO_UPDATE_NOTIFIER: "1",
436
- NO_COLOR: "1"
437
- };
438
- const GH_FIELDS = "number,state,url,headRefOid,mergedAt,closedAt,isCrossRepository";
439
- const SIGNED_OUT_EXIT = 4;
440
- function stateOf(state) {
441
- if (state === "OPEN") return "open";
442
- if (state === "MERGED") return "merged";
443
- if (state === "CLOSED") return "closed";
444
- return null;
445
- }
446
- function epoch(text) {
447
- const at = text ? Date.parse(text) : NaN;
448
- return Number.isFinite(at) ? at : null;
449
- }
450
- /**
451
- * Picks the pull request that describes `head` among those `gh pr list --head <branch>` returned. One whose head is
452
- * `head` wins, then one whose head contains `head`, then one whose head `head` contains. An open one wins a tier,
453
- * then the newest. A pull request unrelated to `head` is from an earlier use of the branch name, and one from a fork
454
- * only shares the branch name; both are ignored.
455
- * `isAncestor(a, b)` answers whether commit `a` is an ancestor of commit `b`, and false when git cannot tell.
456
- */
457
- function selectPullRequest(pulls, head, isAncestor) {
458
- const known = pulls.flatMap((pull) => {
459
- const state = stateOf(pull.state);
460
- return state && pull.headRefOid && !pull.isCrossRepository ? [{
461
- pull,
462
- state
463
- }] : [];
464
- });
465
- const tiers = [
466
- known.filter(({ pull }) => pull.headRefOid === head),
467
- known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(head, pull.headRefOid)),
468
- known.filter(({ pull }) => pull.headRefOid !== head && isAncestor(pull.headRefOid, head))
469
- ];
470
- const tier = tiers.findIndex((entries) => entries.length > 0);
471
- if (tier < 0) return null;
472
- const { pull, state } = tiers[tier].toSorted((a, b) => Number(b.state === "open") - Number(a.state === "open") || b.pull.number - a.pull.number)[0];
473
- return {
474
- number: pull.number,
475
- state,
476
- url: pull.url,
477
- head: pull.headRefOid,
478
- containsHead: tier < 2,
479
- endedAt: state === "merged" ? epoch(pull.mergedAt) : state === "closed" ? epoch(pull.closedAt) : null
480
- };
481
- }
482
- function firstLine(error) {
483
- const { stderr, message } = error;
484
- const text = String(stderr ?? "").trim() || String(message ?? error);
485
- return text.split("\n")[0] ?? text;
486
- }
487
- function ghFailure(error, command) {
488
- if (error.status === SIGNED_OUT_EXIT) return {
489
- unavailable: "gh is not signed in; run `gh auth login`",
490
- sticky: true
491
- };
492
- if (error.code === "ETIMEDOUT") return {
493
- unavailable: `${command} did not answer within ${GH_TIMEOUT_MS / 1e3}s`,
494
- sticky: true
495
- };
496
- return {
497
- unavailable: `${command} failed: ${firstLine(error)}`,
498
- sticky: false
499
- };
500
- }
501
- function ancestry(cwd) {
502
- const exec = getExecutor();
503
- return (ancestor, descendant) => exec.runFileQuiet("git", [
504
- "-C",
505
- cwd,
506
- "merge-base",
507
- "--is-ancestor",
508
- ancestor,
509
- descendant
510
- ]) !== null;
511
- }
512
- /**
513
- * Asks GitHub, through `gh`, which pull requests have `branch` as their head, run from `cwd` so `gh` picks the
514
- * repository from its remotes. Each call is one fixed `gh pr list` invocation. Once `gh` is missing, signed out or
515
- * times out, every later lookup through the same function answers `unavailable` without running it again.
516
- */
517
- function pullRequestLookup() {
518
- let unavailable;
519
- return (cwd, branch, head) => {
520
- const exec = getExecutor();
521
- if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
522
- if (unavailable) return { unavailable };
523
- let out;
524
- try {
525
- out = exec.runFile("gh", [
526
- "pr",
527
- "list",
528
- "--head",
529
- branch,
530
- "--state",
531
- "all",
532
- "--limit",
533
- "20",
534
- "--json",
535
- GH_FIELDS
536
- ], {
537
- cwd,
538
- timeoutMs: GH_TIMEOUT_MS,
539
- env: GH_ENV
540
- });
541
- } catch (error) {
542
- const failure = ghFailure(error, "gh pr list");
543
- if (failure.sticky) unavailable = failure.unavailable;
544
- return { unavailable: failure.unavailable };
545
- }
546
- let pulls;
547
- try {
548
- pulls = JSON.parse(out);
549
- } catch {
550
- return { unavailable: "gh pr list printed no JSON" };
551
- }
552
- return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
553
- };
554
- }
555
- function branchesQuery(count) {
556
- return `query($owner: String!, $repo: String!${Array.from({ length: count }, (_, i) => `, $b${i}: String!`).join("")}) { repository(owner: $owner, name: $repo) {${Array.from({ length: count }, (_, i) => ` b${i}: pullRequests(headRefName: $b${i}, states: [OPEN, CLOSED, MERGED], first: 20, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { ${GH_FIELDS.replaceAll(",", " ")} } }`).join("")} } }`;
557
- }
558
- /**
559
- * {@link pullRequestLookup} for every branch of one repository in one fixed `gh api graphql` call run from `repo`,
560
- * which asks for the same 20 newest pull requests of each head branch that `gh pr list --head` returns. `gh` fills
561
- * `{owner}` and `{repo}` from the remotes of `repo`; branch names travel as variables. Once `gh` is missing, signed
562
- * out or times out, every later call through the same function answers `unavailable` without running it again.
563
- */
564
- function pullRequestLookups() {
565
- let unavailable;
566
- return async (repo, queries) => {
567
- const exec = getExecutor();
568
- if (unavailable === void 0) unavailable = exec.findExecutable("gh") ? null : "gh is not installed";
569
- const all = (lookup) => queries.map(() => lookup);
570
- if (unavailable) return all({ unavailable });
571
- if (!queries.length) return [];
572
- const args = [
573
- "api",
574
- "graphql",
575
- "-F",
576
- "owner={owner}",
577
- "-F",
578
- "repo={repo}"
579
- ];
580
- queries.forEach(({ branch }, i) => args.push("-f", `b${i}=${branch}`));
581
- args.push("-f", `query=${branchesQuery(queries.length)}`);
582
- let out;
583
- try {
584
- out = await exec.runFileAsync("gh", args, {
585
- cwd: repo,
586
- timeoutMs: GH_TIMEOUT_MS,
587
- env: GH_ENV
588
- });
589
- } catch (error) {
590
- const failure = ghFailure(error, "gh api graphql");
591
- if (failure.sticky) unavailable = failure.unavailable;
592
- return all({ unavailable: failure.unavailable });
593
- }
594
- let found;
595
- try {
596
- found = JSON.parse(out).data?.repository;
597
- } catch {
598
- return all({ unavailable: "gh api graphql printed no JSON" });
599
- }
600
- if (!found) return all({ unavailable: "gh api graphql printed no repository" });
601
- return queries.map(({ cwd, head }, i) => {
602
- const pulls = found[`b${i}`]?.nodes;
603
- return { pullRequest: Array.isArray(pulls) ? selectPullRequest(pulls, head, ancestry(cwd)) : null };
604
- });
605
- };
606
- }
607
- /** The merged or closed pull request whose commits include HEAD, which makes the worktree removable. */
608
- function endedPullRequest(lookup) {
609
- const pr = lookup && "pullRequest" in lookup ? lookup.pullRequest : null;
610
- return pr && pr.state !== "open" && pr.containsHead ? pr : null;
611
- }
612
- /** "PR #123 merged", for reports. */
613
- function describePullRequest(pr) {
614
- return `PR #${pr.number} ${pr.state}`;
615
- }
616
- //#endregion
617
460
  //#region src/engine/warm-claim.ts
618
461
  const WARM_CLAIM_LABEL = "worktree warm";
619
462
  const WARM_CLAIM_POLL_MS = 250;
@@ -634,10 +477,10 @@ function defaultSleep(ms) {
634
477
  return new Promise((resolve) => setTimeout(resolve, ms));
635
478
  }
636
479
  function warmClaimsDir() {
637
- return join$1(getConfigDir(), "warm-locks");
480
+ return join(getConfigDir(), "warm-locks");
638
481
  }
639
482
  function warmClaimPath(repositoryRoot) {
640
- return join$1(warmClaimsDir(), `${workspaceName(repositoryRoot)}.lock`);
483
+ return join(warmClaimsDir(), `${workspaceName(repositoryRoot)}.lock`);
641
484
  }
642
485
  function warmCommand(phase) {
643
486
  return phase === "refresh" ? "stim worktree warm --refresh" : "stim worktree warm";
@@ -964,11 +807,11 @@ function stepLine(label, reason, action) {
964
807
  return phaseLine(label, `${reason} -> ${action}`);
965
808
  }
966
809
  function installRecordFile(depsRoot) {
967
- return join$1(getConfigDir(), "warm-installs", `${workspaceName(depsRoot)}.json`);
810
+ return join(getConfigDir(), "warm-installs", `${workspaceName(depsRoot)}.json`);
968
811
  }
969
812
  function lockfileHash(depsRoot, lockfile) {
970
813
  try {
971
- return createHash("sha256").update(readFileSync(join$1(depsRoot, lockfile))).digest("hex");
814
+ return createHash("sha256").update(readFileSync(join(depsRoot, lockfile))).digest("hex");
972
815
  } catch {
973
816
  return null;
974
817
  }
@@ -990,7 +833,7 @@ function readInstallEvidence(depsRoot) {
990
833
  function writeInstallEvidence(depsRoot, lockfile, hash, completed) {
991
834
  const file = installRecordFile(depsRoot);
992
835
  const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
993
- mkdirSync(join$1(getConfigDir(), "warm-installs"), { recursive: true });
836
+ mkdirSync(join(getConfigDir(), "warm-installs"), { recursive: true });
994
837
  writeFileSync(tmp, JSON.stringify({
995
838
  lock: lockfile,
996
839
  hash: hash ?? "",
@@ -1008,9 +851,9 @@ function restoreInstallEvidence(depsRoot, prior) {
1008
851
  else rmSync(installRecordFile(depsRoot), { force: true });
1009
852
  }
1010
853
  function inProgressOperation(gitDir) {
1011
- if (existsSync(join$1(gitDir, "rebase-merge"))) return "rebase";
1012
- if (existsSync(join$1(gitDir, "rebase-apply"))) return existsSync(join$1(gitDir, "rebase-apply", "applying")) ? "am" : "rebase";
1013
- return existsSync(join$1(gitDir, "MERGE_HEAD")) ? "merge" : null;
854
+ if (existsSync(join(gitDir, "rebase-merge"))) return "rebase";
855
+ if (existsSync(join(gitDir, "rebase-apply"))) return existsSync(join(gitDir, "rebase-apply", "applying")) ? "am" : "rebase";
856
+ return existsSync(join(gitDir, "MERGE_HEAD")) ? "merge" : null;
1014
857
  }
1015
858
  function readMainCheckoutState(root) {
1016
859
  const exec = getExecutor();
@@ -1264,7 +1107,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
1264
1107
  const consumed = dependencies ? lockfileHash(dependencies.root, dependencies.lock) : null;
1265
1108
  const deps = depsPlan({
1266
1109
  lockfile: dependencies?.lock ?? null,
1267
- lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative$1(root, dependencies.root), dependencies.lock)) : false,
1110
+ lockfileChanged: dependencies ? pathChangedBetween(root, before, head, gitPath(relative(root, dependencies.root), dependencies.lock)) : false,
1268
1111
  installed,
1269
1112
  treeValid: dependencies?.lock === "package-lock.json" && installed ? installedNpmTreeIsValid(dependencies.root) : null,
1270
1113
  lastInstall: priorInstall,
@@ -1296,11 +1139,11 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
1296
1139
  if (marked) restoreInstallEvidence(marked.root, priorInstall);
1297
1140
  emit(stepLine("deps", depsSubject, "skipped"));
1298
1141
  }
1299
- const app = relative$1(root, appDir) || ".";
1142
+ const app = relative(root, appDir) || ".";
1300
1143
  const where = `source ${appDir}: `;
1301
1144
  const podState = readPodState(appDir);
1302
1145
  const pods = podsPlan({
1303
- hasIos: existsSync(join$1(appDir, "ios")),
1146
+ hasIos: existsSync(join(appDir, "ios")),
1304
1147
  hasPodfile: podState.hasPodfile,
1305
1148
  podfileLockChanged: pathChangedBetween(root, before, head, gitPath(app, "ios", "Podfile.lock")),
1306
1149
  stale: podsAreStale(podState.lockText, podState.manifestText)
@@ -1331,12 +1174,12 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
1331
1174
  //#endregion
1332
1175
  //#region src/commands/worktree.ts
1333
1176
  function dependencyInstallCommand(target, dir = ".") {
1334
- const installRoot = resolve(target, dir);
1177
+ const installRoot = resolve$1(target, dir);
1335
1178
  let command = "npm install";
1336
- if (existsSync$1(resolve(installRoot, "pnpm-lock.yaml"))) command = "pnpm install";
1337
- else if (existsSync$1(resolve(installRoot, "yarn.lock"))) command = "yarn install";
1338
- else if (existsSync$1(resolve(installRoot, "bun.lock")) || existsSync$1(resolve(installRoot, "bun.lockb"))) command = "bun install";
1339
- else if (existsSync$1(resolve(installRoot, "package-lock.json"))) command = "npm ci";
1179
+ if (existsSync$1(resolve$1(installRoot, "pnpm-lock.yaml"))) command = "pnpm install";
1180
+ else if (existsSync$1(resolve$1(installRoot, "yarn.lock"))) command = "yarn install";
1181
+ else if (existsSync$1(resolve$1(installRoot, "bun.lock")) || existsSync$1(resolve$1(installRoot, "bun.lockb"))) command = "bun install";
1182
+ else if (existsSync$1(resolve$1(installRoot, "package-lock.json"))) command = "npm ci";
1340
1183
  return `cd '${installRoot.replaceAll("'", "'\\''")}' && ${command}`;
1341
1184
  }
1342
1185
  function reportCarriedStateHealth(root, target, copied) {
@@ -1354,7 +1197,7 @@ function reportCarriedStateHealth(root, target, copied) {
1354
1197
  }
1355
1198
  for (const p of podsOutOfSync(target, copied)) {
1356
1199
  const where = p.dir === "." ? "Podfile.lock" : `${p.dir}/Podfile.lock`;
1357
- const pod = podInstallCommand(p.dir === "." ? target : resolve(target, p.dir, ".."));
1200
+ const pod = podInstallCommand(p.dir === "." ? target : resolve$1(target, p.dir, ".."));
1358
1201
  console.error(chalk.yellow(phaseLine("carry", p.reason === "missing" ? `carried ${p.dir === "." ? "Pods" : `${p.dir}/Pods`} but there is no ${where}. Run \`${pod}\` before building.` : `carried ${p.dir === "." ? "Pods" : `${p.dir}/Pods`} does not match the ${where} on disk here. Pods are gitignored and cloned; Podfile.lock is tracked, so the two can disagree. Run \`${pod}\` before building, or xcodebuild fails with "sandbox is not in sync" only after every pod has compiled.`)));
1359
1202
  }
1360
1203
  }
@@ -1366,18 +1209,51 @@ function reportRefreshFailure(failure) {
1366
1209
  process.exitCode = 1;
1367
1210
  }
1368
1211
  function mainCheckoutAppDir(root, target) {
1369
- const app = findProjectRoot(process.cwd());
1212
+ const app = findProjectRoot$1(process.cwd());
1370
1213
  if (!app) return root;
1371
- const rel = relative(target, app);
1372
- if (!rel || rel.startsWith("..") || isAbsolute(rel)) return root;
1373
- return resolve(root, rel);
1214
+ const rel = relative$1(target, app);
1215
+ if (!rel || rel.startsWith("..") || isAbsolute$1(rel)) return root;
1216
+ return resolve$1(root, rel);
1217
+ }
1218
+ /**
1219
+ * The app workspace a warm prepares: the nearest app below the worktree root, or else the one app registered in
1220
+ * the source checkout, at the same place in this worktree, or else the worktree root when it is the app. A monorepo
1221
+ * root can declare react-native without being the app.
1222
+ */
1223
+ function warmedWorkspace(root, target, cwd) {
1224
+ const nearest = findProjectRoot$1(cwd);
1225
+ const app = nearest && isPathPrefix(target, nearest) && appProjectProblem(nearest) === null ? nearest : null;
1226
+ if (app && app !== target) return app;
1227
+ const apps = /* @__PURE__ */ new Set();
1228
+ for (const path of Object.keys(loadConfig$1()?.projects ?? {})) {
1229
+ const rel = relative$1(root, path);
1230
+ if (rel.startsWith("..") || isAbsolute$1(rel)) continue;
1231
+ const mapped = resolve$1(target, rel);
1232
+ if (appProjectProblem(mapped) === null) apps.add(mapped);
1233
+ }
1234
+ return apps.size === 1 ? [...apps][0] : app;
1235
+ }
1236
+ function registerWarmedWorkspace(workspace) {
1237
+ try {
1238
+ if (!getProject(workspace)) upsertProject(workspace, {});
1239
+ } catch (error) {
1240
+ console.error(chalk.yellow(`Could not register ${workspace} for status: ${error?.message || String(error)}`));
1241
+ }
1374
1242
  }
1375
1243
  function registerWarm(worktree) {
1376
1244
  worktree.command("warm").description("Copy missing ignored paths from the source checkout into the current linked worktree.").option("--refresh", "Before copying, fast-forward the source checkout to its upstream and install what the new commits moved.").action(async (opts) => {
1245
+ let progress = null;
1246
+ let workspace = null;
1377
1247
  try {
1378
1248
  const { root, target, common } = warmWorktreePaths(process.cwd());
1379
- const app = findProjectRoot(process.cwd());
1249
+ const app = findProjectRoot$1(process.cwd());
1380
1250
  if (app) recordWorkspaceUse(app);
1251
+ workspace = warmedWorkspace(root, target, process.cwd());
1252
+ if (!workspace) console.error(chalk.dim(phaseLine("project", "no single app to register here; run warm from the app directory to list it in status while it warms")));
1253
+ else {
1254
+ registerWarmedWorkspace(workspace);
1255
+ progress = startWarmProgress(workspace, opts.refresh ? "refresh" : "copy", { note: (line) => console.error(chalk.yellow(line)) });
1256
+ }
1381
1257
  const readSettings = () => {
1382
1258
  const settings = resolveSettings({
1383
1259
  gitCommonDir: common,
@@ -1393,6 +1269,7 @@ function registerWarm(worktree) {
1393
1269
  return settings;
1394
1270
  };
1395
1271
  const copy = (wait) => {
1272
+ progress?.step("copy");
1396
1273
  if (wait?.holder) console.error(warmClaimAcquiredLine(wait));
1397
1274
  const incomplete = incompleteInstallRefusal(root, mainCheckoutAppDir(root, target));
1398
1275
  if (incomplete) {
@@ -1490,6 +1367,10 @@ function registerWarm(worktree) {
1490
1367
  if (claim) console.error(chalk.dim(claim.remedy));
1491
1368
  if (typeof code === "string" && code.startsWith("STIM_")) console.error(chalk.red(`failed: ${code}`));
1492
1369
  process.exitCode = 1;
1370
+ } finally {
1371
+ progress?.finish(!process.exitCode);
1372
+ const links = workspace && !process.exitCode ? workspaceLinks(workspace) : void 0;
1373
+ if (links) console.error(chalk.dim(workspaceLinkLine(links)));
1493
1374
  }
1494
1375
  });
1495
1376
  }
@@ -1504,6 +1385,20 @@ function porcelainPath(line) {
1504
1385
  }
1505
1386
  const SAFE_DIFF_PATH = /^[A-Za-z0-9._/-]+$/;
1506
1387
  const POD_CHURN_PATH = /(?:^|\/)ios\/(?:Podfile\.lock|[^/]+\.xcodeproj\/project\.pbxproj)$/;
1388
+ const WATCHMAN_COOKIE_PATH = /(?:^|\/)\.watchman-cookie-[A-Za-z0-9._-]+$/;
1389
+ function excludeWatchmanCookies(lines) {
1390
+ const kept = [];
1391
+ const cookies = [];
1392
+ for (const line of lines || []) {
1393
+ const path = String(line).startsWith("?? ") ? porcelainPath(line) : null;
1394
+ if (path && SAFE_DIFF_PATH.test(path) && WATCHMAN_COOKIE_PATH.test(path)) cookies.push(path);
1395
+ else kept.push(line);
1396
+ }
1397
+ return {
1398
+ lines: kept,
1399
+ cookies
1400
+ };
1401
+ }
1507
1402
  function excludePodChurn(lines) {
1508
1403
  const kept = [];
1509
1404
  const restore = [];
@@ -1526,11 +1421,11 @@ function excludePodChurn(lines) {
1526
1421
  }
1527
1422
  function nativeCanonicalPath(path) {
1528
1423
  const missing = [];
1529
- for (let existing = resolve(path);; existing = dirname(existing)) try {
1530
- return resolve(realpathSync$1.native(existing), ...missing);
1424
+ for (let existing = resolve$1(path);; existing = dirname$1(existing)) try {
1425
+ return resolve$1(realpathSync$1.native(existing), ...missing);
1531
1426
  } catch {
1532
- if (dirname(existing) === existing) return resolve(path);
1533
- missing.unshift(basename(existing));
1427
+ if (dirname$1(existing) === existing) return resolve$1(path);
1428
+ missing.unshift(basename$1(existing));
1534
1429
  }
1535
1430
  }
1536
1431
  function matchWorktreeEntry(entries, path) {
@@ -1584,7 +1479,7 @@ function describeKeptDevice(s) {
1584
1479
  return s.udid && s.udid !== s.name ? `${s.name} (${s.udid})` : s.name;
1585
1480
  }
1586
1481
  function reclaimKeys(rootPath) {
1587
- const cfg = loadConfig();
1482
+ const cfg = loadConfig$1();
1588
1483
  const keys = /* @__PURE__ */ new Set([rootPath]);
1589
1484
  const root = nativeCanonicalPath(rootPath);
1590
1485
  if (cfg?.projects) {
@@ -1716,7 +1611,7 @@ function reportRetainedResources(root, result) {
1716
1611
  process.exitCode = 1;
1717
1612
  }
1718
1613
  function hasRegisteredProjectUnder(rootPath) {
1719
- const cfg = loadConfig();
1614
+ const cfg = loadConfig$1();
1720
1615
  return Object.keys(cfg?.projects ?? {}).some((key) => isPathPrefix(rootPath, key));
1721
1616
  }
1722
1617
  async function reclaimEnvironment(root, why) {
@@ -1743,20 +1638,21 @@ function removalPath(target) {
1743
1638
  return canonicalExistingPath(target ?? process.cwd());
1744
1639
  }
1745
1640
  function canonicalExistingPath(target) {
1746
- const resolved = resolve(target);
1641
+ const resolved = resolve$1(target);
1747
1642
  let existing = resolved;
1748
1643
  const missing = [];
1749
1644
  while (!existsSync$1(existing)) {
1750
- const parent = dirname(existing);
1645
+ const parent = dirname$1(existing);
1751
1646
  if (parent === existing) return resolved;
1752
- missing.unshift(basename(existing));
1647
+ missing.unshift(basename$1(existing));
1753
1648
  existing = parent;
1754
1649
  }
1755
- return resolve(realpathSync$1(existing), ...missing);
1650
+ return resolve$1(realpathSync$1(existing), ...missing);
1756
1651
  }
1757
1652
  function inspectRemoval(path, mergedHead) {
1758
1653
  const gitAnswered = hasUncommittedWork(path);
1759
- const { lines: dirtyLines, restore: podChurn } = excludePodChurn(gitAnswered ? dirtyPaths(path, { limit: Infinity }) : []);
1654
+ const { lines: withoutCookies, cookies } = excludeWatchmanCookies(gitAnswered ? dirtyPaths(path, { limit: Infinity }) : []);
1655
+ const { lines: dirtyLines, restore: podChurn } = excludePodChurn(withoutCookies);
1760
1656
  const dirty = gitAnswered === null ? null : dirtyLines.length > 0;
1761
1657
  const unpushed = unpushedCommits(path);
1762
1658
  const blockers = removalBlockers({
@@ -1767,6 +1663,7 @@ function inspectRemoval(path, mergedHead) {
1767
1663
  return {
1768
1664
  dirtyLines,
1769
1665
  podChurn,
1666
+ cookies,
1770
1667
  unpushed,
1771
1668
  blockers
1772
1669
  };
@@ -1785,6 +1682,9 @@ function printRemovalRefusal(path, inspection) {
1785
1682
  console.error(chalk.dim("work stays on the branch."));
1786
1683
  process.exitCode = 1;
1787
1684
  }
1685
+ function deleteWatchmanCookies(path, cookies) {
1686
+ for (const cookie of cookies) rmSync$1(join$1(path, cookie), { force: true });
1687
+ }
1788
1688
  function restorePodChurn(path, files) {
1789
1689
  for (const file of files) if (restoreFile(path, file)) console.error(chalk.dim(` restored ${file} (pod install churn; the worktree is being removed)`));
1790
1690
  else console.error(chalk.yellow(` could not restore ${file}; git may refuse to remove the worktree`));
@@ -1832,7 +1732,7 @@ async function runRemove(target, opts, onRemoved) {
1832
1732
  console.error(chalk.dim(phaseLine("branch", `${branch} is already absent; cleared its pending cleanup record`)));
1833
1733
  return;
1834
1734
  }
1835
- const checkedOutAt = listWorktrees(mainRoot).find((candidate) => candidate.branch === branch && resolve(candidate.path) !== resolve(path))?.path;
1735
+ const checkedOutAt = listWorktrees(mainRoot).find((candidate) => candidate.branch === branch && resolve$1(candidate.path) !== resolve$1(path))?.path;
1836
1736
  if (checkedOutAt) {
1837
1737
  console.error(chalk.red(`Refusing pending cleanup for ${branch}: it is checked out at ${checkedOutAt}.`));
1838
1738
  console.error(chalk.dim("Switch that worktree to another branch, then retry this command."));
@@ -1948,6 +1848,7 @@ async function runRemove(target, opts, onRemoved) {
1948
1848
  return;
1949
1849
  }
1950
1850
  restorePodChurn(path, current.podChurn);
1851
+ deleteWatchmanCookies(path, current.cookies);
1951
1852
  try {
1952
1853
  removeWorktree(path, {
1953
1854
  from: source.path,
@@ -1963,6 +1864,7 @@ async function runRemove(target, opts, onRemoved) {
1963
1864
  return;
1964
1865
  }
1965
1866
  onRemoved();
1867
+ forgetStatusMeasures(path, result.reclaimedKeys);
1966
1868
  const finish = () => {
1967
1869
  printRemovalCleanup(result, false);
1968
1870
  console.error(chalk.dim(phaseLine("removed", path)));
@@ -1978,7 +1880,7 @@ async function runRemove(target, opts, onRemoved) {
1978
1880
  worktreeRemovalComplete: true,
1979
1881
  worktreePendingBranchSha: approvedBranchSha
1980
1882
  });
1981
- const checkedOutAt = listWorktrees(branchDeleteCwd).find((candidate) => candidate.branch === branch && resolve(candidate.path) !== resolve(path))?.path;
1883
+ const checkedOutAt = listWorktrees(branchDeleteCwd).find((candidate) => candidate.branch === branch && resolve$1(candidate.path) !== resolve$1(path))?.path;
1982
1884
  if (checkedOutAt) {
1983
1885
  console.error(chalk.yellow(phaseLine("branch", `kept ${branch} (it is checked out at ${checkedOutAt})`)));
1984
1886
  console.error(chalk.dim(` Switch that worktree to another branch, then retry: stim worktree remove ${path}`));
@@ -2012,4 +1914,4 @@ function worktreeCommand(program) {
2012
1914
  registerRemove(worktree);
2013
1915
  }
2014
1916
  //#endregion
2015
- export { reclaimProject as _, reclaimKeys as a, removalBlockers as c, removeWorktreeTarget as d, worktreeCommand as f, describeDereferenced as g, pullRequestLookups as h, porcelainPath as i, removalPath as l, endedPullRequest as m, excludePodChurn as n, registerRemove as o, describePullRequest as p, matchWorktreeEntry as r, registerWarm as s, dependencyInstallCommand as t, removalRemedy as u };
1917
+ export { porcelainPath as a, registerWarm as c, removalRemedy as d, removeWorktreeTarget as f, reclaimProject as g, describeDereferenced as h, matchWorktreeEntry as i, removalBlockers as l, worktreeCommand as m, excludePodChurn as n, reclaimKeys as o, warmedWorkspace as p, excludeWatchmanCookies as r, registerRemove as s, dependencyInstallCommand as t, removalPath as u };