stim 1.11.0 → 1.13.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 (82) hide show
  1. package/README.md +3 -1
  2. package/dist/{activity-BtG4Va9l.mjs → activity-DfVKZTEB.mjs} +44 -26
  3. package/dist/{android-BA2i_KAV.mjs → android-BHfAu2mf.mjs} +1 -1
  4. package/dist/{android-C1q4l523.mjs → android-CD8pr8Q2.mjs} +112 -54
  5. package/dist/{android-cas-DfJkwCXW.mjs → android-cas-B9Kv9aIy.mjs} +12 -10
  6. package/dist/{android-C4zG2Tuc.mjs → android-qx_31wJo.mjs} +414 -118
  7. package/dist/{app-install-DHut6JnV.mjs → app-install-CDFY2nUL.mjs} +1 -1
  8. package/dist/budget-E5o91NR1.mjs +1739 -0
  9. package/dist/{build-plan-CeAYgKAx.mjs → build-plan-BTa93o_r.mjs} +125 -107
  10. package/dist/{build-progress-CDwogz6R.mjs → build-progress-l7d-X-ZP.mjs} +76 -8
  11. package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
  12. package/dist/cache-manifest.mjs +1 -1
  13. package/dist/cdp-Dq_ypAlJ.mjs +115 -0
  14. package/dist/chrome-B5hWgQJS.mjs +61 -0
  15. package/dist/cli.mjs +17 -16
  16. package/dist/collector-run.mjs +15 -9
  17. package/dist/{command-output-D5z2_bcF.mjs → command-output-BIL7rlX7.mjs} +1 -1
  18. package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
  19. package/dist/created-devices-Cd558h31.mjs +37 -0
  20. package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
  21. package/dist/{deps-OF7CD5Dx.mjs → deps-2Wo81np9.mjs} +2 -2
  22. package/dist/{device-BwH2iI3O.mjs → device-Cf7vl-so.mjs} +7 -7
  23. package/dist/{device-lease-D83nqeMX.mjs → device-lease-CL9dZf73.mjs} +55 -6
  24. package/dist/{device-pool-DHj7cdPy.mjs → device-pool-MuoiyRcu.mjs} +4 -4
  25. package/dist/{device-remote-BQZSnnmE.mjs → device-remote-DT9ngZiD.mjs} +254 -579
  26. package/dist/{doctor-D8QdMRMf.mjs → doctor-D2iysNNH.mjs} +50 -20
  27. package/dist/{error-diagnostics-UYFSQwRy.mjs → error-diagnostics-BoiOhck8.mjs} +7 -7
  28. package/dist/{gc-COZteyiq.mjs → gc-eA-PRBX8.mjs} +1022 -131
  29. package/dist/{guide-NDvTmMi-.mjs → guide-BfZ0OmiP.mjs} +909 -132
  30. package/dist/{guide-status-CWvti2Lg.mjs → guide-status-BaMYu55M.mjs} +2 -2
  31. package/dist/{idle-NETbeNiQ.mjs → idle-DxLi5OkN.mjs} +43 -10
  32. package/dist/{in-use-DVhlSoyn.mjs → in-use-wYEaKQM9.mjs} +11 -7
  33. package/dist/{ios-CQLKpNfr.mjs → ios-CcfCeZ19.mjs} +103 -58
  34. package/dist/{ios-DArbmwer.mjs → ios-CmEzZiOj.mjs} +31 -22
  35. package/dist/{ios-device-CwDZo0X4.mjs → ios-device-BW-t_Lkv.mjs} +1 -1
  36. package/dist/{launch-verify-CuPDGXdr.mjs → launch-verify-CuJaBpEa.mjs} +33 -20
  37. package/dist/{logs-B44a1UeU.mjs → logs-DcSRbC2t.mjs} +12 -11
  38. package/dist/{merge-state-DDxS-XIZ.mjs → merge-state-ytFQCeh4.mjs} +38 -8
  39. package/dist/{metro-BWLOJ_Wr.mjs → metro-BPeY1YMh.mjs} +5 -5
  40. package/dist/{named-ports-Dc7neAlc.mjs → named-ports-n7tnJsI8.mjs} +78 -6
  41. package/dist/native-runtime-CiiFHt0e.mjs +74 -0
  42. package/dist/{ownership-D2xbLVoz.mjs → ownership-Bz2kETAS.mjs} +2 -2
  43. package/dist/{ownership-BiojdtAp.mjs → ownership-PUP4Dwai.mjs} +175 -217
  44. package/dist/page-BTu7I60K.mjs +29 -0
  45. package/dist/{ports-DwBaRFJs.mjs → ports-C5UutqpJ.mjs} +5 -5
  46. package/dist/{project-BXZzOABt.mjs → project-DGeclhvO.mjs} +55 -87
  47. package/dist/{reload-By9Dwsrt.mjs → reload-C-cV5yy_.mjs} +80 -21
  48. package/dist/remote-cache--aehr4Pr.mjs +526 -0
  49. package/dist/{server-bare-D_RK1RCj.mjs → server-bare-Bq8BpSIo.mjs} +1 -1
  50. package/dist/server-expo-BeYwP_Xy.mjs +2 -0
  51. package/dist/{server-expo-o6H5gcBc.mjs → server-expo-DUCg52-K.mjs} +2 -2
  52. package/dist/{settings-C0ugALSC.mjs → settings-ssVBToDR.mjs} +29 -17
  53. package/dist/{settings-B5oFZEri.mjs → settings-xB0Frkg6.mjs} +13 -4
  54. package/dist/settings.schema.json +74 -2
  55. package/dist/{simslim-CIR3IYJO.mjs → simslim-Bbg9UWrt.mjs} +13 -6
  56. package/dist/{slot-launch-rggO1Esw.mjs → slot-launch-BIWEW-wI.mjs} +4 -4
  57. package/dist/{spawn-claims-BJwXTMPt.mjs → spawn-claims-PT8aQpCa.mjs} +1 -1
  58. package/dist/{start-BSsf2tUs.mjs → start-BZhItkiL.mjs} +110 -18
  59. package/dist/{start-i8zc9VmS.mjs → start-Rw2GD3nV.mjs} +1 -1
  60. package/dist/{state-WGdIbi_d.mjs → state-DwAU2_-D.mjs} +15 -3
  61. package/dist/state-l1pYwOre.mjs +148 -0
  62. package/dist/{stats-DBYJ5bxL.mjs → stats-CaSwmsSZ.mjs} +4 -4
  63. package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
  64. package/dist/{status-CitcBRsC.mjs → status-TJlL0HWo.mjs} +649 -116
  65. package/dist/{status-Q-WDEGCB.mjs → status-sszP4XKU.mjs} +130 -28
  66. package/dist/stim-desktop-CXt8-Z3J.mjs +40 -0
  67. package/dist/{stop-DIhrvu0B.mjs → stop-BZ2qMiBP.mjs} +50 -18
  68. package/dist/{stop-rst5mL14.mjs → stop-DskDKNTU.mjs} +2 -2
  69. package/dist/supervisor-run.mjs +11 -11
  70. package/dist/web-run.d.mts +22 -0
  71. package/dist/web-run.mjs +481 -0
  72. package/dist/web-sWXd5iek.mjs +394 -0
  73. package/dist/{worktree-DhxDTK44.mjs → worktree-3cBa-bQt.mjs} +1 -1
  74. package/dist/{worktree-KOjMX3zA.mjs → worktree-D4Do_XiQ.mjs} +229 -21
  75. package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
  76. package/dist/{xcode-B5SPD--o.mjs → xcode-LM6A8cNZ.mjs} +7 -7
  77. package/package.json +5 -5
  78. package/dist/budget-De3P2rq_.mjs +0 -620
  79. package/dist/native-run-D7yB_AsB.mjs +0 -143
  80. package/dist/server-expo-B-CCUJZj.mjs +0 -2
  81. package/dist/workspace-process-lock-Cx74RSDZ.mjs +0 -57
  82. package/dist/workspaces-COD2xCz-.mjs +0 -1013
