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,23 +1,24 @@
1
- import { g as loadConfig$1, l as getConcurrencyLimits, o as configCorruptRepair } from "./config-BEq0Qw_a.mjs";
1
+ import { _ as loadConfig$1, s as configCorruptRepair, u as getConcurrencyLimits } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { D as workspaceDerivedData, S as sharedBuildCache } from "./metro-BWLOJ_Wr.mjs";
4
- import { D as makeTemporaryDirectory, E as filesystemDevice, a as dirtyFingerprintFiles, h as locallyKnownUpstream, k as temporaryRoot, m as listWorktrees, s as gitCommonDir, x as resolveSourceCheckout, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
5
- import { a as detectIsExpo, n as appProjectProblem, o as findProjectRoot } from "./project-BXZzOABt.mjs";
6
- import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-D5z2_bcF.mjs";
7
- import { T as fingerprintProject, h as listBuildLocks, x as diffFingerprintSources } from "./device-lease-D83nqeMX.mjs";
8
- import { C as hostSystemImageArch, T as listAdbDevices } from "./android-C4zG2Tuc.mjs";
9
- import { F as settingsLayers, H as compilerCacheFallbackMessage, L as unknownSettingKeys, N as settingOrigin, O as remoteAndroidSetting, P as settingShapeErrors, T as projectOptimizations, W as resolveOptimizations, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, j as resolveSettings, k as remoteIosSetting, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, y as mergeSettingsLayers } from "./settings-B5oFZEri.mjs";
10
- import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
11
- import { O as hostMemoryPressureAdvice, k as readHostMemoryPressure, l as listAllIosSims } from "./ios-DArbmwer.mjs";
12
- import { o as listBuildSlots } from "./in-use-DVhlSoyn.mjs";
13
- import { L as ownerFromConfig, M as checkEasAuth$1, R as providerFromConfig, _ as easCliSupport, g as MIN_EAS_CLI_SIMULATOR_VERSION, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
3
+ import { D as workspaceDerivedData, S as sharedBuildCache } from "./metro-Dzo30hvJ.mjs";
4
+ import { D as makeTemporaryDirectory, E as filesystemDevice, a as dirtyFingerprintFiles, h as locallyKnownUpstream, k as temporaryRoot, m as listWorktrees, s as gitCommonDir, x as resolveSourceCheckout, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
5
+ import { i as findProjectRoot, n as appProjectProblem, r as detectIsExpo } from "./project-B8rbutVC.mjs";
6
+ import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-BWCj5Vh-.mjs";
7
+ import { T as fingerprintProject, h as listBuildLocks, x as diffFingerprintSources } from "./device-lease-B9LAXIUH.mjs";
8
+ import { E as listAdbDevices, w as hostSystemImageArch } from "./android-75Sk2rIR.mjs";
9
+ import { F as settingsLayers, H as compilerCacheFallbackMessage, L as unknownSettingKeys, N as settingOrigin, O as remoteAndroidSetting, P as settingShapeErrors, T as projectOptimizations, W as resolveOptimizations, a as SETTING_SHAPE_REMEDY, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, j as resolveSettings, k as remoteIosSetting, n as PATH_SETTINGS, v as iosSimSlimProfileSetting, y as mergeSettingsLayers } from "./settings-BlyDn2Oz.mjs";
10
+ import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
11
+ import { O as hostMemoryPressureAdvice, k as readHostMemoryPressure, l as listAllIosSims } from "./ios-CZWOHTTc.mjs";
12
+ import { o as listBuildSlots } from "./in-use-D9XYEgFD.mjs";
13
+ import { f as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig } from "./remote-cache-BRsRZru5.mjs";
14
+ import { D as MIN_EAS_CLI_SIMULATOR_VERSION, O as easCliSupport, k as easCliUpgradeRemedy, s as readInstalledEasCliVersion } from "./device-remote-C0_o-tJH.mjs";
14
15
  import { n as inspectStimVersions, t as compareStimVersions } from "./stim-installations-CINXy_su.mjs";
15
- import { a as liveOwnedDeviceCount, n as simslimIsOnPath, u as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-CIR3IYJO.mjs";
16
- import { n as budgetLine, r as inspectBudget } from "./budget-De3P2rq_.mjs";
17
- import { d as projectCmakeLauncher, g as androidPathRoomRemedy, h as androidPathRoomMessage, i as apkOutputsDir, m as androidPathRoom, r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-DfJkwCXW.mjs";
18
- import { h as podInstallCommand, i as ccacheEnabled, o as detectXcodeMajor } from "./xcode-B5SPD--o.mjs";
19
- import { n as recordDoctorRun } from "./guide-status-CWvti2Lg.mjs";
20
- import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-r9UesA9a.mjs";
16
+ import { a as liveOwnedDeviceCount, n as simslimIsOnPath, u as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-COtEEP7x.mjs";
17
+ import { n as budgetLine, r as inspectBudget } from "./budget-DbzW5VTD.mjs";
18
+ import { d as projectCmakeLauncher, g as androidPathRoomRemedy, h as androidPathRoomMessage, i as apkOutputsDir, m as androidPathRoom, r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-DzLPXiEn.mjs";
19
+ import { h as podInstallCommand, i as ccacheEnabled, o as detectXcodeMajor } from "./xcode-BzplpQzc.mjs";
20
+ import { n as recordDoctorRun } from "./guide-status-i9ogHt4v.mjs";
21
+ import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-DNN0yfx6.mjs";
21
22
  import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
22
23
  import { InvalidArgumentError } from "commander";
23
24
  import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
@@ -1,12 +1,12 @@
1
- import { R as deviceSlotKey, f as getProject, z as deviceSlotPlatforms } from "./config-BEq0Qw_a.mjs";
1
+ import { B as deviceSlotPlatforms, p as getProject, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { P as withDirLock, m as readWorkspaceState$1, s as resolveProjectMetro } from "./metro-BWLOJ_Wr.mjs";
4
- import { d as readWorkspaceLaunches } from "./state-WGdIbi_d.mjs";
5
- import { v as launchErrorPreview } from "./command-output-D5z2_bcF.mjs";
6
- import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-D83nqeMX.mjs";
7
- import { c as androidToolCwd, i as androidHome } from "./android-C4zG2Tuc.mjs";
3
+ import { P as withDirLock, m as readWorkspaceState$1, s as resolveProjectMetro } from "./metro-Dzo30hvJ.mjs";
4
+ import { f as readWorkspaceLaunches } from "./state-DcDgzfu3.mjs";
5
+ import { v as launchErrorPreview } from "./command-output-BWCj5Vh-.mjs";
6
+ import { a as parseLease, n as fileLeaseIo, t as deviceLeasePath } from "./device-lease-B9LAXIUH.mjs";
7
+ import { a as androidHome, l as androidToolCwd } from "./android-75Sk2rIR.mjs";
8
8
  import { r as deviceConsoleLevel } from "./ios-device-BiOsSVzd.mjs";
9
- import { n as parseLogcatLine, t as androidClockOffset } from "./android-BA2i_KAV.mjs";
9
+ import { n as parseLogcatLine, t as androidClockOffset } from "./android-BQiKJYK0.mjs";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
11
11
  import { attachExpoErrorContext, readLogRecords, sortByTs } from "@stim-cli/core/state";
12
12
  import { basename, dirname, join, resolve, sep } from "node:path";
@@ -1,22 +1,24 @@
1
- import { A as directorySize, F as volumeRootFor, M as isOnMountedVolume, N as listMountedVolumes, b as removeProject, g as loadConfig, j as formatBytes, k as ownership_claim_exports } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, I as volumeRootFor, M as formatBytes, N as isOnMountedVolume, P as listMountedVolumes, U as projectDeviceSlots, _ as loadConfig$1, j as directorySize, p as getProject, x as removeProject } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { N as workspaceStateFile, O as workspaceDir, v as workspaceLastUsed } from "./metro-BWLOJ_Wr.mjs";
4
- import { C as sourceCheckoutOf, b as resolveFullRef, d as hasUncommittedWork, l as hasPopulatedSubmodules, m as listWorktrees, o as dirtyPaths, w as unpushedCommits } from "./worktree-BlizKDpZ.mjs";
5
- import { a as detectIsExpo, o as findProjectRoot } from "./project-BXZzOABt.mjs";
6
- import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-D5z2_bcF.mjs";
7
- import { d as removeExpiredLease, h as listBuildLocks } from "./device-lease-D83nqeMX.mjs";
8
- import { D as listAvds, N as ownedAvdDirectory, Y as isStimOwnedSim, k as listOrphanedAvdDirectories, w as isStimOwnedAvdName } from "./android-C4zG2Tuc.mjs";
9
- import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
10
- import { l as listAllIosSims } from "./ios-DArbmwer.mjs";
11
- import { a as parseIdleDuration, o as shutDownIdleDevices, r as idleDeviceLines, t as collectIdleDevices } from "./idle-NETbeNiQ.mjs";
12
- import { i as canonicalPath, o as listBuildSlots, r as workspaceInUse } from "./in-use-DVhlSoyn.mjs";
13
- import { C as listOwnedSessionsArgs, D as verifyStoppedSession, E as stopSessionArgs, S as isDefinitiveMissingSessionError, T as parseSessionListPage, b as getSessionArgs, d as withRemoteSessionLock, f as withEasProjectLock, h as removeEasSessionClaim, m as readEasSessionLedger, p as easMachineStateRoot, x as inspectSessionForTeardown, y as findOrphanedOwnedSessions, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
14
- import { A as discoverCaches, C as unverifiedDeviceCommand, D as planCacheEmptying, E as includesWorkspaceOutputs, O as selectCaches, S as findStaleProjectDevices, T as emptyCaches, _ as describeParkedSims, a as collectWorkspaceOutputs, b as findOrphanedDevices, c as listWorkspaceDirs, d as collectDeviceLeases, f as collectParkedAvds, g as deleteProjectDevices, h as deleteParkedSims, i as collectOrphanedWorkspaces, j as sizeCaches, k as trimCaches, l as sizeText, m as deleteParkedAvds, n as WORKSPACE_OUTPUT_DIRS, o as deleteOrphanedWorkspaces, p as collectParkedSims, r as clearWorkspaceOutputs, s as isInsideWorkspaces, t as REBUILD_COST, u as DEVICE_LIST_TIMEOUT_MS, v as describeUnverifiableDevices, w as withAndroidAvdSizes, x as findStaleDeviceRecords, y as deviceSweepIsScoped } from "./workspaces-COD2xCz-.mjs";
15
- import { a as reclaimKeys, d as removeWorktreeTarget, m as reclaimProject, n as excludePodChurn, p as describeDereferenced, r as matchWorktreeEntry } from "./worktree-KOjMX3zA.mjs";
16
- import { n as mergeState, t as fetchDefaultBranch } from "./merge-state-DDxS-XIZ.mjs";
3
+ import { N as workspaceStateFile, O as workspaceDir, j as workspaceLogsDir, v as workspaceLastUsed } from "./metro-Dzo30hvJ.mjs";
4
+ import { C as sourceCheckoutOf, b as resolveFullRef, d as hasUncommittedWork, l as hasPopulatedSubmodules, m as listWorktrees, o as dirtyPaths, w as unpushedCommits } from "./worktree-DeBQSVtR.mjs";
5
+ import { i as findProjectRoot, r as detectIsExpo } from "./project-B8rbutVC.mjs";
6
+ import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-BWCj5Vh-.mjs";
7
+ import { d as removeExpiredLease, h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-B9LAXIUH.mjs";
8
+ import { A as listOrphanedAvdDirectories, L as ownedAvdSerialResolver, O as listAvds, P as ownedAvdDirectory, Q as isStimOwnedSim, T as isStimOwnedAvdName } from "./android-75Sk2rIR.mjs";
9
+ import { h as POOL_SETTING_REMEDY, y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
10
+ import { l as listAllIosSims } from "./ios-CZWOHTTc.mjs";
11
+ import { a as parseIdleDuration, o as shutDownIdleDevices, r as idleDeviceLines, t as collectIdleDevices } from "./idle-S3tFZ53_.mjs";
12
+ import { i as canonicalPath, o as listBuildSlots, r as workspaceInUse } from "./in-use-D9XYEgFD.mjs";
13
+ import { f as resolveEasCliBin } from "./remote-cache-BRsRZru5.mjs";
14
+ import { A as findOrphanedOwnedSessions, C as withEasProjectLock, E as removeEasSessionClaim, I as parseSessionListPage, L as stopSessionArgs, M as inspectSessionForTeardown, N as isDefinitiveMissingSessionError, P as listOwnedSessionsArgs, R as verifyStoppedSession, T as readEasSessionLedger$1, d as withRemoteSessionLock, j as getSessionArgs, w as easMachineStateRoot$1 } from "./device-remote-C0_o-tJH.mjs";
15
+ import { A as includesWorkspaceOutputs, C as deviceSweepIsScoped, D as unverifiedDeviceCommand, E as findStaleProjectDevices, F as sizeCaches, M as selectCaches, N as trimCaches, O as withAndroidAvdSizes, P as discoverCaches, S as describeUnverifiableDevices, T as findStaleDeviceRecords, _ as collectParkedSims, a as REBUILD_COST, b as deleteProjectDevices, c as collectOrphanedWorkspaces, d as isInsideWorkspaces, f as listWorkspaceDirs, g as collectParkedAvds, h as collectDeviceLeases, i as machineNumber, j as planCacheEmptying, k as emptyCaches, l as collectWorkspaceOutputs, m as DEVICE_LIST_TIMEOUT_MS, o as WORKSPACE_OUTPUT_DIRS, p as sizeText, s as clearWorkspaceOutputs, u as deleteOrphanedWorkspaces, v as deleteParkedAvds, w as findOrphanedDevices, x as describeParkedSims, y as deleteParkedSims } from "./budget-DbzW5VTD.mjs";
16
+ import { a as reclaimKeys, d as removeWorktreeTarget, m as reclaimProject, n as excludePodChurn, p as describeDereferenced, r as matchWorktreeEntry } from "./worktree-ChDL5fO1.mjs";
17
+ import { n as mergeState, t as fetchDefaultBranch } from "./merge-state-ytFQCeh4.mjs";
17
18
  import { InvalidArgumentError } from "commander";
18
19
  import { existsSync, readFileSync, readdirSync, statSync } from "fs";
19
20
  import { basename, dirname, isAbsolute, join } from "path";
21
+ import { settingDefinition } from "@stim-cli/core/state";
20
22
  import chalk from "chalk";
21
23
  //#region src/commands/gc/eas-sessions.ts
22
24
  const EAS_OPERATION_TIMEOUT_MS = 3e4;
@@ -141,8 +143,8 @@ function collectEasSessionSweep(config, deps) {
141
143
  const eas = (deps.resolveEasCliBin ?? resolveEasCliBin)(projectRoot);
142
144
  if (!eas) return empty(["EAS session sweep skipped: eas-cli is not available for the current Expo project."]);
143
145
  const recorded = readRecordedRemoteSessionIds([...Object.keys(config?.projects ?? {}), projectRoot]);
144
- const ledgerRoot = deps.easLedgerRoot ?? easMachineStateRoot();
145
- const ledger = readEasSessionLedger(ledgerRoot);
146
+ const ledgerRoot = deps.easLedgerRoot ?? easMachineStateRoot$1();
147
+ const ledger = readEasSessionLedger$1(ledgerRoot);
146
148
  const run = deps.runEasFile ?? ((file, args, options) => getExecutor().runFile(file, args, options));
147
149
  const sessions = [];
148
150
  const seenCursors = /* @__PURE__ */ new Set();
@@ -180,7 +182,7 @@ function collectEasSessionSweep(config, deps) {
180
182
  }
181
183
  const lockedRoots = deps.easLockedRoots;
182
184
  if (lockedRoots) {
183
- if (easLockRoots(projectRoot, loadConfig()).some((root) => !lockedRoots.includes(root))) return empty([...recorded.notices, "EAS session sweep skipped: registered workspace roots changed after remote-session locks were acquired."]);
185
+ if (easLockRoots(projectRoot, loadConfig$1()).some((root) => !lockedRoots.includes(root))) return empty([...recorded.notices, "EAS session sweep skipped: registered workspace roots changed after remote-session locks were acquired."]);
184
186
  }
185
187
  const compared = findOrphanedOwnedSessions({
186
188
  sessions,
@@ -236,7 +238,7 @@ async function withRemoteSessionGcLocks(projectRoot, deps, fn) {
236
238
  const waitMs = deps.easLockWaitMs ?? EAS_LOCK_WAIT_MS;
237
239
  const maxSnapshots = deps.easLockSnapshotRetries ?? EAS_LOCK_SNAPSHOT_RETRIES;
238
240
  for (let attempt = 0; attempt < maxSnapshots; attempt++) {
239
- const roots = easLockRoots(projectRoot, loadConfig());
241
+ const roots = easLockRoots(projectRoot, loadConfig$1());
240
242
  const unavailable = unavailableLockRootNotice(roots);
241
243
  if (unavailable) return fn({
242
244
  ...deps,
@@ -250,7 +252,7 @@ async function withRemoteSessionGcLocks(projectRoot, deps, fn) {
250
252
  let expanded = false;
251
253
  let coreStarted = false;
252
254
  const acquire = (index) => index === roots.length ? (async () => {
253
- if (easLockRoots(projectRoot, loadConfig()).some((root) => !roots.includes(root))) {
255
+ if (easLockRoots(projectRoot, loadConfig$1()).some((root) => !roots.includes(root))) {
254
256
  expanded = true;
255
257
  return null;
256
258
  }
@@ -293,12 +295,12 @@ async function deleteEasSessions(easSessionSweep, deps) {
293
295
  return;
294
296
  }
295
297
  const coordinatedDeps = lockedDeps;
296
- const currentConfig = loadConfig();
298
+ const currentConfig = loadConfig$1();
297
299
  const currentRoots = easLockRoots(projectScope, currentConfig);
298
300
  const registryExpanded = coordinatedDeps.easLockedRoots && currentRoots.some((root) => !coordinatedDeps.easLockedRoots.includes(root));
299
301
  const currentRecords = registryExpanded ? null : readRecordedRemoteSessionIds([...Object.keys(currentConfig?.projects ?? {}), projectScope]);
300
- const ledgerRoot = coordinatedDeps.easLedgerRoot ?? easMachineStateRoot();
301
- const ledger = readEasSessionLedger(ledgerRoot);
302
+ const ledgerRoot = coordinatedDeps.easLedgerRoot ?? easMachineStateRoot$1();
303
+ const ledger = readEasSessionLedger$1(ledgerRoot);
302
304
  const removeClaim = coordinatedDeps.removeEasSessionClaim ?? removeEasSessionClaim;
303
305
  const reconcileClaim = (sessionId) => {
304
306
  let detail = "the claim store did not remove it";
@@ -402,6 +404,8 @@ async function deleteEasSessions(easSessionSweep, deps) {
402
404
  //#region src/commands/gc/worktrees.ts
403
405
  const DEFAULT_WORKTREE_IDLE_DAYS = 7;
404
406
  const DAY_MS = 864e5;
407
+ const MINUTE_MS = 6e4;
408
+ const GRACE_SETTING = "gc.worktreeGraceMinutes";
405
409
  const MERGE_DECIDES = /* @__PURE__ */ new Set([
406
410
  "unpushed",
407
411
  "not-merged",
@@ -414,7 +418,34 @@ function skip(code, text) {
414
418
  text
415
419
  };
416
420
  }
417
- function worktreeSkipReason(facts, olderThan) {
421
+ /**
422
+ * Why gc keeps a worktree, or null when it removes it. A worktree that would be removed is still kept while its last
423
+ * activity, or its merge into the default branch, is less than `grace.ms` old, and kept when that activity is unknown.
424
+ */
425
+ function worktreeSkipReason(facts, olderThan, grace = {
426
+ ms: 0,
427
+ now: 0
428
+ }) {
429
+ return removalBlocker(facts, olderThan) ?? graceBlocker(facts, grace);
430
+ }
431
+ function graceBlocker(facts, grace) {
432
+ if (grace.ms <= 0) return null;
433
+ if (!facts.activity) return skip("activity-unknown", "its last activity could not be read");
434
+ const merged = facts.merge?.merged ? facts.merge : null;
435
+ const latest = merged && merged.mergedAt > facts.activity.at ? {
436
+ at: merged.mergedAt,
437
+ basis: `merged into ${merged.into}`
438
+ } : facts.activity;
439
+ const eligibleAt = latest.at + grace.ms;
440
+ if (grace.now >= eligibleAt) return null;
441
+ const ago = formatLongDuration(Math.max(0, grace.now - latest.at));
442
+ return {
443
+ code: "recent-activity",
444
+ text: `recent activity: ${latest.basis} ${ago} ago; removable after ${new Date(eligibleAt).toISOString()}`,
445
+ eligibleAt
446
+ };
447
+ }
448
+ function removalBlocker(facts, olderThan) {
418
449
  if (facts.bare) return skip("bare-repository", "bare repository");
419
450
  if (typeof facts.source === "object") return skip("source-checkout-unknown", `source checkout unknown: ${facts.source.refusal}`);
420
451
  if (facts.source === "source") return skip("source-checkout", "source checkout");
@@ -447,7 +478,119 @@ function idleDaysOf(keys, now) {
447
478
  return Number.isFinite(last) ? Math.max(0, Math.floor((now - last) / DAY_MS)) : null;
448
479
  }
449
480
  function inUseOf(keys, checks) {
450
- return [...new Set(keys.flatMap((key) => workspaceInUse(key, checks)))];
481
+ return [.../* @__PURE__ */ new Set([...keys.flatMap((key) => workspaceInUse(key, checks)), ...deviceUseOf(keys)])];
482
+ }
483
+ function deviceUseOf(keys) {
484
+ const reasons = [];
485
+ let sims;
486
+ let avdSerial;
487
+ for (const key of keys) {
488
+ let slots;
489
+ try {
490
+ slots = projectDeviceSlots(getProject(key));
491
+ } catch (error) {
492
+ reasons.push(`its device records cannot be read: ${error.message}`);
493
+ continue;
494
+ }
495
+ for (const { platforms } of slots) {
496
+ const ios = platforms.ios;
497
+ if (ios?.owned && ios.deviceUdid) {
498
+ if (sims === void 0) try {
499
+ sims = listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS });
500
+ } catch {
501
+ sims = null;
502
+ }
503
+ const sim = sims?.find((entry) => entry.udid === ios.deviceUdid);
504
+ if (sims === null) reasons.push(`the state of its owned simulator ${ios.deviceUdid} cannot be read`);
505
+ else if (sim && sim.state !== "Shutdown") reasons.push(`its owned simulator ${sim.name} is ${sim.state}; \`stim stop\` in ${key} shuts it down`);
506
+ }
507
+ const android = platforms.android;
508
+ if (android?.owned && android.avdName) {
509
+ avdSerial ??= ownedAvdSerialResolver({ timeoutMs: DEVICE_LIST_TIMEOUT_MS });
510
+ try {
511
+ if (avdSerial(android.avdName).serial) reasons.push(`its owned emulator ${android.avdName} is running; \`stim stop\` in ${key} shuts it down`);
512
+ } catch {
513
+ reasons.push(`the state of its owned emulator ${android.avdName} cannot be read`);
514
+ }
515
+ }
516
+ }
517
+ }
518
+ const holders = new Set(keys.map(canonicalPath));
519
+ const now = Date.now();
520
+ for (const { lease } of listLeaseFiles()) if (lease && !leaseIsExpired(lease, now) && holders.has(canonicalPath(lease.holder))) reasons.push(`it holds the ${lease.platform} device lease on ${lease.deviceName ?? lease.id}`);
521
+ return reasons;
522
+ }
523
+ function newestMtime(paths) {
524
+ let newest = null;
525
+ for (const { path, basis } of paths) {
526
+ let mtime;
527
+ try {
528
+ mtime = statSync(path).mtimeMs;
529
+ } catch (error) {
530
+ if (error.code === "ENOENT") continue;
531
+ return "unreadable";
532
+ }
533
+ if (!newest || mtime > newest.at) newest = {
534
+ at: mtime,
535
+ basis
536
+ };
537
+ }
538
+ return newest;
539
+ }
540
+ function logFiles$1(key) {
541
+ const dir = workspaceLogsDir(key);
542
+ try {
543
+ return readdirSync(dir).map((name) => ({
544
+ path: join(dir, name),
545
+ basis: "a Stim log write"
546
+ }));
547
+ } catch (error) {
548
+ return error.code === "ENOENT" ? [] : null;
549
+ }
550
+ }
551
+ function worktreeActivityOf(path, keys) {
552
+ const gitDir = getExecutor().runFileQuiet("git", [
553
+ "--no-optional-locks",
554
+ "-C",
555
+ path,
556
+ "rev-parse",
557
+ "--path-format=absolute",
558
+ "--git-dir"
559
+ ])?.trim();
560
+ if (!gitDir) return null;
561
+ const paths = [
562
+ {
563
+ path: join(gitDir, "index"),
564
+ basis: "a git index write"
565
+ },
566
+ {
567
+ path: join(gitDir, "HEAD"),
568
+ basis: "a git HEAD change"
569
+ },
570
+ {
571
+ path: join(gitDir, "logs", "HEAD"),
572
+ basis: "a git reflog entry"
573
+ }
574
+ ];
575
+ for (const key of keys) {
576
+ const logs = logFiles$1(key);
577
+ if (logs === null) return null;
578
+ paths.push({
579
+ path: workspaceStateFile(key),
580
+ basis: "a Stim workspace state write"
581
+ }, ...logs);
582
+ }
583
+ const newest = newestMtime(paths);
584
+ return newest === "unreadable" ? null : newest;
585
+ }
586
+ function graceMsSetting() {
587
+ const { value, error } = machineNumber(GRACE_SETTING, loadConfig$1(), process.env);
588
+ if (error) {
589
+ const fallback = Number(settingDefinition(GRACE_SETTING)?.default);
590
+ console.error(chalk.yellow(`${error} gc uses the default of ${fallback} minutes.`));
591
+ return fallback * MINUTE_MS;
592
+ }
593
+ return (value ?? 0) * MINUTE_MS;
451
594
  }
452
595
  function porcelainOf(path, gitAnswered) {
453
596
  if (gitAnswered === null) return null;
@@ -456,15 +599,15 @@ function porcelainOf(path, gitAnswered) {
456
599
  return lines.length ? lines : null;
457
600
  }
458
601
  function candidateRoots() {
459
- const registered = Object.keys(loadConfig()?.projects ?? {}).filter(isAbsolute);
602
+ const registered = Object.keys(loadConfig$1()?.projects ?? {}).filter(isAbsolute);
460
603
  const recorded = listWorkspaceDirs().flatMap((entry) => entry.projectRoot ? [entry.projectRoot] : []);
461
604
  return [.../* @__PURE__ */ new Set([...registered, ...recorded])].filter((root) => existsSync(root)).toSorted();
462
605
  }
463
- function checkMergeStates(pending, idle, now) {
606
+ function checkMergeStates(pending, idle, grace) {
464
607
  const repos = /* @__PURE__ */ new Map();
465
608
  for (const entry of pending) repos.set(entry.repo, [...repos.get(entry.repo) ?? [], entry]);
466
609
  for (const [repo, entries] of repos) {
467
- const target = fetchDefaultBranch(repo, now);
610
+ const target = fetchDefaultBranch(repo, grace.now);
468
611
  for (const { candidate, facts } of entries) {
469
612
  const merge = "error" in target ? {
470
613
  merged: false,
@@ -474,11 +617,12 @@ function checkMergeStates(pending, idle, now) {
474
617
  const verdict = worktreeSkipReason({
475
618
  ...facts,
476
619
  merge
477
- }, idle);
620
+ }, idle, grace);
478
621
  Object.assign(candidate, {
479
622
  merge,
480
623
  skipCode: verdict?.code ?? null,
481
- skipped: verdict?.text ?? null
624
+ skipped: verdict?.text ?? null,
625
+ eligibleAt: verdict?.eligibleAt ?? null
482
626
  });
483
627
  }
484
628
  }
@@ -489,6 +633,10 @@ function checkMergeStates(pending, idle, now) {
489
633
  */
490
634
  function collectWorktreeSweep({ idle, olderThan, now }) {
491
635
  const days = idle ? olderThan ?? DEFAULT_WORKTREE_IDLE_DAYS : null;
636
+ const grace = {
637
+ ms: graceMsSetting(),
638
+ now
639
+ };
492
640
  const groups = /* @__PURE__ */ new Map();
493
641
  const outside = [];
494
642
  for (const root of candidateRoots()) {
@@ -500,7 +648,8 @@ function collectWorktreeSweep({ idle, olderThan, now }) {
500
648
  idleDays: null,
501
649
  merge: null,
502
650
  skipCode: "not-a-worktree",
503
- skipped: "not inside a git worktree"
651
+ skipped: "not inside a git worktree",
652
+ eligibleAt: null
504
653
  });
505
654
  continue;
506
655
  }
@@ -515,6 +664,7 @@ function collectWorktreeSweep({ idle, olderThan, now }) {
515
664
  const keys = [.../* @__PURE__ */ new Set([...roots, ...reclaimKeys(path)])];
516
665
  const idleDays = idleDaysOf(keys, now);
517
666
  const linked = !("refusal" in source) && entry !== null && source.path !== entry.path;
667
+ const activity = linked && grace.ms > 0 ? worktreeActivityOf(path, keys) : null;
518
668
  const gitAnswered = linked ? hasUncommittedWork(path) : null;
519
669
  const facts = {
520
670
  source: "refusal" in source ? source : linked ? "linked" : "source",
@@ -525,16 +675,18 @@ function collectWorktreeSweep({ idle, olderThan, now }) {
525
675
  submodules: linked && hasPopulatedSubmodules(path),
526
676
  inUse: linked ? inUseOf(keys, { managedLocks: true }) : [],
527
677
  idleDays,
528
- merge: null
678
+ merge: null,
679
+ activity
529
680
  };
530
- const verdict = worktreeSkipReason(facts, days);
681
+ const verdict = worktreeSkipReason(facts, days, grace);
531
682
  const candidate = {
532
683
  path,
533
684
  keys,
534
685
  idleDays,
535
686
  merge: null,
536
687
  skipCode: verdict?.code ?? null,
537
- skipped: verdict?.text ?? null
688
+ skipped: verdict?.text ?? null,
689
+ eligibleAt: verdict?.eligibleAt ?? null
538
690
  };
539
691
  if (verdict && MERGE_DECIDES.has(verdict.code) && !("refusal" in source)) pending.push({
540
692
  candidate,
@@ -543,13 +695,14 @@ function collectWorktreeSweep({ idle, olderThan, now }) {
543
695
  });
544
696
  worktrees.push(candidate);
545
697
  }
546
- checkMergeStates(pending, days, now);
698
+ checkMergeStates(pending, days, grace);
547
699
  const listed = [...worktrees, ...outside].filter((w) => idle || w.skipCode !== "not-a-worktree" && w.skipCode !== "source-checkout");
548
700
  return {
549
701
  idle: days === null ? null : {
550
702
  olderThan: days,
551
703
  defaulted: olderThan === null
552
704
  },
705
+ graceMs: grace.ms,
553
706
  worktrees: listed
554
707
  };
555
708
  }
@@ -568,6 +721,16 @@ async function removeWorktrees(sweep, { now = Date.now() } = {}) {
568
721
  const idleDays = idleDaysOf(keys, now);
569
722
  if (idleDays === null || !sweep.idle || idleDays < sweep.idle.olderThan) reasons.push(`used ${idleDays === null ? "at an unknown time" : `${idleDays}d ago`} since gc checked it`);
570
723
  }
724
+ if (sweep.graceMs > 0) {
725
+ const recent = graceBlocker({
726
+ merge: candidate.merge,
727
+ activity: worktreeActivityOf(candidate.path, keys)
728
+ }, {
729
+ ms: sweep.graceMs,
730
+ now: Date.now()
731
+ });
732
+ if (recent) reasons.push(recent.text);
733
+ }
571
734
  kept = reasons;
572
735
  return reasons;
573
736
  };
@@ -909,7 +1072,8 @@ function gcReportSections({ skipped = [], deadProjects = [], orphanedPorts = [],
909
1072
  mergedInto: w.merge?.merged ? w.merge.into : null,
910
1073
  willRemove: w.skipCode === null,
911
1074
  reason: w.skipCode,
912
- detail: w.skipped ?? worktreeRemovalReason(w)
1075
+ detail: w.skipped ?? worktreeRemovalReason(w),
1076
+ eligibleAt: w.eligibleAt === null ? null : new Date(w.eligibleAt).toISOString()
913
1077
  })),
914
1078
  parkedSimulators: parkedSims.map(({ udid, name, model, runtime, parkedAt, bytes, listed }) => ({
915
1079
  udid,
@@ -1085,7 +1249,7 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
1085
1249
  all
1086
1250
  };
1087
1251
  const mountedVolumes = listMountedVolumes();
1088
- const cfg = loadConfig();
1252
+ const cfg = loadConfig$1();
1089
1253
  let easSessionSweep = deps.precollectedEasSessionSweep;
1090
1254
  if (!easSessionSweep) try {
1091
1255
  easSessionSweep = collectEasSessionSweep(cfg, deps);
@@ -1341,7 +1505,7 @@ async function sweep(opts, deps) {
1341
1505
  try {
1342
1506
  easSessionSweep = await withProjectLock(projectRoot, () => {
1343
1507
  sweepStarted = true;
1344
- return withRemoteSessionGcLocks(projectRoot, deps, (coordinatedDeps) => Promise.resolve(collectEasSessionSweep(loadConfig(), coordinatedDeps)));
1508
+ return withRemoteSessionGcLocks(projectRoot, deps, (coordinatedDeps) => Promise.resolve(collectEasSessionSweep(loadConfig$1(), coordinatedDeps)));
1345
1509
  }, {
1346
1510
  waitMs: 0,
1347
1511
  ownerPurpose: "EAS orphan sweep",
@@ -1385,7 +1549,7 @@ async function runGcCore(opts, deps) {
1385
1549
  const { deadProjects, invalidProjects, orphanedDevices, staleDevices, staleDeviceRecords, buildLocks, buildSlots, deviceLeases, easSessionSweep, caches } = report;
1386
1550
  const actionable = deadProjects.length + invalidProjects.length > 0 || report.orphanedWorkspaces.length > 0 || Boolean(report.workspaceOutputs?.workspaces.some((entry) => entry.willClear)) || Boolean(report.worktreeSweep?.worktrees.some((entry) => !entry.skipped)) || report.parkedSims.length > 0 || report.parkedAvds.length > 0 || orphanedDevices.length > 0 || staleDevices.length > 0 || staleDeviceRecords.length > 0 || buildLocks.stale.length > 0 || buildSlots.stale.length > 0 || deviceLeases.expired.length > 0 || easSessionSweep.orphaned.length > 0 || (olderThan !== null || all) && caches.length > 0;
1387
1551
  const idle = opts.idle ?? null;
1388
- const idleFailures = idle === null ? 0 : shutDownIdleDevices(report.idleDevices, idle, () => collectIdleDevices(loadConfig(), listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS }), report.deadProjects)).failures;
1552
+ const idleFailures = idle === null ? 0 : shutDownIdleDevices(report.idleDevices, idle, () => collectIdleDevices(loadConfig$1(), listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS }), report.deadProjects)).failures;
1389
1553
  if (idleFailures) process.exitCode = 1;
1390
1554
  const payload = (failures) => ({
1391
1555
  mode: opts.delete ? "delete" : "dry-run",