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,8 +1,8 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
2
- import { s as isAppLaunchError } from "./command-output-CBtzyIgF.mjs";
3
- import { o as readNdjsonGenerations } from "./ndjson-LGZAMsqa.mjs";
4
- import { f as deviceShellArg, n as ANDROID_DISABLE_AUTO_LAUNCH_EXTRA, s as androidAppProcess } from "./app-install-D-PUENug.mjs";
5
- import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-Bn7jWDB1.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
+ import { s as isAppLaunchError } from "./command-output-BjPN99ZB.mjs";
3
+ import { s as readNdjsonGenerations } from "./ndjson-GOnbyvso.mjs";
4
+ import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-B1B14xND.mjs";
5
+ import { f as deviceShellArg, n as ANDROID_DISABLE_AUTO_LAUNCH_EXTRA, s as androidAppProcess } from "./app-install-0LgaQRT7.mjs";
6
6
  import { join } from "node:path";
7
7
  //#region src/engine/app-readiness.ts
8
8
  const APP_READINESS_TIMEOUT_MS = 3e4;
@@ -121,7 +121,7 @@ function nativeLaunchFailure({ readCrashes, since, platform, processAlive, mode,
121
121
  waitedMs
122
122
  } : null;
123
123
  }
124
- async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
124
+ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, onActivity, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
125
125
  const delivered = (record) => deliveryOwner(record, {
126
126
  slot,
127
127
  appPid,
@@ -140,6 +140,13 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
140
140
  let runtimeLoadingAt = null;
141
141
  let runtimeStartedAt = null;
142
142
  let nextCrashCheck = startedAt + 1e3;
143
+ let bundlingAt = null;
144
+ let reported = null;
145
+ const report = (name, at) => {
146
+ if (name === reported) return;
147
+ reported = name;
148
+ onActivity?.(name, at);
149
+ };
143
150
  while (true) {
144
151
  const metroRecords = read().filter((record) => after(record, since));
145
152
  const bundleRecords = metroRecords.filter((record) => (!requireBundleResponse || String(record.event).startsWith("bundle_response_")) && delivered(record));
@@ -161,6 +168,7 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
161
168
  const request = bundleRecords.find((record) => record.event === "bundle_response_started" && typeof record.requestId === "string" && isBundleProof(record, since, platform));
162
169
  if (request) {
163
170
  deliveryId = request.requestId;
171
+ bundlingAt = request;
164
172
  proof = null;
165
173
  stabilityDeadline = null;
166
174
  }
@@ -193,6 +201,7 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
193
201
  onReadinessPending?.();
194
202
  }
195
203
  }
204
+ report(...launchActivity(pendingAt, proof, bundlingAt));
196
205
  const ready = pendingAt !== null && signals.some((record) => Number(record.ts) >= pendingAt && Number(record.ts) <= readinessDeadline && appReadinessSignal(record, platform) === "ready");
197
206
  const bundleErrors = bundleRecords.filter((record) => isFatalLaunchError(record, platform) || deliveryId !== null && record.event === "bundle_response_failed" && record.requestId === deliveryId && isBundleProof(record, since, platform));
198
207
  if (bundleErrors.length) {
@@ -257,6 +266,11 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
257
266
  await sleep(Math.min(pollMs, Math.max(0, (runtimeWaiting ? bundleDeadline : proof && pendingAt !== null ? readinessDeadline : stabilityDeadline ?? bundleDeadline) - now())));
258
267
  }
259
268
  }