@@ -1,8 +1,8 @@
1
- import { d as getConfigPath$1, g as loadConfig$1, m as getRepoSettings, p as getProjectSettings } from "./config-BEq0Qw_a.mjs";
2
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
1
+ import { _ as loadConfig$1, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-0jCcMM0E.mjs";
2
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
3
3
  import { existsSync, readFileSync, realpathSync, statSync } from "fs";
4
4
  import { isAbsolute, join, relative, resolve, sep } from "path";
5
- import { ANDROID_COMPILER_CACHE_CHOICES, ANDROID_PCH_CHOICES, REMOTE_DEVICE_BACKENDS, SETTINGS, SETTING_GROUPS, TUNNEL_MODES, acceptsShape, expectedShape, isLayeredSetting, settingDefinition, settingValueError } from "@stim-cli/core/state";
5
+ import { ANDROID_COMPILER_CACHE_CHOICES, ANDROID_PCH_CHOICES, REMOTE_DEVICE_BACKENDS, SETTINGS, SETTING_GROUPS, TUNNEL_MODES, WEB_VIEWPORTS, acceptsShape, expectedShape, isLayeredSetting, settingDefinition, settingValueError } from "@stim-cli/core/state";
6
6
  import { isAbsolute as isAbsolute$1 } from "node:path";
7
7
  import { createHash } from "node:crypto";
8
8
  //#region src/optimizations.ts
@@ -616,5 +616,14 @@ function normalizedHttpsUrl(raw) {
616
616
  return null;
617
617
  }
618
618
  }
619
+ function webSettings(settings) {
620
+ const url = settingValueAt(settings, "web.url");
621
+ const viewport = settingValueAt(settings, "web.viewport");
622
+ return {
623
+ url: typeof url === "string" ? url : null,
624
+ ignoreCertificateErrors: settingValueAt(settings, "web.ignoreCertificateErrors") === true,
625
+ viewport: WEB_VIEWPORTS.includes(viewport) ? viewport : "desktop"
626
+ };
627
+ }
619
628
  //#endregion
