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
@@ -0,0 +1,30 @@
1
+ //#region src/engine/artifact-lifecycle.ts
2
+ async function runArtifactLifecycle(phases) {
3
+ try {
4
+ const resolved = await phases.resolve();
5
+ if (resolved.kind === "ready") return resolved.artifact;
6
+ const cached = resolved.kind === "cached" ? resolved.artifact : await phases.claim?.() ?? null;
7
+ if (cached !== null) {
8
+ const reused = await phases.reuse(cached);
9
+ if (reused !== null) return reused;
10
+ }
11
+ const { build } = phases;
12
+ const placement = build.placement?.select() ?? null;
13
+ if (placement === null) await build.admit();
14
+ const preparation = await build.prepare();
15
+ const late = await build.revalidate(preparation);
16
+ if (late !== null) return late.ready;
17
+ if (build.placement && placement !== null) {
18
+ const offloaded = await build.placement.acquire(placement, preparation);
19
+ if (offloaded !== null) return offloaded.ready;
20
+ await build.admit();
21
+ }
22
+ const artifact = await build.compile(placement, preparation);
23
+ if (await build.validate(preparation) === "cacheable") await build.store(artifact);
24
+ return build.finish ? await build.finish(artifact) : artifact;
25
+ } finally {
26
+ phases.release();
27
+ }
28
+ }
29
+ //#endregion
30
+ export { runArtifactLifecycle as t };
@@ -1,27 +1,36 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
1
+ import { t as getExecutor } from "./exec-B81Qodjn.mjs";
2
2
  import { t as spawnEntry } from "./spawn-entry-Dcb7sDUz.mjs";
