stim 1.11.0 → 1.12.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 (71) hide show
  1. package/dist/{activity-BtG4Va9l.mjs → activity-CCZJs__P.mjs} +4 -3
  2. package/dist/{android-C4zG2Tuc.mjs → android-75Sk2rIR.mjs} +25 -8
  3. package/dist/{android-C1q4l523.mjs → android-B7X-8H7h.mjs} +75 -32
  4. package/dist/{android-BA2i_KAV.mjs → android-BQiKJYK0.mjs} +1 -1
  5. package/dist/{android-cas-DfJkwCXW.mjs → android-cas-DzLPXiEn.mjs} +7 -7
  6. package/dist/{app-install-DHut6JnV.mjs → app-install-CsZi0SAT.mjs} +1 -1
  7. package/dist/{workspaces-COD2xCz-.mjs → budget-DbzW5VTD.mjs} +641 -32
  8. package/dist/{build-plan-CeAYgKAx.mjs → build-plan-CqntbR7b.mjs} +120 -35
  9. package/dist/{build-progress-CDwogz6R.mjs → build-progress-h60GPV27.mjs} +3 -3
  10. package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +16 -16
  13. package/dist/collector-run.mjs +4 -4
  14. package/dist/{command-output-D5z2_bcF.mjs → command-output-BWCj5Vh-.mjs} +1 -1
  15. package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
  16. package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
  17. package/dist/{deps-OF7CD5Dx.mjs → deps-CO-_7UOm.mjs} +2 -2
  18. package/dist/{device-BwH2iI3O.mjs → device-9r9xRYDa.mjs} +7 -7
  19. package/dist/{device-lease-D83nqeMX.mjs → device-lease-B9LAXIUH.mjs} +5 -5
  20. package/dist/{device-pool-DHj7cdPy.mjs → device-pool-BoezJd-c.mjs} +4 -4
  21. package/dist/{device-remote-BQZSnnmE.mjs → device-remote-C0_o-tJH.mjs} +254 -579
  22. package/dist/{doctor-D8QdMRMf.mjs → doctor-LfDlbR-N.mjs} +19 -18
  23. package/dist/{error-diagnostics-UYFSQwRy.mjs → error-diagnostics-CCxjn31V.mjs} +7 -7
  24. package/dist/{gc-COZteyiq.mjs → gc-C4nQFcTX.mjs} +203 -39
  25. package/dist/{guide-NDvTmMi-.mjs → guide-BPBlh9ML.mjs} +189 -38
  26. package/dist/{guide-status-CWvti2Lg.mjs → guide-status-i9ogHt4v.mjs} +2 -2
  27. package/dist/{idle-NETbeNiQ.mjs → idle-S3tFZ53_.mjs} +7 -7
  28. package/dist/{in-use-DVhlSoyn.mjs → in-use-D9XYEgFD.mjs} +7 -7
  29. package/dist/{ios-CQLKpNfr.mjs → ios-CDzWL1mj.mjs} +30 -29
  30. package/dist/{ios-DArbmwer.mjs → ios-CZWOHTTc.mjs} +23 -19
  31. package/dist/{ios-device-CwDZo0X4.mjs → ios-device-D9cLxVr5.mjs} +1 -1
  32. package/dist/{launch-verify-CuPDGXdr.mjs → launch-verify-B2oR_kFN.mjs} +2 -2
  33. package/dist/{logs-B44a1UeU.mjs → logs-SzuYudOj.mjs} +6 -6
  34. package/dist/{merge-state-DDxS-XIZ.mjs → merge-state-ytFQCeh4.mjs} +38 -8
  35. package/dist/{metro-BWLOJ_Wr.mjs → metro-Dzo30hvJ.mjs} +1 -1
  36. package/dist/{named-ports-Dc7neAlc.mjs → named-ports-Dn1o61D9.mjs} +3 -3
  37. package/dist/{ownership-BiojdtAp.mjs → ownership-B8d4kXBx.mjs} +49 -16
  38. package/dist/{ownership-D2xbLVoz.mjs → ownership-Dqnrjrio.mjs} +2 -2
  39. package/dist/{ports-DwBaRFJs.mjs → ports-Dp_QTwTC.mjs} +3 -3
  40. package/dist/{project-BXZzOABt.mjs → project-B8rbutVC.mjs} +4 -72
  41. package/dist/{reload-By9Dwsrt.mjs → reload-nocmx8KB.mjs} +9 -9
  42. package/dist/remote-cache-BRsRZru5.mjs +526 -0
  43. package/dist/{server-bare-D_RK1RCj.mjs → server-bare-Gn3ssSdK.mjs} +1 -1
  44. package/dist/{server-expo-o6H5gcBc.mjs → server-expo-CeT1nIIk.mjs} +2 -2
  45. package/dist/server-expo-eWi9Coof.mjs +2 -0
  46. package/dist/{settings-B5oFZEri.mjs → settings-BlyDn2Oz.mjs} +2 -2
  47. package/dist/{settings-C0ugALSC.mjs → settings-bE-Gu3Ti.mjs} +23 -11
  48. package/dist/settings.schema.json +22 -2
  49. package/dist/{simslim-CIR3IYJO.mjs → simslim-COtEEP7x.mjs} +6 -5
  50. package/dist/{slot-launch-rggO1Esw.mjs → slot-launch-DIACGEfH.mjs} +4 -4
  51. package/dist/{spawn-claims-BJwXTMPt.mjs → spawn-claims-PT8aQpCa.mjs} +1 -1
  52. package/dist/{start-i8zc9VmS.mjs → start-BFstVBlx.mjs} +1 -1
  53. package/dist/{start-BSsf2tUs.mjs → start-BboE1HIS.mjs} +108 -17
  54. package/dist/{state-WGdIbi_d.mjs → state-DcDgzfu3.mjs} +15 -3
  55. package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
  56. package/dist/{stats-DBYJ5bxL.mjs → stats-DiCtmluY.mjs} +4 -4
  57. package/dist/{status-Q-WDEGCB.mjs → status-BUASYyy_.mjs} +73 -28
  58. package/dist/{status-CitcBRsC.mjs → status-DI9Tjo7T.mjs} +41 -29
  59. package/dist/stim-desktop-D0xhpZt8.mjs +29 -0
  60. package/dist/{stop-rst5mL14.mjs → stop-BI7QY76M.mjs} +2 -2
  61. package/dist/{stop-DIhrvu0B.mjs → stop-Bn6v-GvS.mjs} +23 -16
  62. package/dist/supervisor-run.mjs +11 -11
  63. package/dist/{workspace-process-lock-Cx74RSDZ.mjs → workspace-process-lock-BvvJTfo_.mjs} +2 -2
  64. package/dist/{worktree-DhxDTK44.mjs → worktree-B5sTRskL.mjs} +1 -1
  65. package/dist/{worktree-KOjMX3zA.mjs → worktree-ChDL5fO1.mjs} +17 -16
  66. package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
  67. package/dist/{xcode-B5SPD--o.mjs → xcode-BzplpQzc.mjs} +7 -7
  68. package/package.json +5 -5
  69. package/dist/budget-De3P2rq_.mjs +0 -620
  70. package/dist/native-run-D7yB_AsB.mjs +0 -143
  71. package/dist/server-expo-B-CCUJZj.mjs +0 -2