620
- export { resolveCacheProviderConfig as A, planMetroReach as B, ngrokUrlSetting as C, readCommittedSettings as D, publicUrlSetting as E, settingsLayers as F, compilerCacheFallbackMessage as H, tunnelModeSetting as I, unknownSettingKeys as L, settingFile as M, settingOrigin as N, remoteAndroidSetting as O, settingShapeErrors as P, PUBLIC_METRO_ENV as R, metroWarmupUrlSetting as S, projectOptimizations as T, optimizationBuildProfile as U, artifactCachePolicy as V, resolveOptimizations as W, iosSigningIdentitySha1SettingError as _, SETTING_SHAPE_REMEDY as a, metroIdleStopMinutesSetting as b, androidDataPartitionSizeBytes as c, cacheProviderSettingError as d, iosLanHostSetting as f, iosSigningIdentitySha1Setting as g, iosSigningIdentitySettingError as h, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as i, resolveSettings as j, remoteIosSetting as k, androidDataPartitionSizeGbSetting as l, iosSigningIdentitySetting as m, PATH_SETTINGS as n, androidAvdConfigSetting as o, iosLanHostSettingError as p, REMOTE_DEVICE_BACKENDS as r, androidAvdConfigSettingError as s, ANDROID_AVD_CONFIG_HELP as t, androidDataPartitionSizeGbSettingError as u, iosSimSlimProfileSetting as v, projectMetroSharedCache as w, metroTunnelSettingError as x, mergeSettingsLayers as y, detectProviders as z };
629
+ export { resolveCacheProviderConfig as A, detectProviders as B, ngrokUrlSetting as C, readCommittedSettings as D, publicUrlSetting as E, settingsLayers as F, resolveOptimizations as G, artifactCachePolicy as H, tunnelModeSetting as I, unknownSettingKeys as L, settingFile as M, settingOrigin as N, remoteAndroidSetting as O, settingShapeErrors as P, webSettings as R, metroWarmupUrlSetting as S, projectOptimizations as T, compilerCacheFallbackMessage as U, planMetroReach as V, optimizationBuildProfile as W, iosSigningIdentitySha1SettingError as _, SETTING_SHAPE_REMEDY as a, metroIdleStopMinutesSetting as b, androidDataPartitionSizeBytes as c, cacheProviderSettingError as d, iosLanHostSetting as f, iosSigningIdentitySha1Setting as g, iosSigningIdentitySettingError as h, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as i, resolveSettings as j, remoteIosSetting as k, androidDataPartitionSizeGbSetting as l, iosSigningIdentitySetting as m, PATH_SETTINGS as n, androidAvdConfigSetting as o, iosLanHostSettingError as p, REMOTE_DEVICE_BACKENDS as r, androidAvdConfigSettingError as s, ANDROID_AVD_CONFIG_HELP as t, androidDataPartitionSizeGbSettingError as u, iosSimSlimProfileSetting as v, projectMetroSharedCache as w, metroTunnelSettingError as x, mergeSettingsLayers as y, PUBLIC_METRO_ENV as z };
@@ -582,6 +582,58 @@
582
582
  },
583
583
  "additionalProperties": false
584
584
  },
