stim 1.18.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 (178) hide show
  1. package/README.md +21 -4
  2. package/dist/{activity-BxnkDZDi.mjs → activity-BrGh9EAI.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-CZ66YA4T.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-DC3ZLuw0.mjs → android-BsYNR81W.mjs} +103 -45
  7. package/dist/{android-CBwCNicO.mjs → android-CK3fpEyZ.mjs} +2 -2
  8. package/dist/{android-cas-BBFyr9CA.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-D0VtFhqk.mjs → api-zuX3ynYN.mjs} +9 -7
  12. package/dist/api.d.mts +104 -4
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-D-PUENug.mjs → app-install-0LgaQRT7.mjs} +39 -18
  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/{web-DTU0uiWj.mjs → browser-web-CzBmhmgs.mjs} +136 -174
  19. package/dist/{budget-DIhL2BKx.mjs → budget-BONq9vXY.mjs} +3096 -3244
  20. package/dist/build-BixRI6sB.mjs +462 -0
  21. package/dist/build-plan-CP0tckNU.mjs +553 -0
  22. package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/ccache-CjHQ5F8g.mjs +142 -0
  25. package/dist/{chrome-DJnmnS5q.mjs → chrome-Dp2lMLBe.mjs} +1 -1
  26. package/dist/{cli-DNJMwADx.mjs → cli-B2R8wH1F.mjs} +20 -20
  27. package/dist/cli.mjs +1 -1
  28. package/dist/{client-DzhapoMB.mjs → client-BLy1Pw2V.mjs} +172 -165
  29. package/dist/collector-run.d.mts +10 -0
  30. package/dist/collector-run.mjs +7 -7
  31. package/dist/{command-output-CBtzyIgF.mjs → command-output-BjPN99ZB.mjs} +2 -2
  32. package/dist/{config-CgYMahz7.mjs → config-D0LhTY3S.mjs} +13 -13
  33. package/dist/{created-devices-DKbeWsiK.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
  34. package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
  35. package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
  36. package/dist/{dev-client-CLnIH02x.mjs → dev-client-ClATaJoH.mjs} +2 -2
  37. package/dist/{device-D7oCHGWi.mjs → device-B7lsC0K1.mjs} +8 -8
  38. package/dist/device-DVCwAFlX.mjs +727 -0
  39. package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-Ca_ke1LE.mjs} +25 -15
  40. package/dist/device-host-worker.mjs +38 -18
  41. package/dist/{device-ios-6MewKKnc.mjs → device-ios-CRUqPxKw.mjs} +12 -11
  42. package/dist/{device-lease-Co-EwifR.mjs → device-lease-DHOBXGgS.mjs} +135 -22
  43. package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
  44. package/dist/{device-pool-F5WvRPtD.mjs → device-pool-L2-5GxMy.mjs} +3 -3
  45. package/dist/{device-remote-tHbd1fKy.mjs → device-remote-Bmg42063.mjs} +17 -69
  46. package/dist/doctor-C2MSuMMg.mjs +515 -0
  47. package/dist/{doctor-B9ckYUoU.mjs → doctor-DPAqhVCK.mjs} +334 -721
  48. package/dist/doctor-watchman-CB4NnVZm.mjs +260 -0
  49. package/dist/{simslim-EHBQ2R4G.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
  50. package/dist/{stim-installations-aR_WsNOA.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
  51. package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
  52. package/dist/errors-DzkMYh8Q.mjs +205 -0
  53. package/dist/{exec-DWhCZDGm.mjs → exec-B81Qodjn.mjs} +69 -15
  54. package/dist/{gc-Dh6mXOKC.mjs → gc-PWp34zGb.mjs} +23 -22
  55. package/dist/{gradle-C6GKnunQ.mjs → gradle-C2OEKCCI.mjs} +50 -125
  56. package/dist/{guide-tm6igAaa.mjs → guide-Dai9lphv.mjs} +862 -538
  57. package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
  58. package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-Io01s5By.mjs} +9 -3
  59. package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
  60. package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
  61. package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
  62. package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-BdAQi21M.mjs} +23 -16
  63. package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
  64. package/dist/ios-BZ9dg2Fr.mjs +9 -0
  65. package/dist/{ios-B3SbOWdw.mjs → ios-CXLIUxXJ.mjs} +180 -24
  66. package/dist/ios-CZuv6gRv.mjs +1112 -0
  67. package/dist/{ios-Bvbf0SGY.mjs → ios-VGvNdsv2.mjs} +1 -1
  68. package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-B1B14xND.mjs} +1 -1
  69. package/dist/{ios-device-vOaByMhw.mjs → ios-device-BreZOpM0.mjs} +3 -3
  70. package/dist/ios-project-B9drt_aY.mjs +197 -0
  71. package/dist/{ios-state-B2pES6Vs.mjs → ios-state-CjrL2qv-.mjs} +1 -1
  72. package/dist/js-swap-C8icNYIY.mjs +432 -0
  73. package/dist/launch-DxH0THLP.mjs +745 -0
  74. package/dist/launch-YrbqaIFj.mjs +1530 -0
  75. package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
  76. package/dist/{logs-1Ylc1Ri6.mjs → logs-DHaRNfg7.mjs} +11 -11
  77. package/dist/macos-C0iljhsN.mjs +2 -0
  78. package/dist/{macos-DF6C7wUU.mjs → macos-V_3Ui7g4.mjs} +125 -155
  79. package/dist/macos-run.mjs +1 -1
  80. package/dist/maintenance-run.mjs +13 -10
  81. package/dist/{metro-Dh8T4Ytd.mjs → metro-D_j9sN-B.mjs} +209 -43
  82. package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
  83. package/dist/miss-reason-BPAzZS0r.mjs +238 -0
  84. package/dist/{named-ports-BFIz1Shz.mjs → named-ports-C2lvoPsb.mjs} +12 -5
  85. package/dist/native-android-lHzaew7r.mjs +226 -0
  86. package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
  87. package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
  88. package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
  89. package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
  90. package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
  91. package/dist/offload-worker.d.mts +12 -6
  92. package/dist/offload-worker.mjs +409 -73
  93. package/dist/{ownership-D6Se7gg_.mjs → ownership-DXzMMSx6.mjs} +2 -2
  94. package/dist/{placement-log-BcPhRwR4.mjs → placement-log-reFbjqEr.mjs} +7 -3
  95. package/dist/plan-BDk2AeY_.mjs +260 -0
  96. package/dist/plan-placement-D_YYlE6N.mjs +73 -0
  97. package/dist/{ports-BLTtfBq-.mjs → ports-jzvAJXXL.mjs} +3 -3
  98. package/dist/{prebuild-juCyreaR.mjs → prebuild-Bw44QxVh.mjs} +4 -4
  99. package/dist/{preview-D5V07Nrl.mjs → preview-BaBJ72Al.mjs} +51 -34
  100. package/dist/project-B8_duAzW.mjs +1067 -0
  101. package/dist/project-plan-BPwbLwQu.mjs +10 -0
  102. package/dist/{pull-request-u4vp7zmK.mjs → pull-request-vOhLNmIb.mjs} +1 -1
  103. package/dist/pull-requests.mjs +1 -1
  104. package/dist/react-native-android-chm1DMlA.mjs +921 -0
  105. package/dist/react-native-build-oAw6gQeW.mjs +239 -0
  106. package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
  107. package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
  108. package/dist/{recordings-BAWltsVt.mjs → recordings-Bk-VivUV.mjs} +1 -1
  109. package/dist/{reload-DvyWzVjJ.mjs → reload-D34GkY78.mjs} +17 -14
  110. package/dist/remote-BU9UyhCJ.mjs +192 -0
  111. package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
  112. package/dist/result-BDoRk1k3.mjs +186 -0
  113. package/dist/{run-vhtDgpHO.mjs → run-qvff78hv.mjs} +3 -3
  114. package/dist/{server-bare-B9E7S1aR.mjs → server-bare-dWjAarki.mjs} +6 -6
  115. package/dist/server-command-7XIKlWtO.mjs +69 -0
  116. package/dist/{server-expo-DoBHhuzK.mjs → server-expo-CsYu2aKL.mjs} +107 -82
  117. package/dist/server-expo-DV43vep4.mjs +2 -0
  118. package/dist/settings-Bbztm4oV.mjs +1503 -0
  119. package/dist/{settings-Byp2AQ_E.mjs → settings-CT3E71-i.mjs} +6 -7
  120. package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
  121. package/dist/settings.schema.json +156 -6
  122. package/dist/simslim-ChMfe8rg.mjs +149 -0
  123. package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-B9hn96wd.mjs} +6 -6
  124. package/dist/{stage-g_WqWeaE.mjs → stage-BNKKdDNc.mjs} +6 -3
  125. package/dist/start-CbQCSnXQ.mjs +2 -0
  126. package/dist/{start-D-IeOyoK.mjs → start-CdvcTaXr.mjs} +113 -77
  127. package/dist/{state-xnqpx3AD.mjs → state-Boo0IMJq.mjs} +4 -2
  128. package/dist/{state-BG-aAk4k.mjs → state-DI84A-uu.mjs} +29 -10
  129. package/dist/{stats-DY6ekz8F.mjs → stats-BIIDrjA8.mjs} +6 -6
  130. package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
  131. package/dist/{status-DCjZeE-K.mjs → status-DARMkc9q.mjs} +80 -294
  132. package/dist/status-watch-DvmI3SmN.mjs +296 -0
  133. package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
  134. package/dist/{stop-DIJtD2GL.mjs → stop-CCZS-C9m.mjs} +2 -2
  135. package/dist/stop-WQPQHLuy.mjs +72 -0
  136. package/dist/{stop-BTjs3xbc.mjs → stop-iNemHsJC.mjs} +81 -33
  137. package/dist/supervisor-run.d.mts +7 -2
  138. package/dist/supervisor-run.mjs +32 -20
  139. package/dist/{support-Bwvbrq5-.mjs → support-CnE_SIjt.mjs} +17 -7
  140. package/dist/{support-BaayeYCf.mjs → support-DCco5fut.mjs} +61 -8
  141. package/dist/swiftpm-macos-afeNUExW.mjs +119 -0
  142. package/dist/{native-run-B06FkmZx.mjs → tailnet-CoJUb2tB.mjs} +113 -6
  143. package/dist/toolchain-BIupIro1.mjs +2 -0
  144. package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-DqyDXs30.mjs} +225 -315
  145. package/dist/{trigger-CJMhwXe8.mjs → trigger-C0MWBi8O.mjs} +3 -3
  146. package/dist/trigger-SHLOWJ4O.mjs +2 -0
  147. package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-C3ASD6z5.mjs} +134 -37
  148. package/dist/{status-Dcr0Qexd.mjs → watchman-CQl51YZu.mjs} +75 -7
  149. package/dist/web-B3eldHFH.mjs +123 -0
  150. package/dist/web-BLXpOe6b.mjs +2 -0
  151. package/dist/web-run.mjs +10 -10
  152. package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
  153. package/dist/{workspaces-xXItD8Dj.mjs → workspaces-D2xSHBDY.mjs} +1297 -1211
  154. package/dist/{worktree-BSYlofkq.mjs → worktree-BxDqaTev.mjs} +102 -63
  155. package/dist/worktree-q7_OZNY0.mjs +2 -0
  156. package/package.json +8 -6
  157. package/shim/bundle-response.cjs +2 -1
  158. package/shim/bundle-response.d.cts +1 -1
  159. package/shim/expo-metro-config.cjs +1 -1
  160. package/shim/native-android.gradle +101 -0
  161. package/dist/android-BKA16DTf.mjs +0 -4
  162. package/dist/android-BvwuMUJ9.mjs +0 -3572
  163. package/dist/guide-status-Bhf9SJXc.mjs +0 -125
  164. package/dist/ios-CPdkoKaa.mjs +0 -3953
  165. package/dist/ios-DNpdygiv.mjs +0 -7
  166. package/dist/macos-Ck7OBMNY.mjs +0 -2
  167. package/dist/metro-store-BAHFcJm6.mjs +0 -106
  168. package/dist/plan-placement-CtxkCO54.mjs +0 -1859
  169. package/dist/project-C3ChRLZy.mjs +0 -212
  170. package/dist/projects-DD7dBTCj.mjs +0 -92
  171. package/dist/server-expo-Db9HBUoa.mjs +0 -2
  172. package/dist/settings-CQyMElEP.mjs +0 -701
  173. package/dist/start-NTc1Ifqs.mjs +0 -2
  174. package/dist/stop-BGhKMOuH.mjs +0 -48
  175. package/dist/trigger-DWAq9hkw.mjs +0 -2
  176. package/dist/web-B6_bFDn7.mjs +0 -2
  177. package/dist/worktree-BJfnU6r5.mjs +0 -2
  178. package/dist/worktree-CsKYexJM.mjs +0 -753