@@ -1,25 +1,25 @@
1
- import { H as projectDeviceSlots, O as acquireAvdClaim, S as setDevice, T as withConfigLock$1, g as loadConfig$1, i as clearDevice, t as allConsolePortsAndSerials, u as getConfigDir, v as releaseAndroidConsolePort, x as saveConfig, z as deviceSlotPlatforms } from "./config-BEq0Qw_a.mjs";
1
+ import { B as deviceSlotPlatforms, C as setDevice, E as withConfigLock$1, S as saveConfig, U as projectDeviceSlots, _ as loadConfig$1, a as clearDevice, d as getConfigDir, i as clearAndroidBootPending, k as acquireAvdClaim, t as allConsolePortsAndSerials, y as releaseAndroidConsolePort } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { S as sharedBuildCache, g as updateWorkspaceState, i as pidExists, k as workspaceId, m as readWorkspaceState$1, s as resolveProjectMetro, x as ensureWorkspaceStorage } from "./metro-BWLOJ_Wr.mjs";
4
- import { D as makeTemporaryDirectory, O as removeTemporaryEntry, c as gitCommonDirOnDisk } from "./worktree-BlizKDpZ.mjs";
5
- import { a as detectIsExpo, c as ownedDeviceLabel, s as isPackageResolvable } from "./project-BXZzOABt.mjs";
6
- import { a as spawnDeclared } from "./spawn-claims-BJwXTMPt.mjs";
7
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-Cx74RSDZ.mjs";
3
+ import { S as sharedBuildCache, g as updateWorkspaceState, i as pidExists, k as workspaceId, m as readWorkspaceState$1, s as resolveProjectMetro, x as ensureWorkspaceStorage } from "./metro-Dzo30hvJ.mjs";
4
+ import { D as makeTemporaryDirectory, O as removeTemporaryEntry, c as gitCommonDirOnDisk } from "./worktree-DeBQSVtR.mjs";
5
+ import { a as isPackageResolvable, o as ownedDeviceLabel, r as detectIsExpo } from "./project-B8rbutVC.mjs";
6
+ import { a as spawnDeclared } from "./spawn-claims-PT8aQpCa.mjs";
7
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BvvJTfo_.mjs";
8
8
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
9
- import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-D5z2_bcF.mjs";
10
- import { N as storedSources, S as entryDir, x as diffFingerprintSources, y as artifactIn } from "./device-lease-D83nqeMX.mjs";
11
- import { D as listAvds, F as ownedAvdName, H as resolveOwnedAvdSerial, L as ownedAvdSystemImage, M as ownedAvdDeviceProfile, O as listInstalledSystemImages, P as ownedAvdMatchesConfiguration, S as getAvdNameForSerial, T as listAdbDevices, f as avdPoolConfiguration, g as createOwnedAvd, h as configureNewOwnedAvd, j as nextConsolePort, m as bootAndroidEmulator, q as waitForBoot, t as DEFAULT_AVD_DEVICE_PROFILE, u as assertOwnedAvdStopped, z as pickDefaultSystemImage } from "./android-C4zG2Tuc.mjs";
12
- import { l as androidDataPartitionSizeGbSetting, o as androidAvdConfigSetting, v as iosSimSlimProfileSetting } from "./settings-B5oFZEri.mjs";
13
- import { _ as dropParked, b as readParked, d as teardownOwnedAvd, g as adoptParked, m as teardownParkedIosSim, p as teardownParkedAvd, v as isLegacyDeletionClaim, x as selectParked, y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
14
- import { E as configuredIosSimulatorViewer, O as hostMemoryPressureAdvice, S as resolveOwnedIosSim, b as resetIosPrivacy, c as iosSimulatorFailureAdvice, d as listIosDeviceTypes, g as parseRuntimeVersion, k as readHostMemoryPressure, l as listAllIosSims, m as ownedSimName, n as bootIosSim, r as createOwnedIosSim, v as renameIosSim, x as resolveIosCreation, y as resetIosKeychain } from "./ios-DArbmwer.mjs";
15
- import { o as estimateBuild } from "./build-progress-CDwogz6R.mjs";
16
- import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-o6H5gcBc.mjs";
17
- import { N as easAuthNote } from "./device-remote-BQZSnnmE.mjs";
18
- import { r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING } from "./launch-verify-CuPDGXdr.mjs";
19
- import { a as liveOwnedDeviceCount, i as deviceTypeMismatch, t as reconcileSimSlim } from "./simslim-CIR3IYJO.mjs";
20
- import { s as startDevServer } from "./start-BSsf2tUs.mjs";
21
- import { r as readStats } from "./stats-BAgJaLA4.mjs";
22
- import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B5SPD--o.mjs";
9
+ import { i as formatDuration, l as phaseLine, m as shortHash, u as plural } from "./command-output-BWCj5Vh-.mjs";
10
+ import { N as storedSources, S as entryDir, x as diffFingerprintSources, y as artifactIn } from "./device-lease-B9LAXIUH.mjs";
11
+ import { B as pickDefaultSystemImage, C as getAvdNameForSerial, E as listAdbDevices, F as ownedAvdMatchesConfiguration, I as ownedAvdName, M as nextConsolePort, N as ownedAvdDeviceProfile, O as listAvds, R as ownedAvdSystemImage, W as resolveOwnedAvdSerial, X as waitForBoot, _ as createOwnedAvd, d as assertOwnedAvdStopped, g as configureNewOwnedAvd, h as bootAndroidEmulator, k as listInstalledSystemImages, n as OWNED_AVD_CONFIG_DEFAULTS, p as avdPoolConfiguration, t as DEFAULT_AVD_DEVICE_PROFILE } from "./android-75Sk2rIR.mjs";
12
+ import { l as androidDataPartitionSizeGbSetting, o as androidAvdConfigSetting, v as iosSimSlimProfileSetting } from "./settings-BlyDn2Oz.mjs";
13
+ import { _ as dropParked, b as readParked, d as teardownOwnedAvd, g as adoptParked, m as teardownParkedIosSim, p as teardownParkedAvd, v as isLegacyDeletionClaim, x as selectParked, y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
14
+ import { E as configuredIosSimulatorViewer, O as hostMemoryPressureAdvice, S as resolveOwnedIosSim, b as resetIosPrivacy, c as iosSimulatorFailureAdvice, d as listIosDeviceTypes, g as parseRuntimeVersion, k as readHostMemoryPressure, l as listAllIosSims, m as ownedSimName, n as bootIosSim, r as createOwnedIosSim, v as renameIosSim, x as resolveIosCreation, y as resetIosKeychain } from "./ios-CZWOHTTc.mjs";
15
+ import { o as estimateBuild } from "./build-progress-h60GPV27.mjs";
16
+ import { i as expoBinRefusal, r as expoBinPath, t as cleanLine } from "./server-expo-CeT1nIIk.mjs";
17
+ import { a as easAuthNote } from "./remote-cache-BRsRZru5.mjs";
18
+ import { r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING } from "./launch-verify-B2oR_kFN.mjs";
19
+ import { a as liveOwnedDeviceCount, i as deviceTypeMismatch, t as reconcileSimSlim } from "./simslim-COtEEP7x.mjs";
20
+ import { s as startDevServer } from "./start-BboE1HIS.mjs";
21
+ import { r as readStats } from "./stats-D8rUTPHd.mjs";
22
+ import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-BzplpQzc.mjs";
23
23
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync } from "node:fs";
24
24
  import { LAST_BUILD_KEYS, isJsonObject, loadConfig, readIdleStop, readJsonObject, readWorkspaceState } from "@stim-cli/core/state";
25
25
  import { basename, dirname, join, relative } from "node:path";
@@ -641,7 +641,10 @@ async function prepareOwnedAvd({ projectPath, slot, label, previousAvdName, syst
641
641
  avdName,
642
642
  owned: true,
643
643
  deviceName: avdName,
644
- ...prepared.created ? { poolConfiguration: configuration } : {},
644
+ ...prepared.created ? {
645
+ poolConfiguration: configuration,
646
+ bootPending: true
647
+ } : {},
645
648
  ...prepared.consolePort ? { consolePort: prepared.consolePort } : {}
646
649
  }, slot);
647
650
  });