585
+ "web": {
586
+ "type": "object",
587
+ "properties": {
588
+ "url": {
589
+ "description": "Page `stim web` opens; unset opens the Metro URL for Expo web",
590
+ "type": "string",
591
+ "pattern": "^https?://",
592
+ "x-stim": {
593
+ "key": "web.url",
594
+ "kind": "string",
595
+ "scopes": [
596
+ "workspace",
597
+ "repo",
598
+ "committed"
599
+ ]
600
+ }
601
+ },
602
+ "ignoreCertificateErrors": {
603
+ "description": "Accept self-signed dev certificates in Stim's owned Chrome profile",
604
+ "type": "boolean",
605
+ "default": false,
606
+ "x-stim": {
607
+ "key": "web.ignoreCertificateErrors",
608
+ "kind": "boolean",
609
+ "scopes": [
610
+ "workspace",
611
+ "repo",
612
+ "committed"
613
+ ]
614
+ }
615
+ },
616
+ "viewport": {
617
+ "description": "Viewport of the owned Chrome page: desktop, or phone for a 390x844 touch screen",
618
+ "type": "string",
619
+ "enum": [
620
+ "desktop",
621
+ "phone"
622
+ ],
623
+ "default": "desktop",
624
+ "x-stim": {
625
+ "key": "web.viewport",
626
+ "kind": "choice",
627
+ "scopes": [
628
+ "workspace",
629
+ "repo",
630
+ "committed"
631
+ ]
632
+ }
633
+ }
634
+ },
635
+ "additionalProperties": false
636
+ },
585
637
  "worktree": {
586
638
  "type": "object",
587
639
  "properties": {
@@ -904,7 +956,7 @@
904
956
  "additionalProperties": false
905
957
  },
906
958
  "iosSimulatorApp": {
907
- "description": "App that displays an owned iOS simulator",
959
+ "description": "App that displays an owned iOS simulator; stim-desktop by default when Stim Desktop is installed",
908
960
  "type": "string",
909
961
  "enum": [
910
962
  "xcode",
@@ -921,7 +973,7 @@
921
973
  }
922
974
  },
923
975
  "androidEmulatorApp": {
924
- "description": "App that displays an owned Android emulator Stim boots on macOS",
976
+ "description": "App that displays an owned Android emulator Stim boots on macOS; stim-desktop by default when Stim Desktop is installed",
925
977
  "type": "string",
926
978
  "enum": [
927
979
  "emulator",
@@ -1030,6 +1082,26 @@
1030
1082
  },
1031
1083
  "additionalProperties": false
1032
1084
  },
1085
+ "gc": {
1086
+ "type": "object",
1087
+ "properties": {
1088
+ "worktreeGraceMinutes": {
1089
+ "description": "Minutes after a linked worktree last changed, or its branch or pull request finished, before gc removes it; 0 removes it at once",
1090
+ "type": "integer",
1091
+ "minimum": 0,
1092
+ "default": 120,
1093
+ "x-stim": {
1094
+ "key": "gc.worktreeGraceMinutes",
1095
+ "kind": "number",
1096
+ "scopes": [
1097
+ "machine"
1098
+ ],
1099
+ "env": "STIM_GC_WORKTREE_GRACE_MINUTES"
1100
+ }
1101
+ }
1102
+ },
1103
+ "additionalProperties": false
1104
+ },
1033
1105
  "pool": {
1034
1106
  "type": "object",
1035
1107
  "properties": {
@@ -1,10 +1,11 @@
1
- import { D as process_identity_exports, H as projectDeviceSlots, g as loadConfig, k as ownership_claim_exports, u as getConfigDir, z as deviceSlotPlatforms } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, B as deviceSlotPlatforms, O as process_identity_exports, U as projectDeviceSlots, _ as loadConfig, d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { g as releaseBuildLock, m as acquireBuildLock } from "./device-lease-D83nqeMX.mjs";
5
- import { T as listAdbDevices } from "./android-C4zG2Tuc.mjs";
6
- import { l as listAllIosSims, s as iosRuntimeMatches } from "./ios-DArbmwer.mjs";
7
- import { _ as easCliSupport, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
4
+ import { g as releaseBuildLock, m as acquireBuildLock } from "./device-lease-CL9dZf73.mjs";
5
+ import { D as listAdbDevices } from "./android-qx_31wJo.mjs";
6
+ import { g as parseRuntimeVersion, l as listAllIosSims, s as iosRuntimeMatches } from "./ios-CmEzZiOj.mjs";
7
+ import { f as resolveEasCliBin } from "./remote-cache--aehr4Pr.mjs";
8
+ import { O as easCliSupport, k as easCliUpgradeRemedy, s as readInstalledEasCliVersion } from "./device-remote-DT9ngZiD.mjs";
8
9
  import { existsSync, realpathSync, statSync } from "node:fs";
9
10
  import { join } from "node:path";
10
11
  import { createHash } from "node:crypto";
@@ -304,6 +305,12 @@ function deviceTypeMismatch(recordedTypeId, requestedName, deviceTypes) {
304
305
  const recorded = (deviceTypes || []).find((d) => d.identifier === recordedTypeId);
305
306
  return `this project's sim is ${recorded ? recorded.name : recordedTypeId}, but --device-type asked for ${requestedName}`;
306
307
  }
308
+ function runtimeMismatch(recordedRuntimeId, requested, runtimes) {
309
+ if (!requested || !recordedRuntimeId) return null;
310
+ const wanted = runtimes.find((r) => iosRuntimeMatches(r, requested));
311
+ if (!wanted || wanted.identifier === recordedRuntimeId) return null;
312
+ return `this project's sim runs iOS ${parseRuntimeVersion(recordedRuntimeId)}, but --runtime asked for ${requested}`;
313
+ }
307
314
  function installedNames(names) {
308
315
  const unique = [...new Set(names.filter((n) => typeof n === "string" && n !== ""))];
309
316
  return unique.length > 0 ? unique.join(", ") : "none";
@@ -488,4 +495,4 @@ function simslimIsOnPath() {
488
495
  }
489
496
  }
490
497
  //#endregion
491
- export { liveOwnedDeviceCount as a, unknownIosDeviceTypeRefusal as c, easDeviceBuildRemedy as d, isEasBuildFailure as f, deviceTypeMismatch as i, unknownIosRuntimeRefusal as l, resolveEasDevelopmentBuild as m, simslimIsOnPath as n, unknownAndroidDeviceProfileRefusal as o, planEasDevelopmentBuild as p, checkDeviceCapacity as r, unknownAndroidSystemImageRefusal as s, reconcileSimSlim as t, MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION as u };
498
+ export { liveOwnedDeviceCount as a, unknownAndroidSystemImageRefusal as c, MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION as d, easDeviceBuildRemedy as f, resolveEasDevelopmentBuild as h, deviceTypeMismatch as i, unknownIosDeviceTypeRefusal as l, planEasDevelopmentBuild as m, simslimIsOnPath as n, runtimeMismatch as o, isEasBuildFailure as p, checkDeviceCapacity as r, unknownAndroidDeviceProfileRefusal as s, reconcileSimSlim as t, unknownIosRuntimeRefusal as u };
@@ -1,7 +1,7 @@
1
- import { f as getProject } from "./config-BEq0Qw_a.mjs";
2
- import { m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
3
- import { n as fileLeaseIo } from "./device-lease-D83nqeMX.mjs";
4
- import { d as deviceShellArg } from "./app-install-DHut6JnV.mjs";
1
+ import { p as getProject } from "./config-0jCcMM0E.mjs";
2
+ import { h as readWorkspaceState } from "./metro-BPeY1YMh.mjs";
3
+ import { n as fileLeaseIo } from "./device-lease-CL9dZf73.mjs";
4
+ import { d as deviceShellArg } from "./app-install-CDFY2nUL.mjs";
5
5
  //#region src/engine/slot-launch.ts
6
6
  function launchSlotScope(root, slot = "default") {
7
7
  if (slot !== "default") return slot;
@@ -1,4 +1,4 @@
1
- import { D as process_identity_exports, k as ownership_claim_exports } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, O as process_identity_exports } from "./config-0jCcMM0E.mjs";
2
2
  //#region src/engine/spawn-claims.ts
3
3
  const declaring = /* @__PURE__ */ new Set();
4
4
  const running = /* @__PURE__ */ new Set();
@@ -1,32 +1,123 @@
1
- import { D as process_identity_exports, f as getProject, w as upsertProject } from "./config-BEq0Qw_a.mjs";
1
+ import { O as process_identity_exports, T as upsertProject, p as getProject } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { i as levelRank } from "./ndjson-CDY9IkVC.mjs";
4
- import { T as supervisorLogFile, c as signalProcessTree, d as reserveMetroPort, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, p as clearWorkspaceStateKeys, s as resolveProjectMetro, x as ensureWorkspaceStorage, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
5
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
6
- import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, r as detectAndroidPackage, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
4
+ import { E as supervisorLogFile, M as workspaceLogsDir, S as ensureWorkspaceStorage, a as pidExists, b as writeWorkspaceState, c as resolveProjectMetro, f as reserveMetroPort, g as recordWorkspaceUse, h as readWorkspaceState$1, l as signalProcessTree, m as clearWorkspaceStateKeys } from "./metro-BPeY1YMh.mjs";
5
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
6
+ import { a as findProjectRoot, d as readAppJson, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL, u as readAppConfigText } from "./project-DGeclhvO.mjs";
7
7
  import { n as windowsLauncherArgs } from "./detached-entry-DJHoca49.mjs";
8
- import { i as clearManagedMetroTunnel, s as readMetroTunnel } from "./state-WGdIbi_d.mjs";
9
- import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-Cx74RSDZ.mjs";
10
- import { _ as stepTimer, l as phaseLine } from "./command-output-D5z2_bcF.mjs";
11
- import { A as resolveCacheProviderConfig, B as planMetroReach, C as ngrokUrlSetting, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, O as remoteAndroidSetting, P as settingShapeErrors, R as PUBLIC_METRO_ENV, a as SETTING_SHAPE_REMEDY, b as metroIdleStopMinutesSetting, d as cacheProviderSettingError, j as resolveSettings, k as remoteIosSetting, x as metroTunnelSettingError, z as detectProviders } from "./settings-B5oFZEri.mjs";
12
- import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-BiojdtAp.mjs";
13
- import { i as stopOwnedMetroForReset, t as budgetGate } from "./budget-De3P2rq_.mjs";
8
+ import { c as readMetroTunnel, i as clearManagedMetroTunnel } from "./state-DwAU2_-D.mjs";
9
+ import { a as withWorkspaceProcessLock, o as workspaceProcessLockError } from "./named-ports-n7tnJsI8.mjs";
10
+ import { _ as stepTimer, l as phaseLine } from "./command-output-BIL7rlX7.mjs";
11
+ import { A as resolveCacheProviderConfig, B as detectProviders, C as ngrokUrlSetting, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, O as remoteAndroidSetting, P as settingShapeErrors, V as planMetroReach, a as SETTING_SHAPE_REMEDY, b as metroIdleStopMinutesSetting, d as cacheProviderSettingError, j as resolveSettings, k as remoteIosSetting, x as metroTunnelSettingError, z as PUBLIC_METRO_ENV } from "./settings-xB0Frkg6.mjs";
12
+ import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-PUP4Dwai.mjs";
13
+ import { d as readProjectConfig } from "./remote-cache--aehr4Pr.mjs";
14
+ import { I as stopOwnedMetroForReset, t as budgetGate } from "./budget-E5o91NR1.mjs";
14
15
  import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
16
+ import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
17
+ import { join } from "path";
15
18
  import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
16
- import { basename, dirname, join } from "node:path";
19
+ import { basename as basename$1, dirname as dirname$1, join as join$1 } from "node:path";
17
20
  import { EventEmitter } from "node:events";
18
21
  import { fileURLToPath } from "node:url";
19
22
  import chalk from "chalk";
20
23
  import { CACHE_PROVIDER_ENV, cacheProviderEnv } from "@stim-cli/cache";
24
+ //#region src/workspace/app-id.ts
25
+ function configString(config, platform, key) {
26
+ if (!config || typeof config !== "object") return null;
27
+ const expoField = config.expo;
28
+ const section = (expoField && typeof expoField === "object" ? expoField : config)[platform];
29
+ if (!section || typeof section !== "object") return null;
30
+ const value = section[key];
31
+ return typeof value === "string" && value ? value : null;
32
+ }
33
+ function literalString(text, key) {
34
+ return text?.match(new RegExp(`${key}\\s*:\\s*["']([^"']+)["']`))?.[1] ?? null;
35
+ }
36
+ function idsFromConfig(projectRoot) {
37
+ const read = readProjectConfig(projectRoot);
38
+ if (!read.unavailable) return {
39
+ bundleId: configString(read.config, "ios", "bundleIdentifier"),
40
+ androidPackage: configString(read.config, "android", "package")
41
+ };
42
+ const appJson = readAppJson(projectRoot);
43
+ const text = readAppConfigText(projectRoot);
44
+ return {
45
+ bundleId: configString(appJson, "ios", "bundleIdentifier") ?? literalString(text, "bundleIdentifier"),
46
+ androidPackage: configString(appJson, "android", "package") ?? literalString(text, "package")
47
+ };
48
+ }
49
+ function detectAppIds(projectRoot) {
50
+ const ids = idsFromConfig(projectRoot);
51
+ return {
52
+ bundleId: ids.bundleId ?? detectBundleIdFromPbxproj(projectRoot),
53
+ androidPackage: ids.androidPackage ?? detectAndroidPackageFromGradle(projectRoot)
54
+ };
55
+ }
56
+ function detectBundleId(projectRoot) {
57
+ return detectAppIds(projectRoot).bundleId;
58
+ }
59
+ function detectAndroidPackage(projectRoot) {
60
+ return detectAppIds(projectRoot).androidPackage;
61
+ }
62
+ function detectBundleIdFromPbxproj(projectRoot) {
63
+ const iosDir = join(projectRoot, "ios");
64
+ if (!existsSync$1(iosDir)) return null;
65
+ let entries;
66
+ try {
67
+ entries = readdirSync$1(iosDir, { withFileTypes: true });
68
+ } catch {
69
+ return null;
70
+ }
71
+ for (const entry of entries) {
72
+ if (!entry.isDirectory() || !entry.name.endsWith(".xcodeproj")) continue;
73
+ const pbx = join(iosDir, entry.name, "project.pbxproj");
74
+ if (!existsSync$1(pbx)) continue;
75
+ let text;
76
+ try {
77
+ text = readFileSync$1(pbx, "utf-8");
78
+ } catch {
79
+ continue;
80
+ }
81
+ const concrete = [...text.matchAll(/PRODUCT_BUNDLE_IDENTIFIER\s*=\s*([^;\s"]+)\s*;/g)].map((m) => m[1]).filter((id) => !!id && !id.startsWith("$") && !id.includes("("));
82
+ if (concrete.length === 0) continue;
83
+ const counts = {};
84
+ for (const id of concrete) counts[id] = (counts[id] || 0) + 1;
85
+ let best = null, bestCount = 0, bestLen = Infinity;
86
+ for (const [id, count] of Object.entries(counts)) if (count > bestCount || count === bestCount && id.length < bestLen) {
87
+ best = id;
88
+ bestCount = count;
89
+ bestLen = id.length;
90
+ }
91
+ return best;
92
+ }
93
+ return null;
94
+ }
95
+ function detectAndroidPackageFromGradle(projectRoot) {
96
+ const gradle = join(projectRoot, "android", "app", "build.gradle");
97
+ if (!existsSync$1(gradle)) return null;
98
+ let text;
99
+ try {
100
+ text = readFileSync$1(gradle, "utf-8");
101
+ } catch {
102
+ return null;
103
+ }
104
+ const nsId = text.match(/namespace\s+["']([^"']+)["']/)?.[1];
105
+ if (nsId) return nsId;
106
+ const appId = text.match(/applicationId\s+["']([^"']+)["']/)?.[1];
107
+ if (appId) return appId;
108
+ return null;
109
+ }
110
+ //#endregion
21
111
  //#region src/spawn-entry.ts
22
112
  const DEV_ENTRIES = {
23
113
  "supervisor-run": "./supervisor/run.ts",
24
- "collector-run": "./collector/run.ts"
114
+ "collector-run": "./collector/run.ts",
115
+ "web-run": "./web/run.ts"
25
116
  };
26
117
  function spawnEntry(name) {
27
118
  const here = fileURLToPath(import.meta.url);
28
- if (basename(dirname(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
29
- return join(dirname(here), `${name}.mjs`);
119
+ if (basename$1(dirname$1(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
120
+ return join$1(dirname$1(here), `${name}.mjs`);
30
121
  }
31
122
  //#endregion
32
123
  //#region src/commands/start.ts
@@ -269,9 +360,10 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
269
360
  if (tunnel) note(chalk.dim("note requesting an Expo tunnel for this workspace's dev server"));
270
361
  const managedRemote = remote && !tunnel && !publicUrl && tunnelMode !== "off";
271
362
  const runStart = async () => {
363
+ const appIds = detectAppIds(root);
272
364
  upsertProject(root, {
273
- bundleId: detectBundleId(root) ?? void 0,
274
- androidPackage: detectAndroidPackage(root) ?? void 0,
365
+ bundleId: appIds.bundleId ?? void 0,
366
+ androidPackage: appIds.androidPackage ?? void 0,
275
367
  isExpo
276
368
  });
277
369
  const gateBudget = async () => {
@@ -819,7 +911,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
819
911
  };
820
912
  const startLocked = async () => {
821
913
  try {
822
- return await withWorkspaceProcessLock(dirname(workspaceLogsDir(root)), "metro-start", runStart, { external: true });
914
+ return await withWorkspaceProcessLock(dirname$1(workspaceLogsDir(root)), "metro-start", runStart, { external: true });
823
915
  } catch (error) {
824
916
  if (workspaceProcessLockError(error) !== "timeout") throw error;
825
917
  return fail({
@@ -935,4 +1027,4 @@ function report({ json, out, facts, waited, reclaimed }) {
935
1027
  out(chalk.dim(phaseLine("logs", facts.logsDir)));
936
1028
  }
937
1029
  //#endregion
938
- export { registerStart as a, startFacts as c, wantsExpoOwnTunnel as d, spawnEntry as f, readLogTail as i, supervisorEntry as l, liveSupervisor as n, startCommand as o, parseWait as r, startDevServer as s, failureEvidence as t, tailLines as u };
1030
+ export { registerStart as a, startFacts as c, wantsExpoOwnTunnel as d, spawnEntry as f, detectBundleId as h, readLogTail as i, supervisorEntry as l, detectAppIds as m, liveSupervisor as n, startCommand as o, detectAndroidPackage as p, parseWait as r, startDevServer as s, failureEvidence as t, tailLines as u };
@@ -1,2 +1,2 @@
1
- import { a as registerStart, c as startFacts, d as wantsExpoOwnTunnel, i as readLogTail, l as supervisorEntry, n as liveSupervisor, o as startCommand, r as parseWait, s as startDevServer, t as failureEvidence, u as tailLines } from "./start-BSsf2tUs.mjs";
1
+ import { a as registerStart, c as startFacts, d as wantsExpoOwnTunnel, i as readLogTail, l as supervisorEntry, n as liveSupervisor, o as startCommand, r as parseWait, s as startDevServer, t as failureEvidence, u as tailLines } from "./start-BZhItkiL.mjs";
2
2
  export { startCommand as default, failureEvidence, liveSupervisor, parseWait, readLogTail, registerStart, startDevServer, startFacts, supervisorEntry, tailLines, wantsExpoOwnTunnel };
@@ -1,5 +1,5 @@
1
- import { B as parseDeviceSlotKey, D as process_identity_exports, R as deviceSlotKey } from "./config-BEq0Qw_a.mjs";
2
- import { E as supervisorPidFile, N as workspaceStateFile, _ as withWorkspaceStateLock, f as clearWorkspaceStateKey, g as updateWorkspaceState, m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
1
+ import { O as process_identity_exports, V as parseDeviceSlotKey, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
+ import { D as supervisorPidFile, P as workspaceStateFile, _ as updateWorkspaceState, h as readWorkspaceState, p as clearWorkspaceStateKey, v as withWorkspaceStateLock } from "./metro-BPeY1YMh.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname } from "node:path";
5
5
  //#region src/supervisor/state.ts
@@ -68,6 +68,18 @@ function writeWorkspaceLaunch(root, platform, record, slot = "default") {
68
68
  };
69
69
  });
70
70
  }
71
+ function clearWorkspaceLaunches(root, slot) {
72
+ updateWorkspaceState(root, (state) => {
73
+ if (!state.launches || typeof state.launches !== "object") return state;
74
+ const launches = { ...state.launches };
75
+ delete launches[deviceSlotKey("ios", slot)];
76
+ delete launches[deviceSlotKey("android", slot)];
77
+ return {
78
+ ...state,
79
+ launches
80
+ };
81
+ });
82
+ }
71
83
  function readRemoteSession(root) {
72
84
  const record = readWorkspaceState(root)?.remoteDevice;
73
85
  if (!record || typeof record !== "object") return null;
@@ -130,4 +142,4 @@ function readPidFile(root) {
130
142
  }
131
143
  }
132
144
  //#endregion
133
- export { clearRemoteSession as a, readPidFile as c, readWorkspaceLaunches as d, writePidFile as f, clearManagedMetroTunnel as i, readRemoteSession as l, MODE_EXPO as n, clearWorkspaceSupervisor as o, writeWorkspaceLaunch as p, clearExpoMetroTunnel as r, readMetroTunnel as s, MODE_BARE as t, readRemoteSessionId as u };
145
+ export { clearRemoteSession as a, readMetroTunnel as c, readRemoteSessionId as d, readWorkspaceLaunches as f, clearManagedMetroTunnel as i, readPidFile as l, writeWorkspaceLaunch as m, MODE_EXPO as n, clearWorkspaceLaunches as o, writePidFile as p, clearExpoMetroTunnel as r, clearWorkspaceSupervisor as s, MODE_BARE as t, readRemoteSession as u };
@@ -0,0 +1,148 @@
1
+ import { A as ownership_claim_exports, O as process_identity_exports } from "./config-0jCcMM0E.mjs";
2
+ import { M as workspaceLogsDir, _ as updateWorkspaceState, a as pidExists, b as writeWorkspaceState, h as readWorkspaceState$1, k as workspaceDir, p as clearWorkspaceStateKey } from "./metro-BPeY1YMh.mjs";
3
+ import { readlinkSync, rmSync } from "node:fs";
4
+ import { WEB_VIEWPORTS } from "@stim-cli/core/state";
5
+ import { join } from "node:path";
6
+ import { hostname } from "node:os";
7
+ //#region src/web/profile.ts
8
+ const SINGLETON_FILES = [
9
+ "SingletonLock",
10
+ "SingletonSocket",
11
+ "SingletonCookie"
12
+ ];
13
+ /**
14
+ * The process Chrome's `SingletonLock` names, when it is a live process on this host. Chrome writes the lock as a
15
+ * symlink to `<hostname>-<pid>` and refuses a second instance on the profile while that process lives.
16
+ */
17
+ function liveProfileHolder(profile, { alive = pidExists } = {}) {
18
+ let target;
19
+ try {
20
+ target = readlinkSync(join(profile, "SingletonLock"));
21
+ } catch {
22
+ return null;
23
+ }
24
+ const match = /^(.*)-(\d+)$/.exec(target);
25
+ if (!match || match[1] !== hostname()) return null;
26
+ const pid = Number(match[2]);
27
+ return alive(pid) ? pid : null;
28
+ }
29
+ /** Removes the lock files a Chrome that did not exit cleanly leaves; call only once that Chrome is gone. */
30
+ function removeSingletonFiles(profile) {
31
+ for (const name of SINGLETON_FILES) rmSync(join(profile, name), { force: true });
32
+ }
33
+ /**
34
+ * Whether the owned Chrome still runs. `lingering` means the recorded process exited but its process group, whose
35
+ * id is that pid, still has helper processes: a live group id cannot be reused. A pid now held by a different
36
+ * process is `gone`, never something to signal.
37
+ */
38
+ function chromeProcessState(record) {
39
+ const identity = (0, process_identity_exports.inspectProcessIdentity)(record);
40
+ if (identity === "same") return "running";
41
+ if (identity === "unknown") return "unknown";
42
+ if (identity === "different") return "gone";
43
+ return (0, ownership_claim_exports.processGroupAlive)(record.pid) ? "lingering" : "gone";
44
+ }
45
+ //#endregion
46
+ //#region src/web/state.ts
47
+ const WEB_STATE_KEY = "web";
48
+ const CDP_PORT_LABEL = "web-cdp";
49
+ function webDir(root) {
50
+ return join(workspaceDir(root), "web");
51
+ }
52
+ function webProfileDir(root) {
53
+ return join(webDir(root), "profile");
54
+ }
55
+ function webClaimRoot(root) {
56
+ return join(webDir(root), "supervisor.lock");
57
+ }
58
+ function webLogFile(root) {
59
+ return join(workspaceLogsDir(root), "web.ndjson");
60
+ }
61
+ function webSupervisorLogFile(root) {
62
+ return join(workspaceLogsDir(root), "web-supervisor.log");
63
+ }
64
+ function browserLogFile(root) {
65
+ return join(workspaceLogsDir(root), "browser.log");
66
+ }
67
+ function processRecord(value) {
68
+ const record = value;
69
+ return typeof record?.pid === "number" && typeof record.processToken === "string" ? {
70
+ pid: record.pid,
71
+ processToken: record.processToken
72
+ } : void 0;
73
+ }
74
+ function parseWebRecord(value) {
75
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
76
+ const record = value;
77
+ const owner = processRecord(record);
78
+ if (!owner || typeof record.cdpPort !== "number" || typeof record.profile !== "string") return null;
79
+ if (typeof record.url !== "string" || typeof record.chrome !== "string") return null;
80
+ const chromeProcess = processRecord(record.chromeProcess);
81
+ return {
82
+ pid: owner.pid,
83
+ processToken: owner.processToken,
84
+ chrome: record.chrome,
85
+ ...chromeProcess ? { chromeProcess } : {},
86
+ cdpPort: record.cdpPort,
87
+ profile: record.profile,
88
+ url: record.url,
89
+ headless: record.headless !== false,
90
+ viewport: WEB_VIEWPORTS.includes(record.viewport) ? record.viewport : "desktop",
91
+ ignoreCertificateErrors: record.ignoreCertificateErrors === true,
92
+ startedAt: typeof record.startedAt === "string" ? record.startedAt : "",
93
+ ...typeof record.targetId === "string" ? { targetId: record.targetId } : {},
94
+ ...typeof record.version === "string" ? { version: record.version } : {},
95
+ ...typeof record.launchId === "string" ? { launchId: record.launchId } : {}
96
+ };
97
+ }
98
+ function readWebRecord(root) {
99
+ return parseWebRecord(readWorkspaceState$1(root)?.[WEB_STATE_KEY]);
100
+ }
101
+ function writeWebRecord(root, record) {
102
+ writeWorkspaceState(root, { [WEB_STATE_KEY]: record });
103
+ }
104
+ /** Merges `patch` into the record only while `owner` still holds it; false when another supervisor does. */
105
+ function updateWebRecord(root, owner, patch) {
106
+ let updated = false;
107
+ updateWorkspaceState(root, (state) => {
108
+ const current = parseWebRecord(state[WEB_STATE_KEY]);
109
+ if (!current || !(0, process_identity_exports.sameProcessRecord)(current, owner)) return state;
110
+ updated = true;
111
+ return {
112
+ ...state,
113
+ [WEB_STATE_KEY]: {
114
+ ...current,
115
+ ...patch
116
+ }
117
+ };
118
+ });
119
+ return updated;
120
+ }
121
+ function clearWebRecord(root, owner) {
122
+ return clearWorkspaceStateKey(root, WEB_STATE_KEY, (value) => {
123
+ const current = parseWebRecord(value);
124
+ return !current || (0, process_identity_exports.sameProcessRecord)(current, owner);
125
+ });
126
+ }
127
+ function cdpEndpoint(port) {
128
+ return `http://127.0.0.1:${port}`;
129
+ }
130
+ function webFacts(record) {
131
+ if (!record) return null;
132
+ const supervisor = (0, process_identity_exports.inspectProcessIdentity)(record);
133
+ const chrome = record.chromeProcess ? chromeProcessState(record.chromeProcess) : "gone";
134
+ if (supervisor === "unknown" || chrome === "unknown") return {
135
+ record,
136
+ status: "unverified"
137
+ };
138
+ if (chrome === "gone") return {
139
+ record,
140
+ status: "stopped"
141
+ };
142
+ return {
143
+ record,
144
+ status: supervisor === "same" && chrome === "running" ? "running" : "orphaned"
145
+ };
146
+ }
147
+ //#endregion
148
+ export { readWebRecord as a, webDir as c, webProfileDir as d, webSupervisorLogFile as f, removeSingletonFiles as g, liveProfileHolder as h, clearWebRecord as i, webFacts as l, chromeProcessState as m, browserLogFile as n, updateWebRecord as o, writeWebRecord as p, cdpEndpoint as r, webClaimRoot as s, CDP_PORT_LABEL as t, webLogFile as u };
@@ -1,7 +1,7 @@
1
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
2
- import { o as findProjectRoot } from "./project-BXZzOABt.mjs";
3
- import { o as formatLongDuration } from "./command-output-D5z2_bcF.mjs";
4
- import { a as statsProjectKey, r as readStats } from "./stats-BAgJaLA4.mjs";
1
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
2
+ import { a as findProjectRoot } from "./project-DGeclhvO.mjs";
3
+ import { o as formatLongDuration } from "./command-output-BIL7rlX7.mjs";
4
+ import { a as statsProjectKey, r as readStats } from "./stats-D8rUTPHd.mjs";
5
5
  import chalk from "chalk";
6
6
  //#region src/commands/stats.ts
7
7
  const PLATFORMS = ["ios", "android"];
@@ -1,4 +1,4 @@
1
- import { T as withConfigLock, u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { E as withConfigLock, d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { basename, dirname, join, relative, resolve } from "node:path";
4
4
  const PLATFORMS = ["ios", "android"];