269
+ function launchActivity(pendingAt, proof, bundling) {
270
+ if (pendingAt !== null) return ["waiting-ready", pendingAt];
271
+ if (proof) return [null, Number(proof.ts)];
272
+ return bundling ? ["bundling", Number(bundling.ts)] : [null, 0];
273
+ }
260
274
  function deliveryOwner(record, { slot, appPid, platformShared }) {
261
275
  if (slot === void 0) return "this";
262
276
  if (typeof record.clientPid === "number" && appPid) return record.clientPid === appPid ? "this" : "other";
@@ -306,7 +320,12 @@ function isIosConnectionRefusal(record, platform) {
306
320
  }
307
321
  function isFatalLaunchError(record, platform) {
308
322
  if (platform && recordPlatform(record) !== platform) return false;
309
- return record.event === "bundle_build_failed" || record.event === "bundling_error" || record.event === "transformer_error" || (record.event === "expo_stdout" || record.event === "expo_stderr") && typeof record.msg === "string" && /\bBundling failed\b/.test(record.msg);
323
+ return record.event === "bundle_build_failed" || record.event === "bundling_error" || record.event === "transformer_error" || [
324
+ "expo_stdout",
325
+ "expo_stderr",
326
+ "command_stdout",
327
+ "command_stderr"
328
+ ].includes(String(record.event)) && typeof record.msg === "string" && /\bBundling failed\b/.test(record.msg);
310
329
  }
311
330
  function isBundleReadyProof(record, since = 0, platform = null) {
312
331
  if (!isBundleProof(record, since, platform)) return false;
@@ -1,15 +1,15 @@
1
1
  import { t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { f as refuseNoProject, l as phaseLine, v as launchErrorPreview } from "./command-output-CBtzyIgF.mjs";
3
- import { H as projectDeviceSlots, V as parseDeviceSlotOption, _ as loadConfig$1, g as isPathPrefix } from "./config-CgYMahz7.mjs";
4
- import { o as findCommandWorkspace } from "./project-C3ChRLZy.mjs";
5
- import { r as readWorkspaceState$1, x as workspaceLogsDir$1 } from "./workspace-state-C59dqG-Z.mjs";
6
- import { n as agentDeviceLiveness, u as readAgentDeviceRecords } from "./activity-BxnkDZDi.mjs";
7
- import { n as SOURCES, t as LEVELS } from "./ndjson-LGZAMsqa.mjs";
8
- import { o as connectHost } from "./hosted-client-C-rMtppF.mjs";
9
- import { n as pullHostedNativeLogs, t as pullHostedMacosLogs } from "./hosted-logs-DN8Iz4mJ.mjs";
10
- import { n as readHostedIos, t as readHostedAndroid } from "./ios-state-B2pES6Vs.mjs";
11
- import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-BRXOqDzG.mjs";
12
- import "./hosted-macos-B-wEjlwG.mjs";
2
+ import { H as projectDeviceSlots, V as parseDeviceSlotOption, _ as loadConfig$1, g as isPathPrefix } from "./config-D0LhTY3S.mjs";
3
+ import { r as readWorkspaceState$1, w as workspaceLogsDir$1 } from "./workspace-state-CSIFuuDa.mjs";
4
+ import { f as refuseNoProject, l as phaseLine, v as launchErrorPreview } from "./command-output-BjPN99ZB.mjs";
5
+ import { n as findCommandWorkspace } from "./project-B8_duAzW.mjs";
6
+ import { n as SOURCES, t as LEVELS } from "./ndjson-GOnbyvso.mjs";
7
+ import { n as agentDeviceLiveness, u as readAgentDeviceRecords } from "./activity-BrGh9EAI.mjs";
8
+ import { s as connectHost } from "./hosted-client-Io01s5By.mjs";
9
+ import { n as pullHostedNativeLogs, t as pullHostedMacosLogs } from "./hosted-logs-DP-ABU_M.mjs";
10
+ import { n as readHostedIos, t as readHostedAndroid } from "./ios-state-CjrL2qv-.mjs";
11
+ import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-Du7I_GuY.mjs";
12
+ import "./hosted-macos-Aziw9T_9.mjs";
13
13
  import { t as watchStdoutReader } from "./stdout-reader-C8yjre1x.mjs";
14
14
  import { realpathSync } from "node:fs";
15
15
  import { dirname, join, relative, resolve, sep } from "node:path";
@@ -0,0 +1,2 @@
1
+ import { n as runMacos, t as macosCommand } from "./macos-V_3Ui7g4.mjs";
2
+ export { macosCommand as default, runMacos };
@@ -1,93 +1,37 @@
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 { l as phaseLine } from "./command-output-CBtzyIgF.mjs";
5
- import { E as upsertProject, u as getConcurrencyLimits } from "./config-CgYMahz7.mjs";
6
- import { s as gitCommonDir, y as repoRoot } from "./worktree-CsKYexJM.mjs";
7
- import { s as findProjectRoot$1, u as ownedDeviceLabel } from "./project-C3ChRLZy.mjs";
8
- import { c as writeWorkspaceState, g as workspaceAgentDeviceDir, i as recordWorkspaceUse, u as ensureWorkspaceStorage, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-C59dqG-Z.mjs";
9
- import { F as recordFinishedBuild, I as startBuildProgress, L as tapBuildLog, O as NO_BUILD_PROGRESS, P as recordBuildPhase } from "./budget-DIhL2BKx.mjs";
10
- import { N as releaseBuildSlot, j as acquireBuildSlot } from "./workspaces-xXItD8Dj.mjs";
4
+ import { E as upsertProject, u as getConcurrencyLimits } from "./config-D0LhTY3S.mjs";
5
+ import { K as resolveProjectSettings, Q as settingShapeErrors, a as SETTING_SHAPE_REMEDY } from "./settings-Bbztm4oV.mjs";
6
+ import { c as writeWorkspaceState, i as recordWorkspaceUse, p as ensureWorkspaceStorage, w as workspaceLogsDir$1, x as workspaceDir, y as workspaceAgentDeviceDir } from "./workspace-state-CSIFuuDa.mjs";
7
+ import { l as phaseLine } from "./command-output-BjPN99ZB.mjs";
8
+ import { d as projectRegistry, o as ownedDeviceLabel, r as findProjectRoot } from "./project-B8_duAzW.mjs";
11
9
  import { a as spawnDeclared } from "./spawn-claims-Kqiifsk2.mjs";
12
- import { E as sanitizeDeviceLabel } from "./ios-B3SbOWdw.mjs";
13
- import { F as resolveSettings, i as SETTING_SHAPE_REMEDY, z as settingShapeErrors } from "./settings-CQyMElEP.mjs";
14
- import { a as withWorkspaceProcessLock } from "./named-ports-BFIz1Shz.mjs";
15
- import { a as requiredMacosRecord, n as macosLogFile, r as macosProcess, t as macosDir } from "./state-xnqpx3AD.mjs";
16
- import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
17
- import { _ as resolveBuildPlacement, a as offloadBuild, c as placementLoad, d as setRemoteLogSink, f as OffloadRefusal, h as parseBuildMachineOption, i as closeOffload, l as remotePhaseText, m as namedBuildMachine, n as buildPlacementCandidates, r as chooseBuildMachine, s as offloadPlacement } from "./client-DzhapoMB.mjs";
18
- import { i as macosToolchain } from "./toolchain-Bnyd_K3A.mjs";
19
- import { o as connectHost } from "./hosted-client-C-rMtppF.mjs";
20
- import { t as buildPlacementRecord } from "./placement-log-BcPhRwR4.mjs";
21
- import { f as withNativeBuildRun } from "./native-run-B06FkmZx.mjs";
22
- import { t as placeHostedMacos } from "./hosted-macos-B-wEjlwG.mjs";
23
- import { t as logLines } from "./run-vhtDgpHO.mjs";
24
- import { i as validateInfoPlist, n as setBundleName, r as stageBundle, t as resolveBundleExtras } from "./stage-g_WqWeaE.mjs";
25
- import { n as stopMacosAppHeld } from "./stop-BGhKMOuH.mjs";
10
+ import { F as acquireBuildSlot, L as releaseBuildSlot } from "./workspaces-D2xSHBDY.mjs";
11
+ import { Dt as recordFinishedBuild, Et as recordBuildPhase, Ot as startBuildProgress, kt as tapBuildLog, yt as NO_BUILD_PROGRESS } from "./budget-BONq9vXY.mjs";
12
+ import { a as withWorkspaceProcessLock } from "./named-ports-C2lvoPsb.mjs";
13
+ import { S as withNativeBuildRun } from "./tailnet-CoJUb2tB.mjs";
14
+ import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
15
+ import { _ as requireLocalBuild, c as offloadPlacement, f as setRemoteLogSink, g as parseBuildMachineOption, h as namedBuildMachine, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, p as OffloadRefusal, r as chooseBuildMachine, u as remotePhaseText, y as resolveBuildPlacement } from "./client-BLy1Pw2V.mjs";
16
+ import { D as sanitizeDeviceLabel } from "./ios-CXLIUxXJ.mjs";
17
+ import { i as macosProcess, n as macosDir, o as requiredMacosRecord, r as macosLogFile } from "./state-Boo0IMJq.mjs";
18
+ import { t as buildPlacementRecord } from "./placement-log-reFbjqEr.mjs";
19
+ import { s as connectHost } from "./hosted-client-Io01s5By.mjs";
20
+ import { t as placeHostedMacos } from "./hosted-macos-Aziw9T_9.mjs";
21
+ import { i as validateInfoPlist, t as resolveBundleExtras } from "./stage-BNKKdDNc.mjs";
22
+ import { r as stopMacosAppHeld, t as stopBundleInstances } from "./stop-WQPQHLuy.mjs";
26
23
  import { closeSync, existsSync, mkdirSync, mkdtempSync, openSync, realpathSync, renameSync, rmSync } from "node:fs";
27
- import { join, relative, resolve } from "node:path";
24
+ import { join } from "node:path";
28
25
  import { machineCapacity, readMacosRecord, validHostedAppArguments } from "@stim-cli/core/state";
29
26
  import { LOG_ROTATE_BYTES } from "@stim-cli/core";
30
27
  import { createHash, randomUUID } from "node:crypto";
31
- //#region src/macos/app-name.ts
32
- const DOT = String.fromCodePoint(183);
33
- const ELLIPSIS = String.fromCodePoint(8230);
34
- const LABEL_MAX = 24;
35
- const PRODUCT_MAX = 40;
36
- function clip(text, max) {
37
- const chars = [...text];
38
- return chars.length <= max ? text : `${chars.slice(0, max - 1).join("")}${ELLIPSIS}`;
39
- }
40
- /** The visible app name for a run: `<product> <dot> <label>`, or just the product when the label is empty. */
41
- function macosAppName(product, label) {
42
- const name = clip(product.replace(/[\p{Cc}/:\\]+/gu, " ").trim(), PRODUCT_MAX) || "App";
43
- const suffix = clip(sanitizeDeviceLabel(label), LABEL_MAX);
44
- return suffix ? `${name} ${DOT} ${suffix}` : name;
45
- }
46
- function workspaceAppName(root, product) {
47
- return macosAppName(product, ownedDeviceLabel(root));
48
- }
49
- //#endregion
50
28
  //#region src/macos/build.ts
51
- async function tool(root, args, writer, note, capture = false) {
52
- const child = spawnDeclared(() => getExecutor().spawn("swift", args, {
53
- cwd: root,
54
- detached: true,
55
- stdio: [
56
- "ignore",
57
- "pipe",
58
- "pipe"
59
- ]
60
- }));
61
- let stdout = "";
62
- child.stdout?.on("data", (chunk) => {
63
- if (capture) stdout += chunk.toString("utf8");
64
- });
65
- const write = (msg) => {
66
- writer.write({
67
- src: "build",
68
- platform: "macos",
69
- level: "debug",
70
- msg
71
- });
72
- note(msg);
73
- };
74
- if (child.stdout) logLines(child.stdout, write);
75
- if (child.stderr) logLines(child.stderr, write);
76
- await new Promise((done, reject) => {
77
- child.once("error", reject);
78
- child.once("close", (code) => code === 0 ? done() : reject(/* @__PURE__ */ new Error(`swift ${args[0]} failed (${code}). See stim logs --source build.`)));
79
- });
80
- return stdout.trim();
81
- }
82
- async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, displayName, scratch, writer, note, record, buildMachine, resources, assetCatalog, progress = NO_BUILD_PROGRESS }) {
29
+ async function buildMacosBundle({ root, recipe, bundle, bundleId, displayName, scratch, writer, note, record, buildMachine, progress = NO_BUILD_PROGRESS }) {
83
30
  if (record) record.buildMachine = buildMachine;
84
31
  setRemoteLogSink((entry) => writer.write({
85
32
  ...entry,
86
33
  platform: "macos"
87
34
  }));
88
- validateInfoPlist(root, product, infoPlist);
89
- const repository = realpathSync(repoRoot(root) ?? root);
90
- const extras = resolveBundleExtras(root, repository, resources, assetCatalog);
91
35
  const write = (msg) => {
92
36
  writer.write({
93
37
  src: "build",
@@ -113,6 +57,7 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
113
57
  }
114
58
  }));
115
59
  if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, reason);
60
+ requireLocalBuild(buildMachine);
116
61
  offloadFallback = reason;
117
62
  if (record) record.offloadFallback = reason;
118
63
  writer.write({
@@ -141,10 +86,11 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
141
86
  let choice = null;
142
87
  try {
143
88
  try {
144
- const { mode, machines } = buildPlacementCandidates(buildMachine);
89
+ const { mode, machines, localEnabled } = buildPlacementCandidates(buildMachine);
145
90
  const here = machineCapacity();
146
91
  const placement = offloadPlacement({
147
92
  mode,
93
+ localEnabled,
148
94
  machines: machines.length,
149
95
  here,
150
96
  unsupported: null,
@@ -153,10 +99,7 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
153
99
  if (placement.offload) {
154
100
  const chosen = await chooseBuildMachine({
155
101
  projectRoot: root,
156
- target: {
157
- platform: "macos",
158
- local: macosToolchain()
159
- },
102
+ target: recipe.offload.target(),
160
103
  mode,
161
104
  here,
162
105
  machines,
@@ -179,14 +122,7 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
179
122
  write(`placement: ${choice.machine} (${placement.reason}${placementLoad(choice)})`);
180
123
  const outcome = await offloadBuild({
181
124
  choice,
182
- request: {
183
- platform: "macos",
184
- product,
185
- infoPlist: relative(root, resolve(root, infoPlist)),
186
- bundleId,
187
- resources: Object.fromEntries(Object.entries(extras.resources).map(([destination, source]) => [destination, relative(repository, source)])),
188
- assetCatalog: extras.assetCatalog ? relative(repository, extras.assetCatalog) : null
189
- },
125
+ request: recipe.offload.request(bundleId),
190
126
  stagingDir: join(staging, "offload"),
191
127
  onPhase: (phase, line) => note(remotePhaseText(phase, line, choice.machine)),
192
128
  onEnter: (phase) => {
@@ -211,30 +147,7 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
211
147
  progress.place(null);
212
148
  if (!outcome.ok) throw new Error(`${outcome.machine}: ${outcome.reason}`);
213
149
  progress.step("install");
214
- const executable = join(outcome.artifactPath, "Contents", "MacOS", product);
215
- const plist = JSON.parse(getExecutor().runFile("plutil", [
216
- "-convert",
217
- "json",
218
- "-o",
219
- "-",
220
- join(outcome.artifactPath, "Contents", "Info.plist")
221
- ]));
222
- if (plist.CFBundleIdentifier !== bundleId || plist.CFBundleExecutable !== product || !existsSync(executable)) throw new Error("The fetched macOS bundle does not match the requested identity and executable.");
223
- for (const destination of [...Object.keys(extras.resources), ...extras.assetCatalog ? ["Assets.car"] : []]) if (!existsSync(join(outcome.artifactPath, "Contents", "Resources", destination))) throw new Error(`The fetched macOS bundle lacks declared resource ${destination}.`);
224
- if (displayName !== void 0) {
225
- setBundleName(join(outcome.artifactPath, "Contents", "Info.plist"), displayName);
226
- getExecutor().runFile("codesign", [
227
- "--force",
228
- "--sign",
229
- "-",
230
- outcome.artifactPath
231
- ]);
232
- }
233
- getExecutor().runFile("codesign", [
234
- "--verify",
235
- "--strict",
236
- outcome.artifactPath
237
- ]);
150
+ recipe.validateFetched(outcome.artifactPath, bundleId, displayName);
238
151
  promote(outcome.artifactPath);
239
152
  if (record) {
240
153
  record.offloadedTo = outcome.machine;
@@ -264,36 +177,24 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
264
177
  let slot;
265
178
  try {
266
179
  slot = await acquireBuildSlot({
180
+ automatic: buildMachine === "auto",
267
181
  max: getConcurrencyLimits().maxBuilds,
268
182
  root,
269
183
  logFile: writer.file,
270
184
  out: note,
271
185
  waitingFor: (info) => progress.waitingFor(info, "build-slot")
272
186
  });
187
+ requireLocalBuild(buildMachine);
273
188
  if (record) record.builtOn = "here";
274
189
  progress.step("compile");
275
- await tool(root, [
276
- "build",
277
- "-c",
278
- "debug",
279
- "--product",
280
- product,
281
- "--scratch-path",
190
+ const bin = await recipe.compile({
282
191
  scratch,
283
- "--jobs",
284
- "2"
285
- ], writer, note);
286
- const bin = await tool(root, [
287
- "build",
288
- "-c",
289
- "debug",
290
- "--scratch-path",
291
- scratch,
292
- "--show-bin-path"
293
- ], writer, () => {}, true);
192
+ writer,
193
+ note
194
+ });
294
195
  progress.step("install");
295
- const staged = join(staging, `${product}.app`);
296
- stageBundle(root, product, infoPlist, bin, staged, bundleId, extras, displayName);
196
+ const staged = join(staging, `${recipe.product}.app`);
197
+ recipe.stage(bin, staged, bundleId, displayName);
297
198
  promote(staged);
298
199
  return {
299
200
  bundleId,
@@ -314,6 +215,55 @@ async function buildMacosBundle({ root, product, infoPlist, bundle, bundleId, di
314
215
  }
315
216
  }
316
217
  //#endregion
218
+ //#region src/macos/app-name.ts
219
+ const DOT = String.fromCodePoint(183);
220
+ const ELLIPSIS = String.fromCodePoint(8230);
221
+ const LABEL_MAX = 24;
222
+ const PRODUCT_MAX = 40;
223
+ function clip(text, max) {
224
+ const chars = [...text];
225
+ return chars.length <= max ? text : `${chars.slice(0, max - 1).join("")}${ELLIPSIS}`;
226
+ }
227
+ /** The visible app name for a run: `<product> <dot> <label>`, or just the product when the label is empty. */
228
+ function macosAppName(product, label) {
229
+ const name = clip(product.replace(/[\p{Cc}/:\\]+/gu, " ").trim(), PRODUCT_MAX) || "App";
230
+ const suffix = clip(sanitizeDeviceLabel(label), LABEL_MAX);
231
+ return suffix ? `${name} ${DOT} ${suffix}` : name;
232
+ }
233
+ function workspaceAppName(root, product) {
234
+ return macosAppName(product, ownedDeviceLabel(root));
235
+ }
236
+ //#endregion
237
+ //#region src/macos/plan.ts
238
+ function planMacos(root, buildMachineFlag) {
239
+ if (process.platform !== "darwin") throw new Error("stim macos requires a Mac with Swift installed.");
240
+ root = realpathSync(root);
241
+ if (!existsSync(join(root, "Package.swift"))) throw new Error("Run stim macos from the directory containing Package.swift.");
242
+ const { context, settings } = resolveProjectSettings(root);
243
+ const [shape] = settingShapeErrors(settings);
244
+ if (shape) throw new Error(`${shape} ${SETTING_SHAPE_REMEDY}`);
245
+ const selected = resolveBuildPlacement(buildMachineFlag);
246
+ if (selected.failure) throw Object.assign(new Error(selected.failure.message), selected.failure);
247
+ const macos = settings.macos;
248
+ if (!macos?.product || !macos.infoPlist) throw Object.assign(/* @__PURE__ */ new Error("Set macos.product and macos.infoPlist explicitly in .stim.json. See stim guide macos."), { code: "STIM_BAD_ARG" });
249
+ validateInfoPlist(root, macos.product, macos.infoPlist);
250
+ resolveBundleExtras(root, context.repoRoot ?? root, macos.resources, macos.assetCatalog);
251
+ return {
252
+ platform: "macos",
253
+ product: macos.product,
254
+ buildMachine: selected.selected,
255
+ fingerprint: null,
256
+ cacheKey: null,
257
+ cacheHit: false,
258
+ provider: null,
259
+ cacheSkipped: false,
260
+ prebuild: null,
261
+ outcome: null,
262
+ expectedMs: null,
263
+ basis: 0
264
+ };
265
+ }
266
+ //#endregion
317
267
  //#region src/commands/macos.ts
318
268
  /**
319
269
  * Builds the Debug app and launches it here, or with `remote` on that approved remote Mac. A named host never falls
@@ -325,19 +275,18 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
325
275
  if (backend === "auto") throw Object.assign(/* @__PURE__ */ new Error("stim macos --remote auto is not available yet: automatic placement has not shipped. Name a hosting Mac from remote.machines."), { code: "STIM_BAD_ARG" });
326
276
  if (process.platform !== "darwin") throw new Error("stim macos requires a Mac with Swift installed.");
327
277
  root = realpathSync(root);
328
- if (!existsSync(join(root, "Package.swift"))) throw new Error("Run stim macos from the directory containing Package.swift.");
329
- const settings = resolveSettings({
330
- projectPath: root,
331
- gitCommonDir: gitCommonDir(root),
332
- repoRoot: repoRoot(root)
278
+ const operation = projectRegistry.selectMacos(root);
279
+ if ("problem" in operation) throw Object.assign(new Error(operation.problem.message), {
280
+ code: "STIM_NO_PROJECT",
281
+ remedy: operation.problem.remedy
333
282
  });
283
+ const { settings } = resolveProjectSettings(root);
334
284
  const [shape] = settingShapeErrors(settings);
335
285
  if (shape) throw new Error(`${shape} ${SETTING_SHAPE_REMEDY}`);
336
286
  const selected = resolveBuildPlacement(buildMachineFlag);
337
287
  if (selected.failure) throw Object.assign(new Error(selected.failure.message), selected.failure);
338
288
  const buildMachine = selected.selected;
339
- const macos = settings.macos;
340
- if (!macos?.product || !macos.infoPlist) throw Object.assign(/* @__PURE__ */ new Error("Set macos.product and macos.infoPlist explicitly in .stim.json. See stim guide macos."), { code: "STIM_BAD_ARG" });
289
+ const macos = (await operation.load()).prepare(settings);
341
290
  ensureWorkspaceStorage(root);
342
291
  return withNativeBuildRun(root, {
343
292
  command: "macos",
@@ -353,7 +302,7 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
353
302
  return withWorkspaceProcessLock(workspaceDir(root), "macos-launch", async () => {
354
303
  const previous = requiredMacosRecord(root);
355
304
  if (previous?.host && previous.host.machine !== remote) throw new Error(`This workspace's macOS app runs on ${previous.host.machine}. Run stim stop first, then stim macos${remote ? ` --remote ${remote}` : ""}.`);
356
- if (remote && !validHostedAppArguments(macos.arguments ?? [])) throw new Error("macos.arguments is too large for a hosted app: at most 32 arguments of 1024 characters (8192 in total), without NUL or line breaks.");
305
+ if (remote && !validHostedAppArguments(macos.arguments)) throw new Error("macos.arguments is too large for a hosted app: at most 32 arguments of 1024 characters (8192 in total), without NUL or line breaks.");
357
306
  if (remote) (await connectHost(remote)).connection.close();
358
307
  if (!previous?.host) await stopMacosAppHeld(root);
359
308
  upsertProject(root, {});
@@ -365,7 +314,7 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
365
314
  bundleId: "",
366
315
  executable: join(bundle, "Contents", "MacOS", macos.product),
367
316
  launchId: randomUUID(),
368
- arguments: macos.arguments ?? [],
317
+ arguments: macos.arguments,
369
318
  supervisor: macosProcess(process.pid),
370
319
  build: {
371
320
  state: "running",
@@ -377,7 +326,7 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
377
326
  hostLaunched: previous.hostLaunched ?? false
378
327
  } : {}
379
328
  };
380
- const handoff = await buildBundle(root, macos.infoPlist, record, remote !== void 0, note, macos, progress);
329
+ const handoff = await buildBundle(root, macos, record, remote !== void 0, note, progress);
381
330
  progress.step("launch");
382
331
  const launched = () => {
383
332
  try {
@@ -403,7 +352,7 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
403
352
  bundle: record.bundle,
404
353
  bundleId: record.bundleId,
405
354
  handoff,
406
- arguments: macos.arguments ?? [],
355
+ arguments: macos.arguments,
407
356
  recorded: previous?.host,
408
357
  reserved: (reserved) => {
409
358
  placement = reserved;
@@ -443,19 +392,18 @@ async function runMacos(root, note = console.error, remote, buildMachineFlag) {
443
392
  }).finally(() => progress.clear());
444
393
  }, { write: note });
445
394
  }
446
- async function buildBundle(root, infoPlist, record, hosted, note, extras, progress = NO_BUILD_PROGRESS) {
395
+ async function buildBundle(root, recipe, record, hosted, note, progress = NO_BUILD_PROGRESS) {
447
396
  const started = Date.parse(record.build.startedAt);
448
397
  const scratch = join(macosDir(root), "build");
449
398
  writeWorkspaceState(root, { macos: record });
450
399
  const writer = tapBuildLog(createNdjsonWriter(macosLogFile(root), { maxBytes: LOG_ROTATE_BYTES }), progress);
451
400
  try {
452
- const { bundleId: base } = validateInfoPlist(root, record.product, infoPlist);
401
+ const base = recipe.bundleId;
453
402
  const bundleId = hosted ? base : `${base}.stim.${createHash("sha256").update(root).digest("hex").slice(0, 12)}`;
454
403
  const displayName = workspaceAppName(root, record.product);
455
404
  const built = await buildMacosBundle({
456
405
  root,
457
- product: record.product,
458
- infoPlist,
406
+ recipe,
459
407
  bundle: record.bundle,
460
408
  bundleId,
461
409
  displayName,
@@ -464,9 +412,7 @@ async function buildBundle(root, infoPlist, record, hosted, note, extras, progre
464
412
  note,
465
413
  progress,
466
414
  record: record.build,
467
- buildMachine: record.build.buildMachine,
468
- resources: extras.resources,
469
- assetCatalog: extras.assetCatalog
415
+ buildMachine: record.build.buildMachine
470
416
  });
471
417
  record.bundleId = built.bundleId;
472
418
  record.displayName = displayName;
@@ -528,6 +474,7 @@ function recordMacosBuild(root, build, compileSteps) {
528
474
  });
529
475
  }
530
476
  async function launchHere(root, record) {
477
+ await stopBundleInstances(root);
531
478
  const fd = openSync(join(workspaceLogsDir$1(root), "macos-supervisor.log"), "a");
532
479
  let child;
533
480
  try {
@@ -580,8 +527,31 @@ function launchPayload(root, record) {
580
527
  };
581
528
  }
582
529
  function macosCommand(program) {
583
- program.command("macos").description("Build and launch an owned Swift Package macOS Debug app.").option("--remote-build <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "print one launch payload; build output goes to stderr").option("--remote <machine>", "run it on this approved remote Mac from remote.machines").action(async (options) => {
584
- const root = findProjectRoot$1(process.cwd());
530
+ program.command("macos").description("Build and launch an owned Swift Package macOS Debug app.").option("--remote-build <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "print one launch or plan payload; build output goes to stderr").option("--plan", "validate the next SwiftPM Debug build without building or launching").option("--remote <machine>", "run it on this approved remote Mac from remote.machines").action(async (options) => {
531
+ const root = findProjectRoot(process.cwd());
532
+ if (options.plan) {
533
+ try {
534
+ if (!root) throw new Error("Run stim macos from the Swift Package directory.");
535
+ if (options.remote !== void 0) throw Object.assign(/* @__PURE__ */ new Error("--remote selects a launch host and does not apply to --plan."), { code: "STIM_BAD_ARG" });
536
+ const plan = planMacos(root, options.remoteBuild);
537
+ if (options.json) console.log(JSON.stringify(plan));
538
+ else {
539
+ console.log(phaseLine("plan", `macos ${plan.product}: SwiftPM Debug build, then stage and launch`));
540
+ console.log(phaseLine("build", `selection: ${plan.buildMachine}; worker availability is not checked`));
541
+ console.log(phaseLine("expect", "unknown: SwiftPM determines incremental work when the build runs"));
542
+ }
543
+ } catch (error) {
544
+ const failure = {
545
+ code: error.code ?? "STIM_BAD_ARG",
546
+ message: error instanceof Error ? error.message : String(error),
547
+ remedy: error.remedy ?? "Check the macOS project settings in stim guide macos."
548
+ };
549
+ console.error(failure.message);
550
+ if (options.json) console.log(JSON.stringify(failure));
551
+ process.exitCode = 1;
552
+ }
553
+ return;
554
+ }
585
555
  if (!root) throw new Error("Run stim macos from the Swift Package directory.");
586
556
  const record = await runMacos(root, console.error, options.remote, options.remoteBuild).catch((error) => {
587
557
  const remedy = error.remedy;
@@ -595,4 +565,4 @@ function macosCommand(program) {
595
565
  });
596
566
  }
597
567
  //#endregion
598
- export { runMacos as n, macosCommand as t };
568
+ export { runMacos as n, buildMacosBundle as r, macosCommand as t };
@@ -1,2 +1,2 @@
1
- import { n as runMacosSupervisor, t as logLines } from "./run-vhtDgpHO.mjs";
1
+ import { n as runMacosSupervisor, t as logLines } from "./run-qvff78hv.mjs";
2
2
  export { logLines, runMacosSupervisor };
@@ -1,13 +1,13 @@
1
- import { M as isOnMountedVolume, N as listMountedVolumes, _ as loadConfig$1, j as formatBytes } from "./config-CgYMahz7.mjs";
2
- import { a as unregister, n as readManifest } from "./cache-manifest-BI7ozfmH.mjs";
3
- import { Qt as pruneCache, Zt as discoverCaches, l as resolveBudget, pt as planCacheEmptying, r as cacheLabel, st as emptyCaches } from "./budget-DIhL2BKx.mjs";
4
- import { F as takeGcResults, I as canonicalPath, a as collectWorkspaceOutputs, i as collectOrphanedWorkspaces, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs } from "./workspaces-xXItD8Dj.mjs";
5
- import { D as projectMaintenancePinned } from "./settings-CQyMElEP.mjs";
6
- import { r as createNdjsonWriter } from "./ndjson-LGZAMsqa.mjs";
7
- import { t as relaunchWithLogFile } from "./detached-entry-BLfcgc4O.mjs";
1
+ import { M as isOnMountedVolume, N as listMountedVolumes, _ as loadConfig$1, j as formatBytes } from "./config-D0LhTY3S.mjs";
2
+ import { a as unregister, n as readManifest } from "./cache-manifest-qA3dT2x2.mjs";
3
+ import { T as canonicalPath, a as collectWorkspaceOutputs, i as collectOrphanedWorkspaces, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs, w as takeGcResults } from "./workspaces-D2xSHBDY.mjs";
4
+ import { N as emptyCaches, at as discoverCaches, l as resolveBudget, ot as pruneCache, r as cacheLabel, z as planCacheEmptying } from "./budget-BONq9vXY.mjs";
5
+ import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
6
+ import { t as relaunchWithLogFile } from "./detached-entry-BXq4fIl-.mjs";
7
+ import { F as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-CXLIUxXJ.mjs";
8
8
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
9
9
  import { r as due, t as capChildLog } from "./attempt-DW-mQqM7.mjs";
10
- import { a as recentUse, d as measureDisk, f as measurePressure, i as cacheEntryProtection, m as sizeScanDeferred, p as measureSizes, r as triggeringRoot, s as removeWorktrees, t as plannedMaintenance, u as cacheBlocked } from "./preview-D5V07Nrl.mjs";
10
+ import { a as maintenancePinned, c as removeWorktrees, d as cacheBlocked, f as measureDisk, h as sizeScanDeferred, i as cacheEntryProtection, m as measureSizes, o as recentUse, p as measurePressure, r as triggeringRoot, t as plannedMaintenance } from "./preview-BaBJ72Al.mjs";
11
11
  import { appendFileSync, existsSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
12
12
  import { basename, join, resolve, sep } from "node:path";
13
13
  import { MAINTENANCE_LOG_NAME, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState, sharedCompilationCache, workspaceLogsDir } from "@stim-cli/core/state";
@@ -123,7 +123,7 @@ async function clearOutputs(action, context) {
123
123
  const root = action.workspace;
124
124
  if (!root) return kept("the action names no workspace");
125
125
  if (root === context.protectedRoot) return kept("the command that started this pass runs in it");
126
- if (projectMaintenancePinned(root)) return kept("pinned by maintenance.keep");
126
+ if (maintenancePinned(root)) return kept("pinned by maintenance.keep");
127
127
  const recent = recentUse(root, context.settings);
128
128
  if (recent) return kept(recent);
129
129
  const olderThan = action.olderThanDays ?? null;
@@ -150,7 +150,7 @@ async function removeWorktree(action, context) {
150
150
  if (!sweep || !worktree) return kept("it is not in this pass's worktree check");
151
151
  const path = canonicalPath(worktree.path);
152
152
  if (context.protectedRoot === path || context.protectedRoot.startsWith(`${path}${sep}`)) return kept("the command that started this pass runs inside it");
153
- if (worktree.keys.some(projectMaintenancePinned)) return kept("pinned by maintenance.keep");
153
+ if (worktree.keys.some(maintenancePinned)) return kept("pinned by maintenance.keep");
154
154
  const { results } = await quietly(() => removeWorktrees({
155
155
  ...sweep,
156
156
  worktrees: [worktree]
@@ -343,6 +343,8 @@ async function runMaintenance(trigger) {
343
343
  if (check === "worktree" || check === "sweep") continue;
344
344
  if (check === "pressure") {
345
345
  state.pressure = measurePressure(settings, state.pressure, state.lastAt[check]);
346
+ const culprits = settings.memoryPressureLevel === "off" ? null : memoryCulpritsUnder(state.pressure.memory.level);
347
+ if (culprits) state.pressure.memory.culprits = culprits;
346
348
  const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
347
349
  for (const disk of state.pressure.disk) record("maintenance_check", "debug", `Disk free on ${disk.volume}: ${(disk.freeMb / 1024).toFixed(1)}G`, { check: {
348
350
  kind: "disk-free",
@@ -356,6 +358,7 @@ async function runMaintenance(trigger) {
356
358
  threshold: state.pressure.memory.availableBytes === null ? settings.memoryPressureLevel : settings.minAvailableMemoryGb ?? "10% of RAM",
357
359
  unit: state.pressure.memory.availableBytes === null ? "level" : "GiB"
358
360
  } });
361
+ for (const culprit of state.pressure.memory.culprits ?? []) record("maintenance_check", "info", memoryCulpritAdvice([culprit]), { culprit });
359
362
  } else {
360
363
  measuredSizes = true;
361
364
  state.sizes = measureSizes(state.lastAt[check], (target, workspace) => {