@@ -1,29 +1,36 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
3
3
  import { t as spawnEntry } from "./spawn-entry-Dcb7sDUz.mjs";
4
- import { _ as stepTimer, l as phaseLine } from "./command-output-CBtzyIgF.mjs";
5
- import { E as upsertProject, p as getProject } from "./config-CgYMahz7.mjs";
6
- import { s as gitCommonDir, y as repoRoot } from "./worktree-CsKYexJM.mjs";
7
- import { f as readAppConfigText, i as detectIsExpo, n as appProjectProblem, p as readAppJson, s as findProjectRoot$1, t as NO_PROJECT_REFUSAL } from "./project-C3ChRLZy.mjs";
8
- import { l as resolveProjectMetro, o as pidExists, p as reserveMetroPort, u as signalProcessTree } from "./metro-Dh8T4Ytd.mjs";
9
- 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-C59dqG-Z.mjs";
10
- import { Ht as readMetroTunnel, Rt as clearManagedMetroTunnel, d as stopOwnedMetroForReset, t as budgetGate } from "./budget-DIhL2BKx.mjs";
11
- import { _ as terminateChild, b as withManagedTunnelLock, g as stopTunnel, h as startTunnelSequence, m as resolveSupervisorTarget, v as withManagedRemoteWorktreeLock } from "./workspaces-xXItD8Dj.mjs";
12
- import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Behws_fi.mjs";
13
- import { A as publicUrlSetting, F as resolveSettings, G as PUBLIC_METRO_ENV, H as tunnelModeSetting, K as detectProviders, M as remoteAndroidSetting, N as remoteIosSetting, P as resolveCacheProviderConfig, S as metroTunnelSettingError, U as unknownSettingKeys, b as metroIdleStopMinutesSetting, d as deviceIdleShutdownMinutesSetting, i as SETTING_SHAPE_REMEDY, q as planMetroReach, u as cacheProviderSettingError, w as ngrokUrlSetting, x as metroPortSetting, z as settingShapeErrors } from "./settings-CQyMElEP.mjs";
14
- import { a as withWorkspaceProcessLock, o as workspaceProcessLockError } from "./named-ports-BFIz1Shz.mjs";
15
- import { i as levelRank } from "./ndjson-LGZAMsqa.mjs";
16
- import { d as readProjectConfig } from "./remote-cache-BGg7aGIZ.mjs";
17
- import { n as windowsLauncherArgs } from "./detached-entry-BLfcgc4O.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";
18
17
  import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