3
- import { f as refuseNoProject, l as phaseLine } from "./command-output-CBtzyIgF.mjs";
4
- import { E as upsertProject, p as getProject } from "./config-CgYMahz7.mjs";
5
- import { s as gitCommonDir, y as repoRoot } from "./worktree-CsKYexJM.mjs";
6
- import { i as detectIsExpo, l as isPackageResolvable, o as findCommandWorkspace } from "./project-C3ChRLZy.mjs";
7
- import { l as resolveProjectMetro } from "./metro-Dh8T4Ytd.mjs";
8
- import { i as recordWorkspaceUse, r as readWorkspaceState, v as workspaceDir, x as workspaceLogsDir } from "./workspace-state-C59dqG-Z.mjs";
9
- import { d as webLogFile, o as readWebRecord, p as webSupervisorLogFile, r as cdpEndpoint, s as updateWebRecord } from "./state-BG-aAk4k.mjs";
10
- import { T as teardownBrowserHeld, m as resolveSupervisorTarget } from "./workspaces-xXItD8Dj.mjs";
11
- import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Behws_fi.mjs";
12
- import { F as resolveSettings, W as webSettings, i as SETTING_SHAPE_REMEDY, x as metroPortSetting, z as settingShapeErrors } from "./settings-CQyMElEP.mjs";
13
- import { a as withWorkspaceProcessLock, i as reserveBrowserPort, n as getNamedPort } from "./named-ports-BFIz1Shz.mjs";
14
- import { o as readNdjsonGenerations } from "./ndjson-LGZAMsqa.mjs";
15
- import { c as readMetroRecords } from "./launch-verify-hskNcWkZ.mjs";
16
- import { o as resolveWorkspaceMetroPort } from "./start-D-IeOyoK.mjs";
17
- import { n as windowsLauncherArgs } from "./detached-entry-BLfcgc4O.mjs";
18
- import { a as sleep, n as ensureWorkspaceStorageSafely } from "./native-runtime-D_603JiC.mjs";
19
- import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-DJnmnS5q.mjs";
3
+ import { p as getProject } from "./config-D0LhTY3S.mjs";
4
+ import { a as SETTING_SHAPE_REMEDY, j as metroPortSetting, rt as webSettings } from "./settings-Bbztm4oV.mjs";
5
+ import { r as readWorkspaceState, w as workspaceLogsDir, x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
6
+ import { l as phaseLine } from "./command-output-BjPN99ZB.mjs";
7
+ import { _ as detectIsExpo, y as isPackageResolvable } from "./project-B8_duAzW.mjs";
8
+ import { u as resolveProjectMetro } from "./metro-D_j9sN-B.mjs";
9
+ import { P as resolveSupervisorTarget, _ as teardownBrowserHeld } from "./workspaces-D2xSHBDY.mjs";
10
+ import { a as withWorkspaceProcessLock, i as reserveBrowserPort, n as getNamedPort } from "./named-ports-C2lvoPsb.mjs";
11
+ import { s as readNdjsonGenerations } from "./ndjson-GOnbyvso.mjs";
12
+ import { o as resolveWorkspaceMetroPort } from "./start-CdvcTaXr.mjs";
13
+ import { n as windowsLauncherArgs } from "./detached-entry-BXq4fIl-.mjs";
14
+ import { d as webLogFile, o as readWebRecord, p as webSupervisorLogFile, s as updateWebRecord } from "./state-DI84A-uu.mjs";
15
+ import { c as readMetroRecords } from "./launch-verify-BzRdbuO1.mjs";
16
+ import { a as sleep } from "./native-runtime-BRmWL7ru.mjs";
20
17
  import { n as sendToOwnedPage, t as liveWebRecord } from "./page-Bv9s2KwY.mjs";
18
+ import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-Dp2lMLBe.mjs";
21
19
  import { mkdirSync, openSync } from "node:fs";
22
- import chalk from "chalk";
23
20
  import { randomUUID } from "node:crypto";
21
+ import chalk from "chalk";
24
22
  //#region src/web/launch.ts
23
+ const PORT_PLACEHOLDER = /\{port:([^}]*)\}/g;
24
+ /** Replaces each `{port:<label>}` in a `web.url` template; `metro` is the workspace's Metro port. */
25
+ async function resolveWebUrl(template, { metroPort, namedPort }) {
26
+ let url = template;
27
+ for (const [placeholder, label] of template.matchAll(PORT_PLACEHOLDER)) {
28
+ const port = label === "metro" ? metroPort : await namedPort(label);
29
+ if (port === null) throw new Error(`${placeholder} needs a Metro port, and this workspace has none reserved.`);
30
+ url = url.replace(placeholder, String(port));
31
+ }
32
+ return url;
33
+ }
25
34
  const VERIFY_WAIT_MS = 2e4;
26
35
  const LOADING_WAIT_MS = 6e4;
27
36
  const METRO_WEB_BUNDLE = /\bWeb\s+Bundl(?:ing|ed)\b/i;
@@ -128,12 +137,10 @@ function webLaunchRemedy(verdict, { url, template, usesMetro, serve }) {
128
137
  return usesMetro ? METRO_BUILD(url) : nothingServed;
129
138
  }
130
139
  //#endregion
131
- //#region src/commands/web.ts
132
- const PORT_PLACEHOLDER = /\{port:([^}]*)\}/g;
140
+ //#region src/web/runtime.ts
133
141
  const REGISTER_WAIT_MS = 3e4;