@@ -676,10 +679,13 @@ async function prepareOwnedAvd({ projectPath, slot, label, previousAvdName, syst
676
679
  const ANDROID_FRESH_BOOT_TIMEOUT_MS = process.platform === "win32" ? 12e5 : 12e4;
677
680
  const ANDROID_BOOT_TIMEOUT_MS = process.platform === "win32" ? 12e5 : 24e4;
678
681
  async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoot, label, settings, flags, note, out, logFile, alive, configureAvd, teardownAvd }) {
679
- const avdConfig = androidAvdConfigSetting(settings, settingsRoot);
682
+ const projectAvdConfig = androidAvdConfigSetting(settings, settingsRoot);
683
+ const avdConfig = {
684
+ ...OWNED_AVD_CONFIG_DEFAULTS,
685
+ ...projectAvdConfig
686
+ };
680
687
  const requestedProfile = flags.deviceProfile || settings.android?.deviceProfile || null;
681
- const deviceProfile = requestedProfile ?? DEFAULT_AVD_DEVICE_PROFILE;
682
- const configuration = avdPoolConfiguration(androidDataPartitionSizeGbSetting(settings), avdConfig, deviceProfile);
688
+ let replacedProfile = null;
683
689
  if (record?.setupIncomplete && record.avdName) {
684
690
  const avdName = record.avdName;
685
691
  const cleanup = teardownAvd(avdName, {
@@ -696,6 +702,30 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
696
702
  if (cleanup.status === "failed" || cleanup.status === "skipped") throw new AvdRecoveryError(`Owned AVD ${record.avdName} has incomplete setup and could not be deleted (${cleanup.reason || cleanup.status}). Fix the cause, then retry; Stim kept the device record for cleanup.`, "Wait for any active AVD operation to finish. If the refusal names an unresolved claim, inspect its creator and native processes before removing only that claim. Retry `stim android` to reconcile the incomplete device.");
697
703
  record = null;
698
704
  }
705
+ const requestedImage = flags.systemImageFlag || null;
706
+ const currentImage = requestedImage && record?.owned && record.avdName ? ownedAvdSystemImage(record.avdName) : null;
707
+ if (record?.avdName && requestedImage && currentImage && currentImage !== requestedImage) {
708
+ const avdName = record.avdName;
709
+ if (!record.bootPending) throw new AvdRecoveryError(`this project's emulator ${avdName} uses system image ${currentImage}, but ${requestedImage} was requested. --system-image replaces only an emulator that never finished a boot, and this one has.`, "Run `stim worktree remove` (or `stim gc --delete`) to reap the current emulator, then `stim android` again to create the requested one, or pass `--slot <name>` to create it beside the current one.");
710
+ replacedProfile = ownedAvdDeviceProfile(avdName);
711
+ const cleanup = teardownAvd(avdName, {
712
+ del: true,
713
+ owner: {
714
+ projectPath,
715
+ slot,
716
+ expectedRecord: record
717
+ },
718
+ onRemoved: () => {
719
+ clearDevice(projectPath, "android", slot, avdName);
720
+ }
721
+ });
722
+ if (cleanup.status === "failed" || cleanup.status === "skipped") throw new AvdRecoveryError(`Owned AVD ${avdName} never finished a boot, but could not be deleted to create one on ${requestedImage} (${cleanup.reason || cleanup.status}). Stim kept the device record.`, "Fix the cause, then retry, or pass `--slot <name>` to create the requested emulator beside it.");
723
+ out(phaseLine("device", `deleted ${avdName}, which never finished a boot, to create one on ${requestedImage}`));
724
+ record = null;
725
+ }
726
+ const deviceProfile = requestedProfile ?? replacedProfile ?? DEFAULT_AVD_DEVICE_PROFILE;
727
+ const configuration = avdPoolConfiguration(androidDataPartitionSizeGbSetting(settings), avdConfig, deviceProfile);
728
+ const configurationBeforeDefaults = avdPoolConfiguration(androidDataPartitionSizeGbSetting(settings), projectAvdConfig, deviceProfile);
699
729
  if (record?.avdName) {
700
730
  if (record.owned) {
701
731
  const resolved = resolveOwnedAvdSerial(record.avdName);
@@ -748,7 +778,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
748
778
  }
749
779
  if (parkedMaxSetting("android").max > 0) {
750
780
  const systemImage = pickDefaultSystemImage(listInstalledSystemImages(), { systemImage: flags.systemImage || settings.android?.systemImage })?.pkg;
751
- const candidates = readParked("android").filter((entry) => entry.systemImage === systemImage && entry.configuration === configuration).toSorted((a, b) => a.parkedAt.localeCompare(b.parkedAt));
781
+ const candidates = readParked("android").filter((entry) => entry.systemImage === systemImage && (entry.configuration === configuration || entry.configuration === configurationBeforeDefaults)).toSorted((a, b) => a.parkedAt.localeCompare(b.parkedAt));
752
782
  for (const parked of candidates) {
753
783
  if (isLegacyDeletionClaim(parked.deletionClaim)) continue;
754
784
  const resolved = resolveOwnedAvdSerial(parked.name);
@@ -764,7 +794,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
764
794
  out(phaseLine("device", `kept parked ${parked.name}: ${String(error?.message || error)}`));
765
795
  continue;
766
796
  }
767
- if (ownedAvdSystemImage(parked.name) !== systemImage || !ownedAvdMatchesConfiguration(parked.name, configuration)) {
797
+ if (ownedAvdSystemImage(parked.name) !== systemImage || !ownedAvdMatchesConfiguration(parked.name, parked.configuration)) {
768
798
  const result = teardownParkedAvd(parked.name);
769
799
  if (result.status === "failed") out(phaseLine("device", `kept ${parked.name}: ${result.reason}`));
770
800
  continue;
@@ -773,7 +803,7 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
773
803
  avdName: parked.name,
774
804
  deviceName: parked.name,
775
805
  owned: true,
776
- poolConfiguration: configuration,
806
+ poolConfiguration: parked.configuration,
777
807
  adoptionPending: true
778
808
  };
779
809
  if (!adoptParked({
@@ -783,6 +813,15 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
783
813
  udid: parked.udid,
784
814
  device: adopted
785
815
  })) continue;
816
+ if (parked.configuration !== configuration) try {
817
+ configureAvd(parked.name, {
818
+ dataPartitionSizeGb: androidDataPartitionSizeGbSetting(settings),
819
+ avdConfig
820
+ });
821
+ adopted.poolConfiguration = configuration;
822
+ } catch (error) {
823
+ out(phaseLine("device", `${parked.name} keeps its old AVD settings: ${String(error?.message || error)}`));
824
+ }
786
825
  return {
787
826
  ...await bootOwnedAvdOnFreshPort({
788
827
  avdName: parked.name,
@@ -824,7 +863,10 @@ async function ensureOwnedAndroidDevice({ record, projectPath, slot, settingsRoo
824
863
  return {
825
864
  ...await bootOwnedAvdOnFreshPort({
826
865
  avdName: created.avdName,
827
- metadata: created.created ? { poolConfiguration: configuration } : void 0,
866
+ metadata: created.created ? {
867
+ poolConfiguration: configuration,
868
+ bootPending: true
869
+ } : void 0,
828
870
  projectPath,
829
871
  slot,
830
872
  deviceName: created.avdName,
@@ -843,6 +885,7 @@ function claimAndroidConsolePort({ projectPath, slot, avdName, deviceName, liveP
843
885
  const claim = {
844
886
  ...metadata?.poolConfiguration ? { poolConfiguration: metadata.poolConfiguration } : {},
845
887
  ...metadata?.adoptionPending ? { adoptionPending: true } : {},
888
+ ...metadata?.bootPending ? { bootPending: true } : {},
846
889
  avdName,
847
890
  consolePort,
848
891
  owned: true,
@@ -880,8 +923,10 @@ async function bootOwnedAvdOnFreshPort({ avdName, metadata, projectPath, slot, d
880
923
  if (result.failed) throw new AvdBootError(result.reason, result.remedy);
881
924
  const running = getAvdNameForSerial(serial);
882
925
  if (running && running !== avdName) throw new Error(`${serial} is running AVD ${running}, not this workspace's owned AVD ${avdName}; refusing to use it.`);
926
+ clearAndroidBootPending(projectPath, avdName, slot);
927
+ const { bootPending: _booted, ...booted } = claim;
883
928
  return {
884
- ...claim,
929
+ ...booted,
885
930
  serial
886
931
  };
887
932
  } catch (error) {
@@ -960,17 +1005,22 @@ async function ensureAndroidBooted({ device, projectPath, slot, timeoutMs, out,
960
1005
  failed: true,
961
1006
  reason: `AVD ${device.avdName} is not Stim-owned by name; refusing to boot it.`
962
1007
  };
963
- if (resolved.serial) return waitForAndroidBoot({
1008
+ const avdName = device.avdName;
1009
+ const booted = (result) => {
1010
+ if (!result.failed) clearAndroidBootPending(projectPath, avdName, slot);
1011
+ return result;
1012
+ };
1013
+ if (resolved.serial) return booted(await waitForAndroidBoot({
964
1014
  serial: resolved.serial,
965
1015
  timeoutMs,
966
1016
  out
967
- });
1017
+ }));
968
1018
  const freshSerial = `emulator-${device.consolePort}`;
969
- if (device.owned && device.serial === freshSerial) return waitForAndroidBoot({
1019
+ if (device.owned && device.serial === freshSerial) return booted(await waitForAndroidBoot({
970
1020
  serial: freshSerial,
971
1021
  timeoutMs,
972
1022
  out
973
- });
1023
+ }));
974
1024
  const claim = claimAndroidConsolePort({
975
1025
  projectPath,
976
1026
  slot,
@@ -1000,7 +1050,7 @@ async function ensureAndroidBooted({ device, projectPath, slot, timeoutMs, out,
1000
1050
  out
1001
1051
  });
1002
1052
  if (result.failed) releaseAndroidConsolePort(projectPath, claim.consolePort, slot);
1003
- return result;
1053
+ return booted(result);
1004
1054
  }
1005
1055
  //#endregion
1006
1056
  //#region src/engine/device.ts
@@ -1776,6 +1826,28 @@ function explainBuildMiss({ root, platform, current, rekeyedBy = [], baselineDep
1776
1826
  previousHash: baseline?.fingerprint ?? null
1777
1827
  };
1778
1828
  }
1829
+ function predictBuildMiss({ root, platform, current, prebuild }) {
1830
+ const { reason } = explainBuildMiss({
1831
+ root,
1832
+ platform,
1833
+ current
1834
+ });
1835
+ const baseline = reason.baseline && {
1836
+ fingerprint: reason.baseline.fingerprint,
1837
+ from: reason.baseline.from
1838
+ };
1839
+ if (!prebuild || !baseline) return {
1840
+ ...reason,
1841
+ baseline
1842
+ };
1843
+ const dir = platform === "ios" ? "ios/" : "android/";
1844
+ return {
1845
+ ...reason,
1846
+ kind: "prebuild-pending",
1847
+ summary: `${reason.summary} (before prebuild ${prebuild}s ${dir})`,
1848
+ baseline
1849
+ };
1850
+ }
1779
1851
  function skippedMissReason(summary) {
1780
1852
  return {
1781
1853
  kind: "cache-skipped",
@@ -1887,6 +1959,7 @@ async function planCachedBuild(lookup, deps) {
1887
1959
  }
1888
1960
  let prebuild = null;
1889
1961
  let refusal = null;
1962
+ let missReason;
1890
1963
  if (!cacheHit) {
1891
1964
  prebuild = deps.planPrebuild(root, platform, {
1892
1965
  isExpo,
@@ -1894,6 +1967,15 @@ async function planCachedBuild(lookup, deps) {
1894
1967
  sources
1895
1968
  });
1896
1969
  if (prebuild === "refuse") refusal = staleNativeDirRefusal(platform);
1970
+ else if (cachePolicy.read) missReason = predictBuildMiss({
1971
+ root,
1972
+ platform,
1973
+ current: {
1974
+ hash: fingerprint,
1975
+ sources
1976
+ },
1977
+ prebuild: prebuild === "generate" || prebuild === "regenerate" ? prebuild : null
1978
+ });
1897
1979
  }
1898
1980
  return planPayload(lookup, {
1899
1981
  fingerprint,
@@ -1902,11 +1984,12 @@ async function planCachedBuild(lookup, deps) {
1902
1984
  provider,
1903
1985
  cacheSkipped: !cachePolicy.read,
1904
1986
  prebuild,
1987
+ ...missReason ? { missReason } : {},
1905
1988
  refusal
1906
1989
  });
1907
1990
  }
1908
1991
  function planPayload({ platform, slot, projectKey }, found) {
1909
- const { refusal, ...rest } = found;
1992
+ const { refusal, missReason, ...rest } = found;
1910
1993
  const outcome = refusal ? null : found.cacheHit ? "hit" : "cold";
1911
1994
  const estimate = outcome ? estimateBuild(readStats().record?.history?.[projectKey], platform, outcome, "prepare") : {
1912
1995
  expectedMs: null,
@@ -1919,6 +2002,7 @@ function planPayload({ platform, slot, projectKey }, found) {
1919
2002
  outcome,
1920
2003
  expectedMs: estimate.expectedMs,
1921
2004
  basis: estimate.basis,
2005
+ ...missReason ? { missReason } : {},
1922
2006
  ...refusal ? { refusal } : {}
1923
2007
  };
1924
2008
  }
@@ -1935,6 +2019,7 @@ function printPlan(plan, json) {
1935
2019
  }
1936
2020
  const slot = plan.slot ? ` [${plan.slot}]` : "";
1937
2021
  console.log(phaseLine("plan", `${plan.platform}${slot} ${shortHash(plan.fingerprint)} -> ${cacheLine(plan)}`));
2022
+ if (plan.missReason) console.log(phaseLine("cache", `miss: ${plan.missReason.summary}`));
1938
2023
  if (plan.refusal) {
1939
2024
  console.log(phaseLine("error", plan.refusal.message));
1940
2025
  console.log(phaseLine("remedy", plan.refusal.remedy));
@@ -1,6 +1,6 @@
1
- import { k as ownership_claim_exports } from "./config-BEq0Qw_a.mjs";
2
- import { f as clearWorkspaceStateKey, g as updateWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
3
- import { a as formatElapsed, u as plural } from "./command-output-D5z2_bcF.mjs";
1
+ import { A as ownership_claim_exports } from "./config-0jCcMM0E.mjs";
2
+ import { f as clearWorkspaceStateKey, g as updateWorkspaceState } from "./metro-Dzo30hvJ.mjs";
3
+ import { a as formatElapsed, u as plural } from "./command-output-BWCj5Vh-.mjs";
4
4
  import { BUILD_PHASES } from "@stim-cli/core/state";
5
5
  //#region src/engine/build-progress.ts
6
6
  const ACTIVE_BUILD_KEY = "activeBuild";
@@ -1,4 +1,4 @@
1
- import { u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { existsSync } from "fs";
3
3
  import { isAbsolute, join, resolve } from "path";
4
4
  import { readCacheManifest, updateCacheManifest } from "@stim-cli/core";
@@ -1,2 +1,2 @@
1
- import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-Pubfp8wV.mjs";
1
+ import { a as unregister, i as registeredCaches, n as readManifest, r as register, t as manifestPath } from "./cache-manifest-DWPF4RKJ.mjs";
2
2
  export { manifestPath, readManifest, register, registeredCaches, unregister };
package/dist/cli.mjs CHANGED
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import { _ as refuseRelativeStimPaths } from "./config-BEq0Qw_a.mjs";
2
+ import { v as refuseRelativeStimPaths } from "./config-0jCcMM0E.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { Command } from "commander";
5
5
  //#region bin/cli.ts
6
6
  const commands = /* @__PURE__ */ new Map([
7
- ["doctor", () => import("./doctor-D8QdMRMf.mjs")],
8
- ["worktree", () => import("./worktree-DhxDTK44.mjs")],
9
- ["start", () => import("./start-i8zc9VmS.mjs")],
10
- ["ports", () => import("./ports-DwBaRFJs.mjs")],
11
- ["stop", () => import("./stop-rst5mL14.mjs")],
12
- ["ios", () => import("./ios-CQLKpNfr.mjs")],
13
- ["android", () => import("./android-C1q4l523.mjs")],
14
- ["reload", () => import("./reload-By9Dwsrt.mjs")],
15
- ["device", () => import("./device-BwH2iI3O.mjs")],
16
- ["logs", () => import("./logs-B44a1UeU.mjs")],
17
- ["settings", () => import("./settings-C0ugALSC.mjs")],
18
- ["status", () => import("./status-CitcBRsC.mjs")],
19
- ["stats", () => import("./stats-DBYJ5bxL.mjs")],
20
- ["gc", () => import("./gc-COZteyiq.mjs")],
21
- ["guide", () => import("./guide-NDvTmMi-.mjs")]
7
+ ["doctor", () => import("./doctor-LfDlbR-N.mjs")],
8
+ ["worktree", () => import("./worktree-B5sTRskL.mjs")],
9
+ ["start", () => import("./start-BFstVBlx.mjs")],
10
+ ["ports", () => import("./ports-Dp_QTwTC.mjs")],
11
+ ["stop", () => import("./stop-BI7QY76M.mjs")],
12
+ ["ios", () => import("./ios-CDzWL1mj.mjs")],
13
+ ["android", () => import("./android-B7X-8H7h.mjs")],
14
+ ["reload", () => import("./reload-nocmx8KB.mjs")],
15
+ ["device", () => import("./device-9r9xRYDa.mjs")],
16
+ ["logs", () => import("./logs-SzuYudOj.mjs")],
17
+ ["settings", () => import("./settings-bE-Gu3Ti.mjs")],
18
+ ["status", () => import("./status-DI9Tjo7T.mjs")],
19
+ ["stats", () => import("./stats-DiCtmluY.mjs")],
20
+ ["gc", () => import("./gc-C4nQFcTX.mjs")],
21
+ ["guide", () => import("./guide-BPBlh9ML.mjs")]
22
22
  ]);
23
23
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
24
24
  const program = new Command();
@@ -1,11 +1,11 @@
1
- import { D as process_identity_exports, R as deviceSlotKey, W as validateDeviceSlot } from "./config-BEq0Qw_a.mjs";
1
+ import { G as validateDeviceSlot, O as process_identity_exports, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
4
- import { j as workspaceLogsDir } from "./metro-BWLOJ_Wr.mjs";
4
+ import { j as workspaceLogsDir } from "./metro-Dzo30hvJ.mjs";
5
5
  import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
6
6
  import { a as startIosDeviceConsole, i as parseDeviceConsoleLine } from "./ios-device-BiOsSVzd.mjs";
7
- import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-D2xbLVoz.mjs";
8
- import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-BA2i_KAV.mjs";
7
+ import { a as unregisterCollector, i as registerCollector, r as readCollectors, t as collectorProcessTitle } from "./ownership-Dqnrjrio.mjs";
8
+ import { a as watchAppPid, i as waitForAppPid, n as parseLogcatLine, r as startAndroidLogcat, t as androidClockOffset } from "./android-BQiKJYK0.mjs";
9
9
  import { existsSync } from "node:fs";
10
10
  import { LOG_ROTATE_BYTES } from "@stim-cli/core";
11
11
  import { isAbsolute, join, resolve } from "node:path";
@@ -1,4 +1,4 @@
1
- import { t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
1
+ import { t as NO_PROJECT_REFUSAL } from "./project-B8rbutVC.mjs";
2
2
  import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
3
3
  import { quotedPath } from "@stim-cli/core";
4
4
  import chalk from "chalk";
@@ -379,6 +379,15 @@ function releaseAndroidConsolePort(projectPath, consolePort, slot = "default") {
379
379
  return true;
380
380
  });
381
381
  }
382
+ function clearAndroidBootPending(projectPath, avdName, slot = "default") {
383
+ withConfigLock(() => {
384
+ const cfg = loadConfig();
385
+ const android = deviceSlotPlatforms(cfg?.projects?.[projectPath], slot)?.android;
386
+ if (!cfg || android?.avdName !== avdName || !android.bootPending) return;
387
+ delete android.bootPending;
388
+ saveConfig(cfg);
389
+ });
390
+ }
382
391
  function clearDevice(projectPath, platform, slot = "default", expectedId) {
383
392
  return withConfigLock(() => {
384
393
  const cfg = loadConfig();
@@ -512,4 +521,4 @@ function allConsolePortsAndSerials({ isMounted = isOnMountedVolume } = {}) {
512
521
  return result;
513
522
  }
514
523
  //#endregion
515
- export { directorySize as A, parseDeviceSlotKey as B, setSupervisor as C, process_identity_exports as D, writeConfigSetting as E, volumeRootFor as F, projectDeviceSlots as H, assignSlotDevice as I, deviceSlotFileKey as L, isOnMountedVolume as M, listMountedVolumes as N, acquireAvdClaim as O, measuredDirectorySize as P, deviceSlotKey as R, setDevice as S, withConfigLock$1 as T, removeSlotDevice as U, parseDeviceSlotOption as V, validateDeviceSlot as W, refuseRelativeStimPaths as _, clearSupervisor as a, removeProject as b, findEnclosingWorktreeRoot as c, getConfigPath$1 as d, getProject as f, loadConfig$1 as g, isPathPrefix as h, clearDevice as i, formatBytes as j, ownership_claim_exports as k, getConcurrencyLimits as l, getRepoSettings as m, allMetroPorts as n, configCorruptRepair as o, getProjectSettings as p, claimMetroPort as r, ensureConfig as s, allConsolePortsAndSerials as t, getConfigDir as u, releaseAndroidConsolePort as v, upsertProject as w, saveConfig as x, releaseMetroPort as y, deviceSlotPlatforms as z };
524
+ export { ownership_claim_exports as A, deviceSlotPlatforms as B, setDevice as C, writeConfigSetting as D, withConfigLock$1 as E, measuredDirectorySize as F, validateDeviceSlot as G, parseDeviceSlotOption as H, volumeRootFor as I, assignSlotDevice as L, formatBytes as M, isOnMountedVolume as N, process_identity_exports as O, listMountedVolumes as P, deviceSlotFileKey as R, saveConfig as S, upsertProject as T, projectDeviceSlots as U, parseDeviceSlotKey as V, removeSlotDevice as W, loadConfig$1 as _, clearDevice as a, releaseMetroPort as b, ensureConfig as c, getConfigDir as d, getConfigPath$1 as f, isPathPrefix as g, getRepoSettings as h, clearAndroidBootPending as i, directorySize as j, acquireAvdClaim as k, findEnclosingWorktreeRoot as l, getProjectSettings as m, allMetroPorts as n, clearSupervisor as o, getProject as p, claimMetroPort as r, configCorruptRepair as s, allConsolePortsAndSerials as t, getConcurrencyLimits as u, refuseRelativeStimPaths as v, setSupervisor as w, removeProject as x, releaseAndroidConsolePort as y, deviceSlotKey as z };
@@ -1,5 +1,5 @@
1
1
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { y as repoRoot } from "./worktree-BlizKDpZ.mjs";
2
+ import { y as repoRoot } from "./worktree-DeBQSVtR.mjs";
3
3
  import { existsSync } from "node:fs";
4
4
  import { dirname, join, relative } from "node:path";
5
5
  //#region src/dependency-state.ts
@@ -1,7 +1,7 @@
1
1
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { a as spawnDeclared } from "./spawn-claims-BJwXTMPt.mjs";
2
+ import { a as spawnDeclared } from "./spawn-claims-PT8aQpCa.mjs";
3
3
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { d as startBuildHeartbeat, m as bundlerPin, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B5SPD--o.mjs";
4
+ import { d as startBuildHeartbeat, m as bundlerPin, n as HEARTBEAT_INTERVAL_MS } from "./xcode-BzplpQzc.mjs";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import { delimiter, dirname, join, relative, resolve, sep } from "node:path";
7
7
  import { homedir } from "node:os";
@@ -1,10 +1,10 @@
1
- import { H as projectDeviceSlots, R as deviceSlotKey, V as parseDeviceSlotOption, f as getProject } from "./config-BEq0Qw_a.mjs";
2
- import { o as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
3
- import { r as clockTime } from "./command-output-D5z2_bcF.mjs";
4
- import { n as fileLeaseIo, o as parseLeaseDuration, p as takeLease, u as releaseWorkspaceLeases } from "./device-lease-D83nqeMX.mjs";
5
- import { A as memoizeEmulatorProbe, B as probeEmulatorSerial, R as physicalDeviceModel, S as getAvdNameForSerial, T as listAdbDevices, U as resolvePhysicalDevice, a as androidPoolCandidates, o as androidPoolNoCandidatesRefusal } from "./android-C4zG2Tuc.mjs";
6
- import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-DHj7cdPy.mjs";
7
- import { a as iosPoolCandidates, c as listIosDevices, o as iosPoolNoCandidatesRefusal, s as isWirelessIosDevice, u as resolveIosPhysicalDevice } from "./ios-device-CwDZo0X4.mjs";
1
+ import { H as parseDeviceSlotOption, U as projectDeviceSlots, p as getProject, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
+ import { i as findProjectRoot, t as NO_PROJECT_REFUSAL } from "./project-B8rbutVC.mjs";
3
+ import { r as clockTime } from "./command-output-BWCj5Vh-.mjs";
4
+ import { n as fileLeaseIo, o as parseLeaseDuration, p as takeLease, u as releaseWorkspaceLeases } from "./device-lease-B9LAXIUH.mjs";
5
+ import { C as getAvdNameForSerial, E as listAdbDevices, G as resolvePhysicalDevice, V as probeEmulatorSerial, j as memoizeEmulatorProbe, o as androidPoolCandidates, s as androidPoolNoCandidatesRefusal, z as physicalDeviceModel } from "./android-75Sk2rIR.mjs";
6
+ import { d as waitForDevice, s as parseDeviceWait, t as selectFromPool } from "./device-pool-BoezJd-c.mjs";
7
+ import { a as iosPoolCandidates, c as listIosDevices, o as iosPoolNoCandidatesRefusal, s as isWirelessIosDevice, u as resolveIosPhysicalDevice } from "./ios-device-D9cLxVr5.mjs";
8
8
  import chalk from "chalk";
9
9
  //#region src/commands/device.ts
10
10
  const DEFAULT_FOR = "5m";
@@ -1,9 +1,9 @@
1
- import { B as parseDeviceSlotKey, R as deviceSlotKey, W as validateDeviceSlot, k as ownership_claim_exports, u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, G as validateDeviceSlot, V as parseDeviceSlotKey, d as getConfigDir, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { r as register } from "./cache-manifest-Pubfp8wV.mjs";
4
- import { P as withDirLock, S as sharedBuildCache, _ as withWorkspaceStateLock, m as readWorkspaceState, p as clearWorkspaceStateKeys, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
5
- import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-BJwXTMPt.mjs";
6
- import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-D5z2_bcF.mjs";
3
+ import { r as register } from "./cache-manifest-DWPF4RKJ.mjs";
4
+ import { P as withDirLock, S as sharedBuildCache, _ as withWorkspaceStateLock, m as readWorkspaceState, p as clearWorkspaceStateKeys, y as writeWorkspaceState } from "./metro-Dzo30hvJ.mjs";
5
+ import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-PT8aQpCa.mjs";
6
+ import { a as formatElapsed, i as formatDuration, m as shortHash } from "./command-output-BWCj5Vh-.mjs";
7
7
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
8
  import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
9
9
  import { join } from "path";
@@ -1,7 +1,7 @@
1
- import { R as deviceSlotKey } from "./config-BEq0Qw_a.mjs";
2
- import { a as formatElapsed, r as clockTime } from "./command-output-D5z2_bcF.mjs";
3
- import { a as parseLease, c as raiseLease, f as selectPoolDevice, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-D83nqeMX.mjs";
4
- import { a as VERIFY_TIMEOUT_MS, p as APP_READINESS_TIMEOUT_MS } from "./launch-verify-CuPDGXdr.mjs";
1
+ import { z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
+ import { a as formatElapsed, r as clockTime } from "./command-output-BWCj5Vh-.mjs";
3
+ import { a as parseLease, c as raiseLease, f as selectPoolDevice, l as releaseRunLease, n as fileLeaseIo, p as takeLease, r as leaseIsExpired, t as deviceLeasePath } from "./device-lease-B9LAXIUH.mjs";
4
+ import { a as VERIFY_TIMEOUT_MS, p as APP_READINESS_TIMEOUT_MS } from "./launch-verify-B2oR_kFN.mjs";
5
5
  //#region src/engine/device-lease-run.ts
6
6
  const LEASE_STEP_FLOOR_MS = 6e4;
7
7
  const DEBUG_VERIFY_STEP_MS = VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;