19
18
  import { dirname } from "node:path";
20
19
  import { join as join$1 } from "path";
21
20
  import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
22
- import chalk from "chalk";
23
- import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
24
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";
25
24
  import { EventEmitter } from "node:events";
26
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
+ }
27
34
  function configString(config, platform, key) {
28
35
  if (!config || typeof config !== "object") return null;
29
36
  const expoField = config.expo;
@@ -48,21 +55,23 @@ function idsFromConfig(projectRoot) {
48
55
  androidPackage: configString(appJson, "android", "package") ?? literalString(text, "package")
49
56
  };
50
57
  }
51
- function detectAppIds(projectRoot) {
58
+ function detectAppIds(projectRoot, iosDir = join$1(projectRoot, "ios"), androidModuleDir = defaultAndroidLayout(projectRoot).moduleDir) {
52
59
  const ids = idsFromConfig(projectRoot);
60
+ const problems = [];
61
+ const accept = androidPackageFilter(problems);
53
62
  return {
54
- bundleId: ids.bundleId ?? detectBundleIdFromPbxproj(projectRoot),
55
- 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
56
66
  };
57
67
  }
58
- function detectBundleId(projectRoot) {
59
- return detectAppIds(projectRoot).bundleId;
68
+ function detectBundleId(projectRoot, iosDir = join$1(projectRoot, "ios")) {
69
+ return detectAppIds(projectRoot, iosDir).bundleId;
60
70
  }
61
- function detectAndroidPackage(projectRoot) {
62
- return detectAppIds(projectRoot).androidPackage;
71
+ function detectAndroidPackage(projectRoot, androidModuleDir = defaultAndroidLayout(projectRoot).moduleDir) {
72
+ return detectAppIds(projectRoot, void 0, androidModuleDir).androidPackage;
63
73
  }
64
- function detectBundleIdFromPbxproj(projectRoot) {
65
- const iosDir = join$1(projectRoot, "ios");
74
+ function detectBundleIdFromPbxproj(iosDir) {
66
75
  if (!existsSync$1(iosDir)) return null;
67
76
  let entries;
68
77
  try {
@@ -94,20 +103,20 @@ function detectBundleIdFromPbxproj(projectRoot) {
94
103
  }
95
104
  return null;
96
105
  }
97
- function detectAndroidPackageFromGradle(projectRoot) {
98
- const gradle = join$1(projectRoot, "android", "app", "build.gradle");
99
- 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;
100
109
  let text;
101
110
  try {
102
111
  text = readFileSync$1(gradle, "utf-8");
103
112
  } catch {
104
113
  return null;
105
114
  }
106
- const nsId = text.match(/namespace\s+["']([^"']+)["']/)?.[1];
107
- if (nsId) return nsId;
108
- const appId = text.match(/applicationId\s+["']([^"']+)["']/)?.[1];
109
- if (appId) return appId;
110
- 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;
111
120
  }
112
121
  //#endregion
113
122
  //#region src/commands/start.ts
@@ -175,9 +184,14 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
175
184
  function startCommand(program) {
176
185
  registerStart(program);
177
186
  }
178
- 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;
179
192
  return Object.assign(new EventEmitter(), {
180
193
  pid,
194
+ ...recorded ? { recordedIdentity: recorded } : {},
181
195
  stdout: null,
182
196
  stderr: null,
183
197
  kill: (signal = "SIGTERM") => pid !== void 0 && signalProcessTree(pid, typeof signal === "number" ? "SIGTERM" : signal),
@@ -251,13 +265,13 @@ function registerStart(program, overrides = {}) {
251
265
  remedy: "Pass a whole number of seconds, e.g. --wait 90."
252
266
  });
253
267
  const waitSeconds = wait.seconds;
254
- const root = findProjectRoot$1(process.cwd());
268
+ const root = findProjectRoot(process.cwd());
255
269
  if (!root) return fail(NO_PROJECT_REFUSAL);
256
- const projectProblem = appProjectProblem(root);
257
- if (projectProblem) return fail({
270
+ const problem = projectProblem(root, "dev-server");
271
+ if (problem) return fail({
258
272
  code: "STIM_NO_PROJECT",
259
- message: projectProblem.message,
260
- remedy: projectProblem.remedy
273
+ message: problem.message,
274
+ remedy: problem.remedy
261
275
  });
262
276
  try {
263
277
  ensureWorkspaceStorage(root);
@@ -269,12 +283,7 @@ function registerStart(program, overrides = {}) {
269
283
  });
270
284
  }
271
285
  recordWorkspaceUse(root);
272
- const settingsContext = {
273
- projectPath: root,
274
- gitCommonDir: gitCommonDir(root),
275
- repoRoot: repoRoot(root) ?? root
276
- };
277
- const settings = resolveSettings(settingsContext);
286
+ const { context: settingsContext, settings } = resolveProjectSettings(root);
278
287
  const [shapeError, ...moreShapeErrors] = settingShapeErrors(settings);
279
288
  if (shapeError) return fail({
280
289
  code: "STIM_BAD_ARG",
@@ -288,6 +297,7 @@ function registerStart(program, overrides = {}) {
288
297
  const result = await startDevServer({
289
298
  root,
290
299
  settings,
300
+ settingsContext,
291
301
  waitSeconds,
292
302
  remote: Boolean(opts.remote),
293
303
  resetCache: Boolean(opts.resetCache),
@@ -316,7 +326,7 @@ var StartRefusal = class extends Error {
316
326
  this.refusal = refusal;
317
327
  }
318
328
  };
319
- 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 = {}) {
320
330
  const d = {
321
331
  ...DEFAULT_START_DEPS,
322
332
  ...overrides
@@ -327,12 +337,11 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
327
337
  throw new StartRefusal(refusal);
328
338
  };
329
339
  const isExpo = detectIsExpo(root);
330
- const worktreeRoot = repoRoot(root) ?? root;
331
- const cacheProvider = resolveCacheProviderConfig({
332
- projectPath: root,
333
- gitCommonDir: gitCommonDir(root),
334
- repoRoot: worktreeRoot
335
- });
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);
336
345
  const run = async () => {
337
346
  const settingError = metroTunnelSettingError(settings);
338
347
  if (settingError) return fail({
@@ -340,11 +349,27 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
340
349
  message: settingError,
341
350
  remedy: "Set metro.tunnel to \"ngrok\" and metro.ngrokUrl to an HTTPS URL, or remove metro.ngrokUrl."
342
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
+ });
343
368
  const remote = remoteFlag || remoteIosSetting(settings)?.kind === "backend" || remoteAndroidSetting(settings)?.kind === "backend";
344
369
  const tunnelMode = tunnelModeSetting(settings) ?? "auto";
345
370
  const publicUrl = publicUrlSetting(settings);
346
371
  const tunnel = wantsExpoOwnTunnel({
347
- isExpo,
372
+ isExpo: expoServer,
348
373
  remote,
349
374
  mode: tunnelMode,
350
375
  publicUrl
@@ -352,7 +377,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
352
377
  if (tunnel) note(chalk.dim("note requesting an Expo tunnel for this workspace's dev server"));
353
378
  const managedRemote = remote && !tunnel && !publicUrl && tunnelMode !== "off";
354
379
  const runStart = async () => {
355
- const appIds = detectAppIds(root);
380
+ const appIds = detectAppIds(root, resolveIosProjectDir(settings, root).dir, resolveAndroidLayout(settings, root, settingsContext.repoRoot ?? root).moduleDir);
356
381
  upsertProject(root, {
357
382
  bundleId: appIds.bundleId ?? void 0,
358
383
  androidPackage: appIds.androidPackage ?? void 0,
@@ -368,9 +393,9 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
368
393
  };
369
394
  if (resetCache) {
370
395
  await gateBudget();
371
- const pin = metroPortSetting(root);
396
+ const pin = metroPortSetting(settings);
372
397
  if (pin.port !== null || pin.error) {
373
- const pinCheck = await resolveWorkspaceMetroPort(root, note, "start", false);
398
+ const pinCheck = await resolveWorkspaceMetroPort(root, settings, note, "start", false);
374
399
  if (typeof pinCheck !== "number") return fail(pinCheck);
375
400
  }
376
401
  try {
@@ -387,7 +412,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
387
412
  }
388
413
  const logsDir = workspaceLogsDir$1(root);
389
414
  const logFile = supervisorLogFile(root);
390
- const port = await resolvePort(root, note, fail);
415
+ const port = await resolvePort(root, settings, note, fail);
391
416
  let publicOrigin = remote ? publicUrl : null;
392
417
  let resolution = await resolveProjectMetro(port, root);
393
418
  let supervisor = liveSupervisor({
@@ -438,11 +463,14 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
438
463
  });
439
464
  return child;
440
465
  };
441
- const recordedSupervisorPid = async (since) => {
466
+ const recordedSupervisor = async (since) => {
442
467
  const deadline = Date.now() + RECORDED_SUPERVISOR_WAIT_MS;
443
468
  while (Date.now() < deadline) {
444
469
  const record = readWorkspaceState$1(root)?.supervisor;
445
- 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
+ };
446
474
  await sleep(25);
447
475
  }
448
476
  return null;
@@ -483,8 +511,8 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
483
511
  }));
484
512
  });
485
513
  const launcherFailed = exit.code !== 0 || exit.error;
486
- const pid = launcherFailed ? null : await recordedSupervisorPid(since);
487
- if (pid === null) {
514
+ const recorded = launcherFailed ? null : await recordedSupervisor(since);
515
+ if (recorded === null) {
488
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`;
489
517
  appendFileSync(logFile, `Stim start: ${reason}.\n${stderr.join("")}`);
490
518
  childExit = {
@@ -493,7 +521,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
493
521
  ...exit.error ? { error: exit.error } : {}
494
522
  };
495
523
  }
496
- return recordedSupervisorProcess(pid ?? void 0);
524
+ return recordedSupervisorProcess(recorded);
497
525
  };
498
526
  const spawnSupervisor = async (origin) => {
499
527
  mkdirSync(logsDir, { recursive: true });
@@ -520,7 +548,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
520
548
  };
521
549
  childEnv[CACHE_PROVIDER_ENV] = cacheProviderEnv(cacheProvider);
522
550
  const child = d.platform === "win32" ? await spawnThroughWindowsShell(supervisorArgs, childEnv) : spawnDirect(supervisorArgs, childEnv);
523
- 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})`)));
524
552
  spawnedChild = child;
525
553
  return child;
526
554
  };
@@ -544,7 +572,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
544
572
  mode: tunnelMode,
545
573
  metroPort: port,
546
574
  publicUrl,
547
- isExpo,
575
+ isExpo: expoServer,
548
576
  available
549
577
  });
550
578
  if ("failed" in plan) return fail({
@@ -689,20 +717,20 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
689
717
  }
690
718
  const handoffRecord = {
691
719
  pid: child.pid,
692
- 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,
693
721
  port,
694
- mode: isExpo ? "expo-child" : "bare-inproc",
722
+ mode: serverMode,
695
723
  startedAt: new Date(spawnedTs ?? Date.now()).toISOString()
696
724
  };
697
725
  try {
698
726
  d.writeSupervisorRecord(root, { supervisor: handoffRecord });
699
727
  } catch {
700
728
  if (!await waitForSupervisorHandoff(child)) {
701
- const stopped = await d.terminateSupervisorChild(child);
729
+ const stopped = supervisorSignalable(child) && await d.terminateSupervisorChild(child);
702
730
  return { failed: {
703
731
  code: "STIM_SUPERVISOR_EXITED",
704
732
  message: `Could not record supervisor pid ${child.pid ?? "unknown"} before releasing the managed start lock.`,
705
- 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.`
706
734
  } };
707
735
  }
708
736
  }
@@ -959,12 +987,12 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
959
987
  };
960
988
  }
961
989
  }
962
- async function resolvePort(root, note, fail) {
963
- const result = await resolveWorkspaceMetroPort(root, note, "start");
990
+ async function resolvePort(root, settings, note, fail) {
991
+ const result = await resolveWorkspaceMetroPort(root, settings, note, "start");
964
992
  return typeof result === "number" ? result : fail(result);
965
993
  }
966
- async function resolveWorkspaceMetroPort(root, note, command, reserve = true) {
967
- const setting = metroPortSetting(root);
994
+ async function resolveWorkspaceMetroPort(root, settings, note, command, reserve = true) {
995
+ const setting = metroPortSetting(settings);
968
996
  if (setting.error) return {
969
997
  code: "STIM_BAD_ARG",
970
998
  message: setting.error,
@@ -973,7 +1001,7 @@ async function resolveWorkspaceMetroPort(root, note, command, reserve = true) {
973
1001
  const pinned = setting.port;
974
1002
  const project = getProject(root);
975
1003
  const recorded = project?.metroPort;
976
- if (pinned === null && command === "web") return recorded ?? await reserveMetroPort(root);
1004
+ if (pinned === null && command === "web") return recorded ?? await reservePort(root, null);
977
1005
  if (recorded) {
978
1006
  const supervisor = resolveSupervisorTarget({
979
1007
  state: readWorkspaceState$1(root)?.supervisor,
@@ -1005,17 +1033,25 @@ async function resolveWorkspaceMetroPort(root, note, command, reserve = true) {
1005
1033
  } else if (recorded) {
1006
1034
  const held = await resolveProjectMetro(recorded, root);
1007
1035
  if (!held.notOurs) return recorded;
1008
- const fresh = await reserveMetroPort(root);
1009
- if (fresh !== recorded) {
1036
+ const fresh = await reservePort(root, null);
1037
+ if (typeof fresh === "number" && fresh !== recorded) {
1010
1038
  note(chalk.yellow(`Port ${recorded} is held by something else (${held.notOurs}).`));
1011
1039
  note(chalk.dim(`Reserved port ${fresh} for this project instead.`));
1012
1040
  }
1013
1041
  return fresh;
1014
1042
  }
1015
1043
  if (!reserve && pinned !== null) return pinned;
1044
+ return reservePort(root, pinned);
1045
+ }
1046
+ async function reservePort(root, pinned) {
1016
1047
  try {
1017
1048
  return await reserveMetroPort(root, void 0, void 0, pinned);
1018
1049
  } catch (error) {
1050
+ if (error instanceof PortInspectionError) return {
1051
+ code: error.code,
1052
+ message: error.reason,
1053
+ remedy: PORT_INSPECTION_REMEDY
1054
+ };
1019
1055
  return {
1020
1056
  code: "STIM_BAD_ARG",
1021
1057
  message: error.message,
@@ -1078,4 +1114,4 @@ function report({ json, out, facts, waited, reclaimed, links }) {
1078
1114
  if (links) console.error(chalk.dim(workspaceLinkLine(links)));
1079
1115
  }
1080
1116
  //#endregion
1081
- 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,11 +1,13 @@
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-C59dqG-Z.mjs";
2
+ import { a as updateWorkspaceState, r as readWorkspaceState$1, w as workspaceLogsDir$1, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
3
+ import { existsSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
  import { readMacosRecord } from "@stim-cli/core/state";
5
6
  //#region src/macos/state.ts
6
7
  const macosDir = (root) => join(workspaceDir(root), "macos");
7
8
  const macosLogFile = (root) => join(workspaceLogsDir$1(root), "macos.ndjson");
8
9
  const macosRuntimeClaim = (root) => join(macosDir(root), "runtime.lock");
10
+ const macosAppPresent = (root) => readWorkspaceState$1(root)?.macos !== void 0 || existsSync(macosDir(root));
9
11
  function macosProcess(pid) {
10
12
  const processToken = (0, process_identity_exports.captureProcessToken)(pid);
11
13
  const start = (0, process_identity_exports.processStartMicros)(pid);
@@ -38,4 +40,4 @@ function updateMacosRecord(root, owner, patch) {
38
40
  return updated;
39
41
  }
40
42
  //#endregion
41
- export { requiredMacosRecord as a, macosRuntimeClaim as i, macosLogFile as n, updateMacosRecord as o, macosProcess as r, macosDir as t };
43
+ export { macosRuntimeClaim as a, macosProcess as i, macosDir as n, requiredMacosRecord as o, macosLogFile as r, updateMacosRecord as s, macosAppPresent as t };
@@ -1,11 +1,12 @@
1
1
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { o as pidExists } from "./metro-Dh8T4Ytd.mjs";
3
- import { a as updateWorkspaceState, c as writeWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-C59dqG-Z.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-CBtzyIgF.mjs";
2
- import { j as formatBytes } from "./config-CgYMahz7.mjs";
3
- import { s as gitCommonDir, y as repoRoot } from "./worktree-CsKYexJM.mjs";
4
- import { s as findProjectRoot$1 } from "./project-C3ChRLZy.mjs";
5
- import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-CZ66YA4T.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
@@ -13,7 +13,7 @@ function statsCommand(program) {
13
13
  program.command("stats").description("Show how many `ios` and `android` runs this project and this machine have recorded, how many hit the build cache, and an estimate of the time that cache saved.").option("--json", "print the aggregates as JSON").action(async (opts) => {
14
14
  const agentDevice = await getAgentDeviceUsage();
15
15
  const swiftpmCache = await getSwiftpmCacheUsage();
16
- const root = findProjectRoot$1(process.cwd());
16
+ const root = findProjectRoot(process.cwd());
17
17
  const key = root ? statsProjectKey({
18
18
  root,
19
19
  commonDir: gitCommonDir(root),
@@ -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);