stim 1.19.0 → 1.20.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 (172) hide show
  1. package/README.md +20 -3
  2. package/dist/{activity-BSw0x84R.mjs → activity-BrGh9EAI.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-Bjxu_VmX.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
  4. package/dist/android-0vv-OruW.mjs +6 -0
  5. package/dist/android-Brx6EKvJ.mjs +1258 -0
  6. package/dist/{android-BdQC6zs1.mjs → android-BsYNR81W.mjs} +103 -45
  7. package/dist/{android-DE5g_5gv.mjs → android-CK3fpEyZ.mjs} +2 -2
  8. package/dist/{android-cas-C87geAg-.mjs → android-cas-DCAuXryb.mjs} +9 -5
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/api-run.mjs +159 -8
  11. package/dist/{api-DIf_s86s.mjs → api-zuX3ynYN.mjs} +5 -1
  12. package/dist/api.d.mts +98 -4
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-CFI4ptUL.mjs → app-install-0LgaQRT7.mjs} +9 -8
  15. package/dist/artifact-CnC0mfov.mjs +807 -0
  16. package/dist/artifact-DClXJNWx.mjs +772 -0
  17. package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
  18. package/dist/{browser-web-CDhqQxhv.mjs → browser-web-CzBmhmgs.mjs} +19 -19
  19. package/dist/{budget-Dz-kyXLv.mjs → budget-BONq9vXY.mjs} +3101 -3062
  20. package/dist/build-BixRI6sB.mjs +462 -0
  21. package/dist/{build-facts-B87vo-Im.d.mts → build-facts-DcLv2HSd.d.mts} +1 -32
  22. package/dist/build-plan-CP0tckNU.mjs +553 -0
  23. package/dist/{cache-manifest-DiwKSyv9.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
  24. package/dist/cache-manifest.mjs +1 -1
  25. package/dist/{manifest-CX0d1IkZ.mjs → ccache-CjHQ5F8g.mjs} +13 -19
  26. package/dist/{chrome-BTUOo8p2.mjs → chrome-Dp2lMLBe.mjs} +1 -1
  27. package/dist/{cli-C9Zvgbdc.mjs → cli-B2R8wH1F.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-CuUo8Nvg.mjs → client-BLy1Pw2V.mjs} +89 -307
  30. package/dist/collector-run.d.mts +4 -0
  31. package/dist/collector-run.mjs +7 -7
  32. package/dist/{command-output-Bt8ygHE7.mjs → command-output-BjPN99ZB.mjs} +2 -2
  33. package/dist/{config-DC5jEtd1.mjs → config-D0LhTY3S.mjs} +8 -12
  34. package/dist/{created-devices-D0s26Hx5.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
  35. package/dist/{dependency-state-DKaS1OM9.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
  36. package/dist/{detached-entry-pB_IPfV4.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
  37. package/dist/{dev-client-CDY_zAmD.mjs → dev-client-ClATaJoH.mjs} +2 -2
  38. package/dist/{device-BHw0WlHl.mjs → device-B7lsC0K1.mjs} +8 -8
  39. package/dist/device-DVCwAFlX.mjs +727 -0
  40. package/dist/{device-capacity-BoN1jQkO.mjs → device-capacity-Ca_ke1LE.mjs} +13 -14
  41. package/dist/device-host-worker.mjs +38 -18
  42. package/dist/device-ios-CRUqPxKw.mjs +413 -0
  43. package/dist/{device-lease-Cu7PtQpZ.mjs → device-lease-DHOBXGgS.mjs} +135 -22
  44. package/dist/{device-lease-run-D38SnZtt.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
  45. package/dist/{device-pool-CP4rAsHx.mjs → device-pool-L2-5GxMy.mjs} +3 -3
  46. package/dist/{device-remote-B5GiUifk.mjs → device-remote-Bmg42063.mjs} +17 -68
  47. package/dist/doctor-C2MSuMMg.mjs +515 -0
  48. package/dist/{doctor-PRJH94v6.mjs → doctor-DPAqhVCK.mjs} +333 -744
  49. package/dist/{doctor-watchman-wZhyTdp4.mjs → doctor-watchman-CB4NnVZm.mjs} +13 -12
  50. package/dist/{simslim-D9LkJxIO.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
  51. package/dist/{stim-installations-DbmUjsLv.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
  52. package/dist/{error-diagnostics--v5HGOU0.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
  53. package/dist/errors-DzkMYh8Q.mjs +205 -0
  54. package/dist/{exec-i8GDPwq9.mjs → exec-B81Qodjn.mjs} +40 -10
  55. package/dist/{gc-CyHMcKcn.mjs → gc-PWp34zGb.mjs} +21 -20
  56. package/dist/{device-ios-B2ruohE-.mjs → gradle-C2OEKCCI.mjs} +21 -650
  57. package/dist/{guide-dRaQJJk9.mjs → guide-Dai9lphv.mjs} +504 -117
  58. package/dist/{hosted-android-Bs7fytj7.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
  59. package/dist/{hosted-client-C5G4h_OJ.mjs → hosted-client-Io01s5By.mjs} +9 -3
  60. package/dist/{hosted-ios-Bik035eL.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
  61. package/dist/{hosted-logs-CI9Az9a4.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
  62. package/dist/{hosted-macos-DABm3ScO.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
  63. package/dist/{hosted-native-DbV2aUVw.mjs → hosted-native-BdAQi21M.mjs} +17 -14
  64. package/dist/{idle-shutdown-DYiMBn34.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
  65. package/dist/{ios-DYUr9LGc.mjs → ios-BZ9dg2Fr.mjs} +8 -7
  66. package/dist/{ios-BWbHFZVz.mjs → ios-CXLIUxXJ.mjs} +180 -24
  67. package/dist/ios-CZuv6gRv.mjs +1112 -0
  68. package/dist/{ios-DCrkgXEM.mjs → ios-VGvNdsv2.mjs} +1 -1
  69. package/dist/{ios-device-CrW8aMb5.mjs → ios-device-B1B14xND.mjs} +1 -1
  70. package/dist/{ios-device-CJ_ZOGky.mjs → ios-device-BreZOpM0.mjs} +3 -3
  71. package/dist/ios-project-B9drt_aY.mjs +197 -0
  72. package/dist/{ios-state-By0XuLTQ.mjs → ios-state-CjrL2qv-.mjs} +1 -1
  73. package/dist/js-swap-C8icNYIY.mjs +432 -0
  74. package/dist/launch-DxH0THLP.mjs +745 -0
  75. package/dist/{react-native-ios-CSpIxexZ.mjs → launch-YrbqaIFj.mjs} +59 -612
  76. package/dist/{launch-verify-DCveSE6d.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
  77. package/dist/{logs-Bao1HOMy.mjs → logs-DHaRNfg7.mjs} +11 -11
  78. package/dist/macos-C0iljhsN.mjs +2 -0
  79. package/dist/{macos-ciyBdTY5.mjs → macos-V_3Ui7g4.mjs} +42 -50
  80. package/dist/macos-run.mjs +1 -1
  81. package/dist/maintenance-run.mjs +13 -10
  82. package/dist/{metro-DI2AjPF_.mjs → metro-D_j9sN-B.mjs} +18 -5
  83. package/dist/{metro-gateway-BxpJLIwh.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
  84. package/dist/miss-reason-BPAzZS0r.mjs +238 -0
  85. package/dist/{named-ports-B4iWH4E-.mjs → named-ports-C2lvoPsb.mjs} +3 -3
  86. package/dist/native-android-lHzaew7r.mjs +226 -0
  87. package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
  88. package/dist/{native-runtime-BGxsbfny.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
  89. package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
  90. package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
  91. package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
  92. package/dist/offload-worker.d.mts +41 -7
  93. package/dist/offload-worker.mjs +409 -74
  94. package/dist/{ownership-EB0ySdGK.mjs → ownership-DXzMMSx6.mjs} +2 -2
  95. package/dist/{placement-log-Dxe34rJm.mjs → placement-log-reFbjqEr.mjs} +1 -1
  96. package/dist/plan-BDk2AeY_.mjs +260 -0
  97. package/dist/plan-placement-D_YYlE6N.mjs +73 -0
  98. package/dist/{ports-ByPc0_97.mjs → ports-jzvAJXXL.mjs} +3 -3
  99. package/dist/{prebuild-BKJ3wJI1.mjs → prebuild-Bw44QxVh.mjs} +4 -4
  100. package/dist/{preview-BbSottmO.mjs → preview-BaBJ72Al.mjs} +50 -32
  101. package/dist/project-B8_duAzW.mjs +1067 -0
  102. package/dist/project-plan-BPwbLwQu.mjs +10 -0
  103. package/dist/{pull-request-IHNdMnG8.mjs → pull-request-vOhLNmIb.mjs} +1 -1
  104. package/dist/pull-requests.mjs +1 -1
  105. package/dist/react-native-android-chm1DMlA.mjs +921 -0
  106. package/dist/react-native-build-oAw6gQeW.mjs +239 -0
  107. package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
  108. package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
  109. package/dist/{recordings-Bv8McZN4.mjs → recordings-Bk-VivUV.mjs} +1 -1
  110. package/dist/{reload-rAPdqeRR.mjs → reload-D34GkY78.mjs} +17 -13
  111. package/dist/remote-BU9UyhCJ.mjs +192 -0
  112. package/dist/{remote-cache-N3hAEaAL.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
  113. package/dist/result-BDoRk1k3.mjs +186 -0
  114. package/dist/{run-lAkle1-c.mjs → run-qvff78hv.mjs} +3 -3
  115. package/dist/{server-bare-CkIjnegq.mjs → server-bare-dWjAarki.mjs} +5 -5
  116. package/dist/server-command-7XIKlWtO.mjs +69 -0
  117. package/dist/{server-expo-n3tUi3Em.mjs → server-expo-CsYu2aKL.mjs} +107 -82
  118. package/dist/server-expo-DV43vep4.mjs +2 -0
  119. package/dist/{settings-CxgngUZk.mjs → settings-Bbztm4oV.mjs} +179 -129
  120. package/dist/{settings-2am7TSxp.mjs → settings-CT3E71-i.mjs} +6 -6
  121. package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
  122. package/dist/settings.schema.json +84 -0
  123. package/dist/simslim-ChMfe8rg.mjs +149 -0
  124. package/dist/{slot-launch-HV_KtPIw.mjs → slot-launch-B9hn96wd.mjs} +6 -6
  125. package/dist/{stage-BgaZJVZY.mjs → stage-BNKKdDNc.mjs} +6 -3
  126. package/dist/start-CbQCSnXQ.mjs +2 -0
  127. package/dist/{start-DtxthMfI.mjs → start-CdvcTaXr.mjs} +97 -68
  128. package/dist/{state-Tp4uImDS.mjs → state-Boo0IMJq.mjs} +1 -1
  129. package/dist/{state-D2KtnALG.mjs → state-DI84A-uu.mjs} +29 -10
  130. package/dist/{stats-8EJ5ivFT.mjs → stats-BIIDrjA8.mjs} +5 -5
  131. package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
  132. package/dist/{status-BOyp0CUl.mjs → status-DARMkc9q.mjs} +81 -293
  133. package/dist/status-watch-DvmI3SmN.mjs +296 -0
  134. package/dist/{stim-desktop-C65jk_q2.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
  135. package/dist/{stop-DRipAg-e.mjs → stop-CCZS-C9m.mjs} +2 -2
  136. package/dist/{stop-D0UIpZuh.mjs → stop-WQPQHLuy.mjs} +5 -5
  137. package/dist/{stop-zDlknFoz.mjs → stop-iNemHsJC.mjs} +21 -20
  138. package/dist/supervisor-run.d.mts +7 -2
  139. package/dist/supervisor-run.mjs +32 -20
  140. package/dist/{support-DsNaFg6D.mjs → support-CnE_SIjt.mjs} +17 -7
  141. package/dist/{support-CNqYkV0y.mjs → support-DCco5fut.mjs} +61 -8
  142. package/dist/{swiftpm-macos-aJzPAj1t.mjs → swiftpm-macos-afeNUExW.mjs} +5 -5
  143. package/dist/tailnet-CoJUb2tB.mjs +265 -0
  144. package/dist/toolchain-BIupIro1.mjs +2 -0
  145. package/dist/{toolchain-C3xSoyUl.mjs → toolchain-DqyDXs30.mjs} +206 -53
  146. package/dist/{trigger-CAhmG-4s.mjs → trigger-C0MWBi8O.mjs} +2 -2
  147. package/dist/trigger-SHLOWJ4O.mjs +2 -0
  148. package/dist/{warm-progress-pFLB2e6P.mjs → warm-progress-C3ASD6z5.mjs} +6 -6
  149. package/dist/{watchman-BL1IdOtq.mjs → watchman-CQl51YZu.mjs} +6 -6
  150. package/dist/{web-DbbrPUn0.mjs → web-B3eldHFH.mjs} +9 -13
  151. package/dist/web-BLXpOe6b.mjs +2 -0
  152. package/dist/web-run.mjs +10 -10
  153. package/dist/{workspace-state-CR9X86xJ.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
  154. package/dist/{workspaces-Djb2gfi9.mjs → workspaces-D2xSHBDY.mjs} +1260 -1258
  155. package/dist/{worktree-BL4M1rhB.mjs → worktree-BxDqaTev.mjs} +84 -48
  156. package/dist/worktree-q7_OZNY0.mjs +2 -0
  157. package/package.json +8 -6
  158. package/shim/native-android.gradle +101 -0
  159. package/dist/android-BXc6BmEi.mjs +0 -3732
  160. package/dist/android-BvV1gGdN.mjs +0 -4
  161. package/dist/ios-ITYno9rO.mjs +0 -2241
  162. package/dist/macos-nIOATJmR.mjs +0 -2
  163. package/dist/metro-store-BAHFcJm6.mjs +0 -106
  164. package/dist/miss-reason-CjQCOKqq.mjs +0 -1743
  165. package/dist/plan-placement-BVY59qa8.mjs +0 -290
  166. package/dist/project-B5eQ1USs.mjs +0 -612
  167. package/dist/react-native-ios-BMh2i25I.mjs +0 -2
  168. package/dist/server-expo-DGsdUGX2.mjs +0 -2
  169. package/dist/start-D8NbxNBb.mjs +0 -2
  170. package/dist/trigger-CoalsMTV.mjs +0 -2
  171. package/dist/web-DFpFeZu5.mjs +0 -2
  172. package/dist/worktree-DV-A0LNL.mjs +0 -2
@@ -1,28 +1,36 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
3
3
  import { t as spawnEntry } from "./spawn-entry-Dcb7sDUz.mjs";
4
- import { _ as stepTimer, l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
5
- import { E as upsertProject, p as getProject } from "./config-DC5jEtd1.mjs";
6
- import { c as writeWorkspaceState, g as workspaceAgentDeviceDir, i as recordWorkspaceUse, m as supervisorLogFile, n as clearWorkspaceStateKeys, r as readWorkspaceState$1, u as ensureWorkspaceStorage, x as workspaceLogsDir$1 } from "./workspace-state-CR9X86xJ.mjs";
7
- import { E as readMetroTunnel, S as clearManagedMetroTunnel, _ as readAppJson, g as readAppConfigText, p as detectIsExpo, r as findProjectRoot, s as projectProblem, t as NO_PROJECT_REFUSAL } from "./project-B5eQ1USs.mjs";
8
- import { A as publicUrlSetting, B as settingShapeErrors, F as resolveCacheProviderConfig, I as resolveSettings, J as planMetroReach, K as PUBLIC_METRO_ENV, M as remoteAndroidSetting, P as remoteIosSetting, S as metroTunnelSettingError, U as tunnelModeSetting, W as unknownSettingKeys, b as metroIdleStopMinutesSetting, d as deviceIdleShutdownMinutesSetting, i as SETTING_SHAPE_REMEDY, mt as repoRoot, nt as gitCommonDir, q as detectProviders, u as cacheProviderSettingError, w as ngrokUrlSetting, x as metroPortSetting } from "./settings-CxgngUZk.mjs";
9
- import { d as signalProcessTree, g as PortInspectionError, h as PORT_INSPECTION_REMEDY, m as reserveMetroPort, s as pidExists, u as resolveProjectMetro } from "./metro-DI2AjPF_.mjs";
10
- import { d as stopOwnedMetroForReset, t as budgetGate } from "./budget-Dz-kyXLv.mjs";
11
- import { _ as terminateChild, b as withManagedTunnelLock, g as stopTunnel, h as startTunnelSequence, m as resolveSupervisorTarget, v as withManagedRemoteWorktreeLock } from "./workspaces-Djb2gfi9.mjs";
12
- import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-C65jk_q2.mjs";
13
- import { a as withWorkspaceProcessLock, o as workspaceProcessLockError } from "./named-ports-B4iWH4E-.mjs";
14
- import { i as levelRank } from "./ndjson-LGZAMsqa.mjs";
15
- import { d as readProjectConfig } from "./remote-cache-N3hAEaAL.mjs";
16
- import { n as windowsLauncherArgs } from "./detached-entry-pB_IPfV4.mjs";
4
+ import { E as upsertProject, p as getProject } from "./config-D0LhTY3S.mjs";
5
+ import { A as metroIdleStopMinutesSetting, B as remoteAndroidSetting, G as resolveIosProjectDir, H as remoteIosSetting, K as resolveProjectSettings, L as publicUrlSetting, M as metroTunnelSettingError, O as metroCommandSetting, P as ngrokUrlSetting, Q as settingShapeErrors, U as resolveAndroidLayout, W as resolveCacheProviderConfig, a as SETTING_SHAPE_REMEDY, at as detectProviders, h as deviceIdleShutdownMinutesSetting, it as PUBLIC_METRO_ENV, j as metroPortSetting, k as metroCommandSettingError, m as defaultAndroidLayout, nt as unknownSettingKeys, ot as planMetroReach, p as cacheProviderSettingError, tt as tunnelModeSetting } from "./settings-Bbztm4oV.mjs";
6
+ import { _ as supervisorLogFile, c as writeWorkspaceState, i as recordWorkspaceUse, n as clearWorkspaceStateKeys, p as ensureWorkspaceStorage, r as readWorkspaceState$1, w as workspaceLogsDir$1, y as workspaceAgentDeviceDir } from "./workspace-state-CSIFuuDa.mjs";
7
+ import { _ as stepTimer, l as phaseLine } from "./command-output-BjPN99ZB.mjs";
8
+ import { C as MODE_BARE, D as clearManagedMetroTunnel, T as MODE_EXPO, _ as detectIsExpo, b as readAppConfigText, j as readMetroTunnel, r as findProjectRoot, s as projectProblem, t as NO_PROJECT_REFUSAL, w as MODE_COMMAND, x as readAppJson } from "./project-B8_duAzW.mjs";
9
+ import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-8GQX2OV8.mjs";
10
+ import { d as signalProcessTree, g as PortInspectionError, h as PORT_INSPECTION_REMEDY, m as reserveMetroPort, s as pidExists, u as resolveProjectMetro } from "./metro-D_j9sN-B.mjs";
11
+ import { D as stopTunnel, E as startTunnelSequence, O as terminateChild, P as resolveSupervisorTarget, j as withManagedTunnelLock, k as withManagedRemoteWorktreeLock } from "./workspaces-D2xSHBDY.mjs";
12
+ import { ct as stopOwnedMetroForReset, t as budgetGate } from "./budget-BONq9vXY.mjs";
13
+ import { a as withWorkspaceProcessLock, o as workspaceProcessLockError } from "./named-ports-C2lvoPsb.mjs";
14
+ import { i as levelRank } from "./ndjson-GOnbyvso.mjs";
15
+ import { d as readProjectConfig } from "./remote-cache-Bsts6f6Y.mjs";
16
+ import { n as windowsLauncherArgs } from "./detached-entry-BXq4fIl-.mjs";
17
17
  import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
18
18
  import { dirname } from "node:path";
19
19
  import { join as join$1 } from "path";
20
20
  import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
21
- import chalk from "chalk";
22
- import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
23
21
  import { CACHE_PROVIDER_ENV, cacheProviderEnv } from "@stim-cli/cache";
22
+ import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
23
+ import chalk from "chalk";
24
24
  import { EventEmitter } from "node:events";
25
25
  //#region src/workspace/app-id.ts
26
+ const ANDROID_PACKAGE_NAME = /^[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)+$/;
27
+ function androidPackageFilter(problems) {
28
+ return (id, source) => {
29
+ if (id === null || ANDROID_PACKAGE_NAME.test(id)) return id;
30
+ problems.push(`Invalid Android package ${JSON.stringify(id)} in ${source}. Expected dot-separated letters, digits and underscores, such as com.example.app.`);
31
+ return null;
32
+ };
33
+ }
26
34
  function configString(config, platform, key) {
27
35
  if (!config || typeof config !== "object") return null;
28
36
  const expoField = config.expo;
@@ -47,21 +55,23 @@ function idsFromConfig(projectRoot) {
47
55
  androidPackage: configString(appJson, "android", "package") ?? literalString(text, "package")
48
56
  };
49
57
  }
50
- function detectAppIds(projectRoot) {
58
+ function detectAppIds(projectRoot, iosDir = join$1(projectRoot, "ios"), androidModuleDir = defaultAndroidLayout(projectRoot).moduleDir) {
51
59
  const ids = idsFromConfig(projectRoot);
60
+ const problems = [];
61
+ const accept = androidPackageFilter(problems);
52
62
  return {
53
- bundleId: ids.bundleId ?? detectBundleIdFromPbxproj(projectRoot),
54
- androidPackage: ids.androidPackage ?? detectAndroidPackageFromGradle(projectRoot)
63
+ bundleId: ids.bundleId ?? detectBundleIdFromPbxproj(iosDir),
64
+ androidPackage: accept(ids.androidPackage, "the Expo config android.package") ?? detectAndroidPackageFromGradle(androidModuleDir, accept),
65
+ androidPackageProblem: problems.length > 0 ? problems.join(" ") : null
55
66
  };
56
67
  }
57
- function detectBundleId(projectRoot) {
58
- return detectAppIds(projectRoot).bundleId;
68
+ function detectBundleId(projectRoot, iosDir = join$1(projectRoot, "ios")) {
69
+ return detectAppIds(projectRoot, iosDir).bundleId;
59
70
  }
60
- function detectAndroidPackage(projectRoot) {
61
- return detectAppIds(projectRoot).androidPackage;
71
+ function detectAndroidPackage(projectRoot, androidModuleDir = defaultAndroidLayout(projectRoot).moduleDir) {
72
+ return detectAppIds(projectRoot, void 0, androidModuleDir).androidPackage;
62
73
  }
63
- function detectBundleIdFromPbxproj(projectRoot) {
64
- const iosDir = join$1(projectRoot, "ios");
74
+ function detectBundleIdFromPbxproj(iosDir) {
65
75
  if (!existsSync$1(iosDir)) return null;
66
76
  let entries;
67
77
  try {
@@ -93,20 +103,20 @@ function detectBundleIdFromPbxproj(projectRoot) {
93
103
  }
94
104
  return null;
95
105
  }
96
- function detectAndroidPackageFromGradle(projectRoot) {
97
- const gradle = join$1(projectRoot, "android", "app", "build.gradle");
98
- if (!existsSync$1(gradle)) return null;
106
+ function detectAndroidPackageFromGradle(moduleDir, accept) {
107
+ const gradle = [join$1(moduleDir, "build.gradle"), join$1(moduleDir, "build.gradle.kts")].find((file) => existsSync$1(file));
108
+ if (!gradle) return null;
99
109
  let text;
100
110
  try {
101
111
  text = readFileSync$1(gradle, "utf-8");
102
112
  } catch {
103
113
  return null;
104
114
  }
105
- const nsId = text.match(/namespace\s+["']([^"']+)["']/)?.[1];
106
- if (nsId) return nsId;
107
- const appId = text.match(/applicationId\s+["']([^"']+)["']/)?.[1];
108
- if (appId) return appId;
109
- return null;
115
+ const nsId = text.match(/namespace\s*=?\s*["']([^"']+)["']/)?.[1];
116
+ const namespace = nsId ? accept(nsId, gradle) : null;
117
+ if (namespace) return namespace;
118
+ const appId = text.match(/applicationId\s*=?\s*["']([^"']+)["']/)?.[1];
119
+ return appId ? accept(appId, gradle) : null;
110
120
  }
111
121
  //#endregion
112
122
  //#region src/commands/start.ts
@@ -174,9 +184,14 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
174
184
  function startCommand(program) {
175
185
  registerStart(program);
176
186
  }
177
- function recordedSupervisorProcess(pid) {
187
+ function supervisorSignalable(child, inspectIdentity = process_identity_exports.inspectProcessIdentity) {
188
+ return !child.recordedIdentity || inspectIdentity(child.recordedIdentity) === "same";
189
+ }
190
+ function recordedSupervisorProcess(recorded) {
191
+ const pid = typeof recorded?.pid === "number" ? recorded.pid : void 0;
178
192
  return Object.assign(new EventEmitter(), {
179
193
  pid,
194
+ ...recorded ? { recordedIdentity: recorded } : {},
180
195
  stdout: null,
181
196
  stderr: null,
182
197
  kill: (signal = "SIGTERM") => pid !== void 0 && signalProcessTree(pid, typeof signal === "number" ? "SIGTERM" : signal),
@@ -268,12 +283,7 @@ function registerStart(program, overrides = {}) {
268
283
  });
269
284
  }
270
285
  recordWorkspaceUse(root);
271
- const settingsContext = {
272
- projectPath: root,
273
- gitCommonDir: gitCommonDir(root),
274
- repoRoot: repoRoot(root) ?? root
275
- };
276
- const settings = resolveSettings(settingsContext);
286
+ const { context: settingsContext, settings } = resolveProjectSettings(root);
277
287
  const [shapeError, ...moreShapeErrors] = settingShapeErrors(settings);
278
288
  if (shapeError) return fail({
279
289
  code: "STIM_BAD_ARG",
@@ -287,6 +297,7 @@ function registerStart(program, overrides = {}) {
287
297
  const result = await startDevServer({
288
298
  root,
289
299
  settings,
300
+ settingsContext,
290
301
  waitSeconds,
291
302
  remote: Boolean(opts.remote),
292
303
  resetCache: Boolean(opts.resetCache),
@@ -315,7 +326,7 @@ var StartRefusal = class extends Error {
315
326
  this.refusal = refusal;
316
327
  }
317
328
  };
318
- async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECONDS, remote: remoteFlag = false, resetCache = false, out, note }, overrides = {}) {
329
+ async function startDevServer({ root, settings, settingsContext, waitSeconds = DEFAULT_WAIT_SECONDS, remote: remoteFlag = false, resetCache = false, out, note }, overrides = {}) {
319
330
  const d = {
320
331
  ...DEFAULT_START_DEPS,
321
332
  ...overrides
@@ -326,12 +337,11 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
326
337
  throw new StartRefusal(refusal);
327
338
  };
328
339
  const isExpo = detectIsExpo(root);
329
- const worktreeRoot = repoRoot(root) ?? root;
330
- const cacheProvider = resolveCacheProviderConfig({
331
- projectPath: root,
332
- gitCommonDir: gitCommonDir(root),
333
- repoRoot: worktreeRoot
334
- });
340
+ const metroCommand = metroCommandSetting(settings);
341
+ const serverMode = metroCommand ? MODE_COMMAND : isExpo ? MODE_EXPO : MODE_BARE;
342
+ const expoServer = serverMode === MODE_EXPO;
343
+ const worktreeRoot = settingsContext.repoRoot ?? root;
344
+ const cacheProvider = resolveCacheProviderConfig(settingsContext);
335
345
  const run = async () => {
336
346
  const settingError = metroTunnelSettingError(settings);
337
347
  if (settingError) return fail({
@@ -339,11 +349,27 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
339
349
  message: settingError,
340
350
  remedy: "Set metro.tunnel to \"ngrok\" and metro.ngrokUrl to an HTTPS URL, or remove metro.ngrokUrl."
341
351
  });
352
+ if (metroCommand && d.platform === "win32") return fail({
353
+ code: "STIM_BAD_ARG",
354
+ message: "metro.command is not supported on Windows: Stim cannot read a process working directory there, so it cannot prove the Metro a wrapper starts belongs to this app.",
355
+ remedy: "Remove metro.command on Windows, or run this app from macOS or Linux."
356
+ });
357
+ if (metroCommand && resetCache) return fail({
358
+ code: "STIM_BAD_ARG",
359
+ message: "--reset-cache cannot reach a dev server started by metro.command; Stim does not know its reset flag.",
360
+ remedy: "Add the command's own cache-reset flag to metro.command (for React Native, --reset-cache), then run stim stop and stim start."
361
+ });
362
+ const commandError = metroCommandSettingError(settings);
363
+ if (commandError) return fail({
364
+ code: "STIM_BAD_ARG",
365
+ message: commandError,
366
+ remedy: "Set metro.command to the argv that starts the dev server, e.g. [\"npx\", \"react-native\", \"start\", \"--port\", \"{port}\"], or remove it."
367
+ });
342
368
  const remote = remoteFlag || remoteIosSetting(settings)?.kind === "backend" || remoteAndroidSetting(settings)?.kind === "backend";
343
369
  const tunnelMode = tunnelModeSetting(settings) ?? "auto";
344
370
  const publicUrl = publicUrlSetting(settings);
345
371
  const tunnel = wantsExpoOwnTunnel({
346
- isExpo,
372
+ isExpo: expoServer,
347
373
  remote,
348
374
  mode: tunnelMode,
349
375
  publicUrl
@@ -351,7 +377,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
351
377
  if (tunnel) note(chalk.dim("note requesting an Expo tunnel for this workspace's dev server"));
352
378
  const managedRemote = remote && !tunnel && !publicUrl && tunnelMode !== "off";
353
379
  const runStart = async () => {
354
- const appIds = detectAppIds(root);
380
+ const appIds = detectAppIds(root, resolveIosProjectDir(settings, root).dir, resolveAndroidLayout(settings, root, settingsContext.repoRoot ?? root).moduleDir);
355
381
  upsertProject(root, {
356
382
  bundleId: appIds.bundleId ?? void 0,
357
383
  androidPackage: appIds.androidPackage ?? void 0,
@@ -367,9 +393,9 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
367
393
  };
368
394
  if (resetCache) {
369
395
  await gateBudget();
370
- const pin = metroPortSetting(root);
396
+ const pin = metroPortSetting(settings);
371
397
  if (pin.port !== null || pin.error) {
372
- const pinCheck = await resolveWorkspaceMetroPort(root, note, "start", false);
398
+ const pinCheck = await resolveWorkspaceMetroPort(root, settings, note, "start", false);
373
399
  if (typeof pinCheck !== "number") return fail(pinCheck);
374
400
  }
375
401
  try {
@@ -386,7 +412,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
386
412
  }
387
413
  const logsDir = workspaceLogsDir$1(root);
388
414
  const logFile = supervisorLogFile(root);
389
- const port = await resolvePort(root, note, fail);
415
+ const port = await resolvePort(root, settings, note, fail);
390
416
  let publicOrigin = remote ? publicUrl : null;
391
417
  let resolution = await resolveProjectMetro(port, root);
392
418
  let supervisor = liveSupervisor({
@@ -437,11 +463,14 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
437
463
  });
438
464
  return child;
439
465
  };
440
- const recordedSupervisorPid = async (since) => {
466
+ const recordedSupervisor = async (since) => {
441
467
  const deadline = Date.now() + RECORDED_SUPERVISOR_WAIT_MS;
442
468
  while (Date.now() < deadline) {
443
469
  const record = readWorkspaceState$1(root)?.supervisor;
444
- if (record?.pid && record.port === port && Date.parse(String(record.startedAt)) >= since && pidExists(record.pid)) return record.pid;
470
+ if (record?.pid && record.port === port && Date.parse(String(record.startedAt)) >= since && pidExists(record.pid)) return {
471
+ pid: record.pid,
472
+ processToken: record.processToken
473
+ };
445
474
  await sleep(25);
446
475
  }
447
476
  return null;
@@ -482,8 +511,8 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
482
511
  }));
483
512
  });
484
513
  const launcherFailed = exit.code !== 0 || exit.error;
485
- const pid = launcherFailed ? null : await recordedSupervisorPid(since);
486
- if (pid === null) {
514
+ const recorded = launcherFailed ? null : await recordedSupervisor(since);
515
+ if (recorded === null) {
487
516
  const reason = launcherFailed ? `the supervisor launcher exited (${exit.error ? exit.error.message : `code ${exit.code}`})` : `the supervisor did not record itself within ${RECORDED_SUPERVISOR_WAIT_MS / 1e3}s`;
488
517
  appendFileSync(logFile, `Stim start: ${reason}.\n${stderr.join("")}`);
489
518
  childExit = {
@@ -492,7 +521,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
492
521
  ...exit.error ? { error: exit.error } : {}
493
522
  };
494
523
  }
495
- return recordedSupervisorProcess(pid ?? void 0);
524
+ return recordedSupervisorProcess(recorded);
496
525
  };
497
526
  const spawnSupervisor = async (origin) => {
498
527
  mkdirSync(logsDir, { recursive: true });
@@ -519,7 +548,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
519
548
  };
520
549
  childEnv[CACHE_PROVIDER_ENV] = cacheProviderEnv(cacheProvider);
521
550
  const child = d.platform === "win32" ? await spawnThroughWindowsShell(supervisorArgs, childEnv) : spawnDirect(supervisorArgs, childEnv);
522
- out(chalk.dim(phaseLine("metro", `starting on port ${port} (${isExpo ? "expo-child" : "bare-inproc"}, supervisor pid ${child.pid})`)));
551
+ out(chalk.dim(phaseLine("metro", `starting on port ${port} (${serverMode}, supervisor pid ${child.pid})`)));
523
552
  spawnedChild = child;
524
553
  return child;
525
554
  };
@@ -543,7 +572,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
543
572
  mode: tunnelMode,
544
573
  metroPort: port,
545
574
  publicUrl,
546
- isExpo,
575
+ isExpo: expoServer,
547
576
  available
548
577
  });
549
578
  if ("failed" in plan) return fail({
@@ -688,20 +717,20 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
688
717
  }
689
718
  const handoffRecord = {
690
719
  pid: child.pid,
691
- processToken: child.pid ? (0, process_identity_exports.captureProcessToken)(child.pid) : null,
720
+ processToken: child.recordedIdentity ? child.recordedIdentity.processToken ?? null : child.pid ? (0, process_identity_exports.captureProcessToken)(child.pid) : null,
692
721
  port,
693
- mode: isExpo ? "expo-child" : "bare-inproc",
722
+ mode: serverMode,
694
723
  startedAt: new Date(spawnedTs ?? Date.now()).toISOString()
695
724
  };
696
725
  try {
697
726
  d.writeSupervisorRecord(root, { supervisor: handoffRecord });
698
727
  } catch {
699
728
  if (!await waitForSupervisorHandoff(child)) {
700
- const stopped = await d.terminateSupervisorChild(child);
729
+ const stopped = supervisorSignalable(child) && await d.terminateSupervisorChild(child);
701
730
  return { failed: {
702
731
  code: "STIM_SUPERVISOR_EXITED",
703
732
  message: `Could not record supervisor pid ${child.pid ?? "unknown"} before releasing the managed start lock.`,
704
- remedy: stopped ? "The supervisor process was stopped. Retry `stim start --remote`." : `Cleanup failed. Unmanaged supervisor pid ${child.pid ?? "unknown"} may still be running. Stop it before retrying.`
733
+ remedy: stopped ? "The supervisor process was stopped. Retry `stim start --remote`." : `Cleanup failed. Unmanaged supervisor pid ${child.pid ?? "unknown"} may still be running. Stop it with \`stim stop\`${child.pid === void 0 ? "" : `, or \`${d.platform === "win32" ? `taskkill /PID ${child.pid} /T /F` : `kill ${child.pid}`}\``} before retrying.`
705
734
  } };
706
735
  }
707
736
  }
@@ -958,12 +987,12 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
958
987
  };
959
988
  }
960
989
  }
961
- async function resolvePort(root, note, fail) {
962
- const result = await resolveWorkspaceMetroPort(root, note, "start");
990
+ async function resolvePort(root, settings, note, fail) {
991
+ const result = await resolveWorkspaceMetroPort(root, settings, note, "start");
963
992
  return typeof result === "number" ? result : fail(result);
964
993
  }
965
- async function resolveWorkspaceMetroPort(root, note, command, reserve = true) {
966
- const setting = metroPortSetting(root);
994
+ async function resolveWorkspaceMetroPort(root, settings, note, command, reserve = true) {
995
+ const setting = metroPortSetting(settings);
967
996
  if (setting.error) return {
968
997
  code: "STIM_BAD_ARG",
969
998
  message: setting.error,
@@ -1085,4 +1114,4 @@ function report({ json, out, facts, waited, reclaimed, links }) {
1085
1114
  if (links) console.error(chalk.dim(workspaceLinkLine(links)));
1086
1115
  }
1087
1116
  //#endregion
1088
- export { registerStart as a, startDevServer as c, tailLines as d, wantsExpoOwnTunnel as f, detectBundleId as h, readLogTail as i, startFacts as l, detectAppIds as m, liveSupervisor as n, resolveWorkspaceMetroPort as o, detectAndroidPackage as p, parseWait as r, startCommand as s, failureEvidence as t, supervisorEntry as u };
1117
+ export { registerStart as a, startDevServer as c, supervisorSignalable as d, tailLines as f, detectBundleId as g, detectAppIds as h, readLogTail as i, startFacts as l, detectAndroidPackage as m, liveSupervisor as n, resolveWorkspaceMetroPort as o, wantsExpoOwnTunnel as p, parseWait as r, startCommand as s, failureEvidence as t, supervisorEntry as u };
@@ -1,5 +1,5 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { a as updateWorkspaceState, r as readWorkspaceState$1, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-CR9X86xJ.mjs";
2
+ import { a as updateWorkspaceState, r as readWorkspaceState$1, w as workspaceLogsDir$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { readMacosRecord } from "@stim-cli/core/state";
@@ -1,11 +1,12 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { a as updateWorkspaceState, c as writeWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-CR9X86xJ.mjs";
3
- import { s as pidExists } from "./metro-DI2AjPF_.mjs";
2
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
3
+ import { a as updateWorkspaceState, c as writeWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey, w as workspaceLogsDir$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
4
+ import { s as pidExists } from "./metro-D_j9sN-B.mjs";
4
5
  import { readFileSync, readlinkSync, rmSync } from "node:fs";
5
6
  import { join } from "node:path";
6
7
  import { WEB_VIEWPORTS } from "@stim-cli/core/state";
7
- import { hostname } from "node:os";
8
8
  import { rotatedLogPath } from "@stim-cli/core";
9
+ import { hostname } from "node:os";
9
10
  //#region src/web/profile.ts
10
11
  const SINGLETON_FILES = [
11
12
  "SingletonLock",
@@ -32,17 +33,35 @@ function liveProfileHolder(profile, { alive = pidExists } = {}) {
32
33
  function removeSingletonFiles(profile) {
33
34
  for (const name of SINGLETON_FILES) rmSync(join(profile, name), { force: true });
34
35
  }
36
+ /** Whether a process in group `pgid` in a `ps -o pgid=,command=` listing has `profile` as its Chrome user data dir. */
37
+ function groupRunsProfile(listing, pgid, profile) {
38
+ const flag = `--user-data-dir=${profile}`;
39
+ return listing.split("\n").some((line) => {
40
+ const row = /^\s*(\d+)\s+(.*)$/.exec(line);
41
+ if (!row || Number(row[1]) !== pgid) return false;
42
+ const at = row[2].indexOf(flag);
43
+ return at !== -1 && (row[2].length === at + flag.length || row[2][at + flag.length] === " ");
44
+ });
45
+ }
35
46
  /**
36
- * Whether the owned Chrome still runs. `lingering` means the recorded process exited but its process group, whose
37
- * id is that pid, still has helper processes: a live group id cannot be reused. A pid now held by a different
38
- * process is `gone`, never something to signal.
47
+ * Whether the owned Chrome still runs. `lingering` means the recorded process exited but a process of its group,
48
+ * whose id is that pid, still runs Chrome on `profile`. A group id stays reserved only while the original group
49
+ * lives, so a live group whose members do not run on the profile is `gone`, never something to signal, and so is a
50
+ * pid now held by a different process.
39
51
  */
40
- function chromeProcessState(record) {
52
+ function chromeProcessState(record, profile) {
41
53
  const identity = (0, process_identity_exports.inspectProcessIdentity)(record);
42
54
  if (identity === "same") return "running";
43
55
  if (identity === "unknown") return "unknown";
44
- if (identity === "different") return "gone";
45
- return (0, ownership_claim_exports.processGroupAlive)(record.pid) ? "lingering" : "gone";
56
+ if (identity === "different" || !(0, ownership_claim_exports.processGroupAlive)(record.pid)) return "gone";
57
+ const listing = getExecutor().runFileQuiet("ps", [
58
+ "-A",
59
+ "-ww",
60
+ "-o",
61
+ "pgid=,command="
62
+ ]);
63
+ if (listing === null) return "unknown";
64
+ return groupRunsProfile(listing, record.pid, profile) ? "lingering" : "gone";
46
65
  }
47
66
  //#endregion
48
67
  //#region src/web/state.ts
@@ -132,7 +151,7 @@ function cdpEndpoint(port) {
132
151
  function webFacts(record) {
133
152
  if (!record) return null;
134
153
  const supervisor = (0, process_identity_exports.inspectProcessIdentity)(record);
135
- const chrome = record.chromeProcess ? chromeProcessState(record.chromeProcess) : "gone";
154
+ const chrome = record.chromeProcess ? chromeProcessState(record.chromeProcess, record.profile) : "gone";
136
155
  if (supervisor === "unknown" || chrome === "unknown") return {
137
156
  record,
138
157
  status: "unverified"
@@ -1,8 +1,8 @@
1
- import { o as formatLongDuration } from "./command-output-Bt8ygHE7.mjs";
2
- import { j as formatBytes } from "./config-DC5jEtd1.mjs";
3
- import { r as findProjectRoot } from "./project-B5eQ1USs.mjs";
4
- import { mt as repoRoot, nt as gitCommonDir } from "./settings-CxgngUZk.mjs";
5
- import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-Bjxu_VmX.mjs";
1
+ import { j as formatBytes } from "./config-D0LhTY3S.mjs";
2
+ import { Et as repoRoot, mt as gitCommonDir } from "./settings-Bbztm4oV.mjs";
3
+ import { o as formatLongDuration } from "./command-output-BjPN99ZB.mjs";
4
+ import { r as findProjectRoot } from "./project-B8_duAzW.mjs";
5
+ import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-DVyv_hWj.mjs";
6
6
  import { archivedUsage, readArchives, readStatsReport, statsProjectKey } from "@stim-cli/core/state";
7
7
  import chalk from "chalk";
8
8
  //#region src/commands/stats.ts
@@ -1,3 +1,4 @@
1
+ import { j as formatBytes } from "./config-D0LhTY3S.mjs";
1
2
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
2
3
  import { maintenanceRunClaims, readMaintenanceState } from "@stim-cli/core/state";
3
4
  import { claimRemoveCommand, readClaimSet } from "@stim-cli/core/ownership-claim";
@@ -41,7 +42,8 @@ function maintenanceLine(status, includeLabel = true) {
41
42
  const outputs = status.plan.filter((action) => action.kind === "would-clear-outputs");
42
43
  const summary = status.mode === "on" && status.lastPass ? `${status.lastPass.actions} actions, ${(status.lastPass.freedBytes / 1024 ** 3).toFixed(1)} GB freed` : outputs.length ? `would clear build outputs of ${outputs.length} ${outputs.length === 1 ? "workspace" : "workspaces"} (${(outputs.reduce((sum, action) => sum + action.bytes, 0) / 1024 ** 3).toFixed(1)} GB)` : `${status.plan.length} planned actions`;
43
44
  const disk = status.pressure?.disk.map((volume) => `disk ${(volume.freeMb / 1024).toFixed(1)} GB free on ${volume.volume}`).join(", ");
44
- return `${includeLabel ? `Auto maintenance (${status.mode === "report" ? "report only" : status.mode}): ` : ""}${at ? `${at}: ` : ""}${status.lastPass ? summary : "no pass has run yet"}${disk ? `; ${disk}` : ""}${status.running ? "; running" : ""}${status.lastPass?.blocked.length ? `; ${status.lastPass.blocked.join("; ")}` : ""}${status.invalid ? `; invalid: ${status.invalid}` : ""}${status.claim ? `; unresolved claim: ${status.claim.unresolved}; ${status.claim.removeCommand}` : ""}`;
45
+ const culprits = (status.mode === "off" ? void 0 : status.pressure?.memory.culprits)?.map((culprit) => `${culprit.name} uses ${formatBytes(culprit.bytes)}${culprit.command ? ` (\`${culprit.command}\`)` : ""}`).join(", ");
46
+ return `${includeLabel ? `Auto maintenance (${status.mode === "report" ? "report only" : status.mode}): ` : ""}${at ? `${at}: ` : ""}${status.lastPass ? summary : "no pass has run yet"}${disk ? `; ${disk}` : ""}${culprits ? `; memory: ${culprits}` : ""}${status.running ? "; running" : ""}${status.lastPass?.blocked.length ? `; ${status.lastPass.blocked.join("; ")}` : ""}${status.invalid ? `; invalid: ${status.invalid}` : ""}${status.claim ? `; unresolved claim: ${status.claim.unresolved}; ${status.claim.removeCommand}` : ""}`;
45
47
  }
46
48
  function maintenanceLines(status) {
47
49
  const line = maintenanceLine(status);