134
- const POLL_MS = 250;
135
- const printNote = (line) => console.error(line);
136
- function failure(code, message, remedy) {
142
+ const POLL_MS$1 = 250;
143
+ function failure$1(code, message, remedy) {
137
144
  return {
138
145
  ok: false,
139
146
  error: {
@@ -143,16 +150,6 @@ function failure(code, message, remedy) {
143
150
  }
144
151
  };
145
152
  }
146
- /** Replaces each `{port:<label>}` in a `web.url` template; `metro` is the workspace's Metro port. */
147
- async function resolveWebUrl(template, { metroPort, namedPort }) {
148
- let url = template;
149
- for (const [placeholder, label] of template.matchAll(PORT_PLACEHOLDER)) {
150
- const port = label === "metro" ? metroPort : await namedPort(label);
151
- if (port === null) throw new Error(`${placeholder} needs a Metro port, and this workspace has none reserved.`);
152
- url = url.replace(placeholder, String(port));
153
- }
154
- return url;
155
- }
156
153
  function sameLaunch(record, config) {
157
154
  return record.chrome === config.chrome && record.headless === config.headless && record.viewport === config.viewport && record.ignoreCertificateErrors === config.ignoreCertificateErrors;
158
155
  }
@@ -216,77 +213,12 @@ async function waitForSupervisor(root, child, launchId) {
216
213
  const record = readWebRecord(root);
217
214
  if (record?.launchId === launchId && record.targetId) return record;
218
215
  if (exited) return null;
219
- await sleep(POLL_MS);
216
+ await sleep(POLL_MS$1);
220
217
  }
221
218
  return null;
222
219
  }
223
- async function verifyLaunch(root, since, expectBundle) {
224
- const startedAt = Date.now();
225
- for (;;) {
226
- const verdict = webLaunchVerdict({
227
- records: readNdjsonGenerations(webLogFile(root)),
228
- metroRecords: expectBundle ? readMetroRecords(workspaceLogsDir(root)) : [],
229
- since,
230
- expectBundle,
231
- elapsedMs: Date.now() - startedAt
232
- });
233
- if (verdict) return verdict;
234
- await sleep(POLL_MS);
235
- }
236
- }
237
- async function runWeb({ root, headed, note }) {
238
- const startedAt = Date.now();
239
- await ensureWorkspaceStorageSafely(root, { note });
240
- if (!getProject(root)) upsertProject(root, {});
241
- const settings = resolveSettings({
242
- projectPath: root,
243
- gitCommonDir: gitCommonDir(root),
244
- repoRoot: repoRoot(root)
245
- });
246
- const [shapeError] = settingShapeErrors(settings);
247
- if (shapeError) return failure("STIM_BAD_ARG", shapeError, SETTING_SHAPE_REMEDY);
248
- const web = webSettings(settings);
249
- const usesMetro = web.url === null || web.url.includes("{port:metro}");
250
- const pin = usesMetro ? metroPortSetting(root) : null;
251
- if (pin?.error) return failure("STIM_BAD_ARG", pin.error, SETTING_SHAPE_REMEDY);
252
- const chrome = findChrome();
253
- if (!chrome) return failure("STIM_WEB_NO_CHROME", "Google Chrome or Chromium is not installed.", CHROME_INSTALL_REMEDY);
254
- if (web.url === null && !detectIsExpo(root)) return failure("STIM_WEB_NO_URL", "This is not an Expo app, so Stim does not know which page to open.", "Start your web dev server on a named port, then set the page: `stim settings set web.url 'http://localhost:{port:web}/' --scope workspace`. See `stim guide web`.");
255
- if (web.url === null && !isPackageResolvable(root, "react-native-web")) return failure("STIM_WEB_DEPS_MISSING", "This Expo app cannot render on the web: react-native-web is not installed.", `Run \`${EXPO_WEB_DEPENDENCIES}\` and \`stim start\`, then run \`stim web\` again.`);
256
- let metroPort = getProject(root)?.metroPort ?? null;
257
- if (usesMetro && (pin?.port !== null || metroPort === null)) {
258
- const result = await resolveWorkspaceMetroPort(root, note, "web");
259
- if (typeof result !== "number") return failure(result.code, result.message, result.remedy);
260
- metroPort = result;
261
- }
262
- const metro = usesMetro && metroPort !== null ? await resolveProjectMetro(metroPort, root) : null;
263
- const supervisor = resolveSupervisorTarget({
264
- state: readWorkspaceState(root)?.supervisor,
265
- record: getProject(root)?.supervisor,
266
- reservedPort: metroPort
267
- });
268
- const { serve, foreign } = webServePlan({
269
- usesMetro,
270
- metro,
271
- supervisorHeld: supervisor.status !== "none" && supervisor.status !== "stale",
272
- missingWebPackages: usesMetro && detectIsExpo(root) ? EXPO_WEB_PACKAGES.filter((name) => !isPackageResolvable(root, name)) : []
273
- });
274
- let url;
275
- try {
276
- url = await resolveWebUrl(web.url ?? "http://localhost:{port:metro}/", {
277
- metroPort,
278
- namedPort: (label) => getNamedPort(root, label)
279
- });
280
- } catch (error) {
281
- return failure("STIM_BAD_ARG", `web.url: ${error.message}`, SETTING_SHAPE_REMEDY);
282
- }
283
- const config = {
284
- chrome,
285
- headless: !headed,
286
- viewport: web.viewport,
287
- ignoreCertificateErrors: web.ignoreCertificateErrors
288
- };
289
- const launch = await withWorkspaceProcessLock(workspaceDir(root), "web", async () => {
220
+ async function launchOwnedBrowser({ url, config }, { root, note }) {
221
+ return withWorkspaceProcessLock(workspaceDir(root), "web", async () => {
290
222
  const live = liveWebRecord(readWebRecord(root));
291
223
  if (live && sameLaunch(live, config)) {
292
224
  const since = Date.now();
@@ -308,7 +240,7 @@ async function runWeb({ root, headed, note }) {
308
240
  }
309
241
  }
310
242
  const stopped = await teardownBrowserHeld(root);
311
- if (stopped.status === "failed" || stopped.status === "skipped") return failure("STIM_WEB_BROWSER_HELD", `The previous owned Chrome could not be stopped: ${stopped.reason ?? "unknown reason"}.`, "Run `stim status` and `stim guide errors teardown`.");
243
+ if (stopped.status === "failed" || stopped.status === "skipped") return failure$1("STIM_WEB_BROWSER_HELD", `The previous owned Chrome could not be stopped: ${stopped.reason ?? "unknown reason"}.`, "Run `stim status` and `stim guide errors teardown`.");
312
244
  const port = await reserveBrowserPort(root);
313
245
  const since = Date.now();
314
246
  note(chalk.dim(phaseLine("device", `starting ${config.headless ? "headless " : ""}Chrome on DevTools port ${port}`)));
@@ -319,7 +251,7 @@ async function runWeb({ root, headed, note }) {
319
251
  config,
320
252
  launchId
321
253
  }), launchId);
322
- if (!record) return failure("STIM_WEB_LAUNCH_FAILED", "The owned Chrome did not start.", `Read ${webSupervisorLogFile(root)} and \`stim logs --errors\`, then run \`stim web\` again.`);
254
+ if (!record) return failure$1("STIM_WEB_LAUNCH_FAILED", "The owned Chrome did not start.", `Read ${webSupervisorLogFile(root)} and \`stim logs --errors\`, then run \`stim web\` again.`);
323
255
  return {
324
256
  ok: true,
325
257
  record,
@@ -330,80 +262,110 @@ async function runWeb({ root, headed, note }) {
330
262
  external: true,
331
263
  ownerPurpose: "stim web"
332
264
  });
333
- if (!launch.ok) return launch;
334
- const measured = await verifyLaunch(root, launch.since, usesMetro);
335
- const live = liveWebRecord(readWebRecord(root));
336
- const record = live ?? launch.record;
337
- const verdict = foreign ? {
338
- launched: "unverified",
339
- kind: "no-response",
340
- reason: foreign.reason
341
- } : measured;
342
- const remedy = foreign ? foreign.remedy : webLaunchRemedy(verdict, {
343
- url,
344
- template: web.url,
345
- usesMetro,
346
- serve
347
- });
265
+ }
266
+ //#endregion
267
+ //#region src/integrations/browser-web.ts
268
+ const POLL_MS = 250;
269
+ function failure(code, message, remedy) {
348
270
  return {
349
- ok: true,
350
- remedy: verdict.reason && remedy ? `${verdict.reason}. ${remedy}` : remedy,
351
- facts: {
352
- platform: "web",
353
- browser: "chrome",
354
- version: record.version ?? null,
355
- running: live !== null,
356
- pid: live?.chromeProcess?.pid ?? null,
357
- supervisorPid: live?.pid ?? null,
358
- url,
359
- headless: record.headless,
360
- viewport: record.viewport,
361
- profile: record.profile,
362
- cdpEndpoint: live ? cdpEndpoint(live.cdpPort) : null,
363
- targetId: live?.targetId ?? null,
364
- reused: launch.reused,
365
- launched: verdict.launched,
366
- metroPort: usesMetro ? metroPort : null,
367
- logs: { dir: workspaceLogsDir(root) },
368
- durationMs: Date.now() - startedAt
271
+ ok: false,
272
+ error: {
273
+ code,
274
+ message,
275
+ remedy
369
276
  }
370
277
  };
371
278
  }
372
- function webCommand(program) {
373
- program.command("web").description("Open this workspace's page in a Stim-owned headless Chrome and capture its console, errors and failed requests in stim logs").option("--headed", "Show the Chrome window instead of running headless").option("--json", "Print the result as one JSON object; progress goes to stderr").action(async (opts) => {
374
- const json = Boolean(opts.json);
375
- const root = findCommandWorkspace(process.cwd());
376
- if (!root) {
377
- refuseNoProject({ json });
378
- return;
379
- }
380
- recordWorkspaceUse(root);
381
- const result = await runWeb({
382
- root,
383
- headed: Boolean(opts.headed),
384
- note: printNote
385
- });
386
- if (!result.ok) {
387
- printNote(chalk.red(phaseLine("error", `${result.error.code}: ${result.error.message}`)));
388
- if (result.error.remedy) printNote(phaseLine("remedy", result.error.remedy));
389
- if (json) console.log(JSON.stringify(result.error));
390
- process.exitCode = 1;
391
- return;
392
- }
393
- const { facts, remedy } = result;
394
- if (remedy) printNote(chalk.yellow(phaseLine("launch", remedy)));
395
- const links = workspaceLinks(root, { platform: "web" });
396
- if (json) {
397
- console.log(JSON.stringify(links ? {
398
- ...facts,
399
- links
400
- } : facts));
401
- return;
279
+ function browserWebProject(root) {
280
+ return { runtime: ({ settings, headed, note }) => ({
281
+ async prepare() {
282
+ const web = webSettings(settings);
283
+ const usesMetro = web.url === null || web.url.includes("{port:metro}");
284
+ const pin = usesMetro ? metroPortSetting(settings) : null;
285
+ if (pin?.error) return failure("STIM_BAD_ARG", pin.error, SETTING_SHAPE_REMEDY);
286
+ const chrome = findChrome();
287
+ if (!chrome) return failure("STIM_WEB_NO_CHROME", "Google Chrome or Chromium is not installed.", CHROME_INSTALL_REMEDY);
288
+ if (web.url === null && !detectIsExpo(root)) return failure("STIM_WEB_NO_URL", "This is not an Expo app, so Stim does not know which page to open.", "Start your web dev server on a named port, then set the page: `stim settings set web.url 'http://localhost:{port:web}/' --scope workspace`. See `stim guide web`.");
289
+ if (web.url === null && !isPackageResolvable(root, "react-native-web")) return failure("STIM_WEB_DEPS_MISSING", "This Expo app cannot render on the web: react-native-web is not installed.", `Run \`${EXPO_WEB_DEPENDENCIES}\` and \`stim start\`, then run \`stim web\` again.`);
290
+ let metroPort = getProject(root)?.metroPort ?? null;
291
+ if (usesMetro && (pin?.port !== null || metroPort === null)) {
292
+ const result = await resolveWorkspaceMetroPort(root, settings, note, "web");
293
+ if (typeof result !== "number") return failure(result.code, result.message, result.remedy);
294
+ metroPort = result;
295
+ }
296
+ const metro = usesMetro && metroPort !== null ? await resolveProjectMetro(metroPort, root) : null;
297
+ const supervisor = resolveSupervisorTarget({
298
+ state: readWorkspaceState(root)?.supervisor,
299
+ record: getProject(root)?.supervisor,
300
+ reservedPort: metroPort
301
+ });
302
+ const { serve, foreign } = webServePlan({
303
+ usesMetro,
304
+ metro,
305
+ supervisorHeld: supervisor.status !== "none" && supervisor.status !== "stale",
306
+ missingWebPackages: usesMetro && detectIsExpo(root) ? EXPO_WEB_PACKAGES.filter((name) => !isPackageResolvable(root, name)) : []
307
+ });
308
+ let url;
309
+ try {
310
+ url = await resolveWebUrl(web.url ?? "http://localhost:{port:metro}/", {
311
+ metroPort,
312
+ namedPort: (label) => getNamedPort(root, label)
313
+ });
314
+ } catch (error) {
315
+ return failure("STIM_BAD_ARG", `web.url: ${error.message}`, SETTING_SHAPE_REMEDY);
316
+ }
317
+ return {
318
+ ok: true,
319
+ prepared: {
320
+ url,
321
+ config: {
322
+ chrome,
323
+ headless: !headed,
324
+ viewport: web.viewport,
325
+ ignoreCertificateErrors: web.ignoreCertificateErrors
326
+ },
327
+ metroPort: usesMetro ? metroPort : null,
328
+ verification: {
329
+ template: web.url,
330
+ expectBundle: usesMetro,
331
+ serve,
332
+ foreign
333
+ }
334
+ }
335
+ };
336
+ },
337
+ launch: launchOwnedBrowser,
338
+ async verify({ url, verification: { template, expectBundle, serve, foreign } }, { since }) {
339
+ const startedAt = Date.now();
340
+ let measured;
341
+ for (;;) {
342
+ measured = webLaunchVerdict({
343
+ records: readNdjsonGenerations(webLogFile(root)),
344
+ metroRecords: expectBundle ? readMetroRecords(workspaceLogsDir(root)) : [],
345
+ since,
346
+ expectBundle,
347
+ elapsedMs: Date.now() - startedAt
348
+ });
349
+ if (measured) break;
350
+ await sleep(POLL_MS);
351
+ }
352
+ const verdict = foreign ? {
353
+ launched: "unverified",
354
+ kind: "no-response",
355
+ reason: foreign.reason
356
+ } : measured;
357
+ const remedy = foreign ? foreign.remedy : webLaunchRemedy(verdict, {
358
+ url,
359
+ template,
360
+ usesMetro: expectBundle,
361
+ serve
362
+ });
363
+ return {
364
+ verdict,
365
+ remedy: verdict.reason && remedy ? `${verdict.reason}. ${remedy}` : remedy
366
+ };
402
367
  }
403
- const launched = facts.launched === true ? chalk.green("loaded") : chalk.yellow(facts.launched === "bundling" ? "bundling" : "unverified");
404
- console.log(facts.running ? `${facts.url} ${launched} in ${facts.version ?? "Chrome"} (pid ${facts.pid}, ${facts.headless ? "headless" : "headed"}, ${facts.viewport}). DevTools: ${facts.cdpEndpoint}. Logs: stim logs --errors.` : `${facts.url} ${launched}, and the owned Chrome is no longer running. Run stim logs --errors, then stim web again.`);
405
- if (links) console.error(chalk.dim(workspaceLinkLine(links)));
406
- });
368
+ }) };
407
369
  }
408
370
  //#endregion
409
- export { runWeb as n, webCommand as r, resolveWebUrl as t };
371
+ export { browserWebProject };