stim 1.21.0 → 1.23.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.
- package/README.md +60 -7
- package/dist/{acquire-artifact-CD4lbiWE.mjs → acquire-artifact-ybouwJSR.mjs} +21 -3
- package/dist/{act-DHAw2A2S.mjs → act-DG54PWtJ.mjs} +298 -164
- package/dist/{activity-BzVfHSrY.mjs → activity-B5RtpFda.mjs} +33 -12
- package/dist/{agent-device-usage-output-zh1vhbLp.mjs → agent-device-usage-output-UJ5gC80l.mjs} +7 -7
- package/dist/{android-BLgbNqox.mjs → android-BoUJKbfz.mjs} +66 -52
- package/dist/{android-DUYkNF4u.mjs → android-C7sVmyI9.mjs} +160 -59
- package/dist/{android-CV_GCELZ.mjs → android-CHH4KLOR.mjs} +5 -5
- package/dist/{android-BEJ8Jpl7.mjs → android-DR5lZ2Az.mjs} +2 -2
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{android-cas-Ct5b1xCK.mjs → android-cas-ngferVq2.mjs} +3 -3
- package/dist/{client-B7QVOlCr.d.mts → android-project-DVWyCbWU.d.mts} +145 -7
- package/dist/api.d.mts +132 -118
- package/dist/api.mjs +239 -42
- package/dist/{artifact-DAuZ-FNU.mjs → artifact-5RteZem7.mjs} +69 -40
- package/dist/{artifact-B8T3S5gi.mjs → artifact-Dwdo7k1E.mjs} +40 -35
- package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
- package/dist/{browser-web-QQzVjz3O.mjs → browser-web-CeEVlGug.mjs} +187 -59
- package/dist/{budget-Bs6SxxzO.mjs → budget-DnPX3DXj.mjs} +830 -699
- package/dist/{build-CoPzQRNw.mjs → build-CqufZFqy.mjs} +34 -27
- package/dist/{build-cache-DmyR9Zzc.mjs → build-cache-Dv7RN200.mjs} +4 -4
- package/dist/{build-plan-CaFskB7_.mjs → build-plan-C8CIvRyi.mjs} +74 -14
- package/dist/{cache-manifest-DkkqguoK.mjs → cache-manifest-DSeQjt-Q.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-BJRZ9pG3.mjs → ccache-RcAy92gH.mjs} +6 -6
- package/dist/{cdp-CWmIUMbw.mjs → cdp-3fwICjzi.mjs} +1 -1
- package/dist/{chrome-B6tfCta1.mjs → chrome-Bbw689-6.mjs} +1 -1
- package/dist/{cli-0DYf8QhQ.mjs → cli-D-J9fWGV.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-UXD70ZbM.mjs → client-yyso1bwi.mjs} +218 -47
- package/dist/collector-run.d.mts +1 -1
- package/dist/collector-run.mjs +6 -6
- package/dist/{command-output-B1UrjZHL.mjs → command-output-Db8BqzxH.mjs} +1 -1
- package/dist/{config-CYcBF478.mjs → config-DlrsduwG.mjs} +17 -11
- package/dist/{created-devices-CqeBlrEn.mjs → created-devices-x9rN6bhs.mjs} +13 -3
- package/dist/{dependency-state-BbKQW83h.mjs → dependency-state-1I9KZT1Y.mjs} +2 -2
- package/dist/{detached-entry-DFRyG1_o.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
- package/dist/{dev-client-UOeESKm6.mjs → dev-client-BnYSDiKa.mjs} +2 -2
- package/dist/{device-DCxH7_By.mjs → device-BvzPUBs3.mjs} +16 -16
- package/dist/{device-ExJq8Ei7.mjs → device-CCkWmkAA.mjs} +71 -14
- package/dist/{device-capacity-CMlqEcvw.mjs → device-capacity-CjaSdrhg.mjs} +9 -10
- package/dist/device-host-worker.mjs +25 -32
- package/dist/{device-ios-DRUeKaFV.mjs → device-ios-uOiEETX2.mjs} +39 -16
- package/dist/{device-lease-run-C8raGFoP.mjs → device-lease-run-BgwPHc6u.mjs} +5 -5
- package/dist/{device-pool-DMRpVX9a.mjs → device-pool-C-ptmZTa.mjs} +3 -3
- package/dist/{doctor-DTvaDOda.mjs → doctor-8sr2tFOL.mjs} +24 -37
- package/dist/{doctor-Dhqebm0q.mjs → doctor-D2SN3Ltx.mjs} +19 -16
- package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-BLHCYxzi.mjs → doctor-pxxvipYC.mjs} +1 -1
- package/dist/{doctor-watchman-Cv1F10Kj.mjs → doctor-watchman-sy_RNhFt.mjs} +5 -5
- package/dist/{eas-build-BomfRnFT.mjs → eas-build-CyjU5K7E.mjs} +4 -4
- package/dist/{eas-fallback-DJwZpy0c.mjs → eas-fallback-DV3Wytf1.mjs} +27 -18
- package/dist/{eas-session-ledger-op6A54yi.mjs → eas-session-ledger-BzzsX97d.mjs} +8 -7
- package/dist/{error-diagnostics-Bf0rZvG9.mjs → error-diagnostics-C6sVoeqO.mjs} +10 -10
- package/dist/{exec-_UbtCQcG.mjs → exec-DEoAhcze.mjs} +155 -47
- package/dist/{exec-H20xSg2T.d.mts → exec-DnYc4HGH.d.mts} +17 -4
- package/dist/{gc-_-dCXdyL.mjs → gc-CDoogxAI.mjs} +587 -313
- package/dist/gc-DLbzvTP2.mjs +3 -0
- package/dist/{guide-Yqwt2bd6.mjs → guide-BC37GcDG.mjs} +288 -59
- package/dist/{hosted-android-Bw-honsd.mjs → hosted-android-CkclQig_.mjs} +6 -6
- package/dist/{hosted-client-DB_gBPfY.mjs → hosted-client-ByuMMO5s.mjs} +4 -4
- package/dist/{hosted-ios-CUvOf4Vr.mjs → hosted-ios-DtYHeuYR.mjs} +1 -1
- package/dist/{hosted-logs-DL_P5AdN.mjs → hosted-logs-Br84qWy1.mjs} +5 -5
- package/dist/{hosted-macos-QI141yKk.mjs → hosted-macos-DdtYajZt.mjs} +21 -12
- package/dist/{hosted-native-Ksyjgzq-.mjs → hosted-native-UPI9zdZ4.mjs} +27 -14
- package/dist/{idle-BVeRGroT.d.mts → idle-C4cZ757K.d.mts} +3 -3
- package/dist/{idle-shutdown-DaKmZi0z.mjs → idle-shutdown-DO7oIRlc.mjs} +7 -7
- package/dist/ios-CDvlmUs7.d.mts +24 -0
- package/dist/{ios-ubFsBzwq.mjs → ios-DZZbNYlY.mjs} +59 -50
- package/dist/{ios-device-CXGP1bsD.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
- package/dist/{ios-device-CwFMehUS.mjs → ios-device-JC3uWM4K.mjs} +3 -3
- package/dist/{ios-CpByZy12.mjs → ios-hcBpnEGk.mjs} +81 -34
- package/dist/{ios-project-WuwwBdvW.mjs → ios-project-CVyNwjAF.mjs} +5 -5
- package/dist/{ios-signing-DTTIChGs.mjs → ios-signing-BtAffm0A.mjs} +2 -2
- package/dist/{ios-state-DvFX-K_l.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
- package/dist/{ios-CQ68hG9s.mjs → ios-vbUOqGXu.mjs} +8 -8
- package/dist/{ios-qNJt4dFm.mjs → ios-xtlRHaeB.mjs} +1 -1
- package/dist/{js-swap-Cc1dttps.mjs → js-swap-C3QxUFJR.mjs} +7 -29
- package/dist/{launch-CD1yVc7U.mjs → launch-Bz7JtaC4.mjs} +16 -16
- package/dist/{launch-Zq2mOSDy.mjs → launch-CHY3p-yz.mjs} +40 -39
- package/dist/{logs-CMm05HxN.mjs → logs-CtNeNDuq.mjs} +10 -17
- package/dist/{logs-BS00Anxf.mjs → logs-mxqsWpJs.mjs} +151 -24
- package/dist/{macos-B65--pPd.mjs → macos-inNFbBWc.mjs} +1 -1
- package/dist/macos-run.mjs +1 -1
- package/dist/{macos-C-0qJ6zq.mjs → macos-u0BoHKnO.mjs} +143 -46
- package/dist/maintenance-run.mjs +8 -8
- package/dist/{metro-DEXpIhHC.mjs → metro-DiXtA3Ty.mjs} +59 -37
- package/dist/{metro-gateway-BMJNlj3E.mjs → metro-gateway-CKZqKqx7.mjs} +120 -22
- package/dist/{named-ports-BWTzt6mu.mjs → named-ports-DkEzOfzO.mjs} +40 -33
- package/dist/{native-android-JACyjTZs.mjs → native-android-CdCSylTn.mjs} +43 -242
- package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
- package/dist/{native-gradle-inputs-Bep9JcSF.mjs → native-gradle-inputs-Dnh84Zbd.mjs} +3 -129
- package/dist/{native-run-DY_RLx3C.mjs → native-run-BUTu8T7A.mjs} +4 -5
- package/dist/{native-runtime-Dg1Q7tfF.mjs → native-runtime-CRSOZxKY.mjs} +8 -7
- package/dist/native-source-Y0yLhFyQ.mjs +133 -0
- package/dist/{native-xcode-inputs-CB2iQeWq.mjs → native-xcode-inputs-G6rkkhxu.mjs} +2 -3
- package/dist/{native-xcode-ios-CXX39F7o.mjs → native-xcode-ios-_os2PlCD.mjs} +27 -32
- package/dist/offload-worker.d.mts +65 -2
- package/dist/offload-worker.mjs +305 -73
- package/dist/operation-exec-BW0em61G.mjs +171 -0
- package/dist/{ownership-DEmM5vhh.mjs → ownership-C5fo5Edb.mjs} +3 -3
- package/dist/{page-CPaHeYqj.mjs → page-DBL2PiUU.mjs} +8 -4
- package/dist/{placement-log-BqGbTa61.mjs → placement-log-BnGgJRRZ.mjs} +1 -1
- package/dist/{plan-placement-Bwj-IjY1.mjs → plan-placement-BU42oOyT.mjs} +12 -8
- package/dist/{ports-D-MmCTdv.mjs → ports-BSmQKzW7.mjs} +3 -3
- package/dist/{prebuild-uD_ipCxF.mjs → prebuild-BFm63bQ0.mjs} +63 -16
- package/dist/{project-BZNjmW_8.mjs → project-CTLNHCfE.mjs} +16 -16
- package/dist/{pull-request-Lfetn8Kr.mjs → pull-request-W1IuLXDt.mjs} +102 -20
- package/dist/{pull-request-zjCSAryH.d.mts → pull-request-eODyIqZF.d.mts} +6 -2
- package/dist/pull-requests.d.mts +2 -2
- package/dist/pull-requests.mjs +2 -2
- package/dist/{react-native-android-DuzH0cn3.mjs → react-native-android-CFgUroxW.mjs} +73 -53
- package/dist/{react-native-build-rhk4smwQ.mjs → react-native-build-CmJkTljQ.mjs} +8 -8
- package/dist/{react-native-doctor-CQpuIMso.mjs → react-native-doctor-LTF-Xt8l.mjs} +7 -7
- package/dist/{react-native-ios-Bhq1rJeV.mjs → react-native-ios-ChBF1MkB.mjs} +43 -29
- package/dist/{recordings-DYteQSu4.mjs → recordings-CQmfzAh7.mjs} +1 -1
- package/dist/registration-BcRgF6Ox.mjs +51 -0
- package/dist/{reload-CmTRFJaX.mjs → reload-DF9hqUUB.mjs} +16 -15
- package/dist/{reload-DzjSl5P_.mjs → reload-RBi1nj6Z.mjs} +1 -1
- package/dist/{remote-ByYkXdGD.mjs → remote-BmvMCcJw.mjs} +18 -15
- package/dist/{result-DNiS-tTP.mjs → result-Cx5CRLvS.mjs} +24 -23
- package/dist/{run-D23HmJMs.mjs → run-DidHghD1.mjs} +3 -2
- package/dist/{selection-CSl9i5qU.mjs → selection-DSMbWEX2.mjs} +6 -5
- package/dist/{server-bare-CxTrvDg8.mjs → server-bare-CafzuyFB.mjs} +2 -2
- package/dist/{server-command-CtzloH3v.mjs → server-command-BTiGPEjS.mjs} +5 -5
- package/dist/server-expo-C-Buqvn_.mjs +2 -0
- package/dist/{server-expo-DT_F_uVI.mjs → server-expo-D9lEz4aq.mjs} +7 -5
- package/dist/{settings-CsJDEXgK.mjs → settings-C7O8A6ZI.mjs} +223 -243
- package/dist/{settings-T1gtc3bf.mjs → settings-eKF_vJJs.mjs} +1 -1
- package/dist/{settings-write-HyVZ8eQ8.mjs → settings-write-79mQRr9C.mjs} +7 -6
- package/dist/settings.schema.json +13 -0
- package/dist/{simslim-Cgk17SXV.mjs → simslim-BNckWpXi.mjs} +2 -2
- package/dist/{slot-launch-DF8VfT64.mjs → slot-launch-D7M2nE4b.mjs} +6 -6
- package/dist/{stage-BIS0ydsV.mjs → stage-DKNM4ZPd.mjs} +21 -4
- package/dist/{start-RChynRDp.mjs → start-CRfN1kWV.mjs} +1 -1
- package/dist/{start-7lpH7hmN.mjs → start-bjfiScgz.mjs} +622 -393
- package/dist/{state-C4ZtUisW.mjs → state--smjFSTL.mjs} +22 -7
- package/dist/{state-XMziexv2.mjs → state-08I3hw3_.mjs} +2 -2
- package/dist/{stats-53T7OTb9.mjs → stats-DioA6cBU.mjs} +5 -5
- package/dist/{stats-report-BFfMpWWF.mjs → stats-report-BzaPrRm6.mjs} +1 -1
- package/dist/{status-DqEUSSxs.mjs → status-BRROykC8.mjs} +2 -2
- package/dist/{status-CSi6tlRq.mjs → status-Eqx_20WC.mjs} +1 -1
- package/dist/{status-BL7jVyAB.mjs → status-kzbeWk4x.mjs} +43 -29
- package/dist/{status-watch-GDCfqpTE.mjs → status-watch-BIqqbJ6q.mjs} +48 -16
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-C12we7lz.mjs → stim-desktop-D5OGpYZM.mjs} +2 -2
- package/dist/{stop-Bk_1qiV6.mjs → stop-B18d8KDw.mjs} +2 -2
- package/dist/{stop-CPzlM1L-.mjs → stop-B2uLQfoM.mjs} +15 -16
- package/dist/{stop-D7h6jAXQ.mjs → stop-DzLJc7Ei.mjs} +31 -22
- package/dist/supervisor-run.d.mts +3 -3
- package/dist/supervisor-run.mjs +28 -36
- package/dist/{support-Dlu37g6H.mjs → support-BTpZ6RAJ.mjs} +15 -11
- package/dist/{support-67vraa1Q.mjs → support-DTBV56gy.mjs} +8 -8
- package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
- package/dist/swiftpm-macos-r_WSKlXr.mjs +532 -0
- package/dist/{toolchain-Hp9sCpK4.mjs → toolchain-CWeGJgCc.mjs} +9 -6
- package/dist/toolchain-GVgnf8d1.mjs +2 -0
- package/dist/{trigger-BAahxUPq.mjs → trigger-Cbyc41d_.mjs} +3 -3
- package/dist/trigger-yb_nFzPF.mjs +2 -0
- package/dist/{warm-progress-BHX5r0Ei.mjs → warm-progress-CA3TgT3-.mjs} +29 -16
- package/dist/web-Cduk0NSE.mjs +2 -0
- package/dist/{web-CJmIj6AI.mjs → web-CwREhjD-.mjs} +11 -10
- package/dist/web-run.mjs +11 -9
- package/dist/windows-report.mjs +1 -1
- package/dist/{workspace-state-Cjuigeeu.mjs → workspace-state-U08dEzhG.mjs} +3 -3
- package/dist/{workspaces-BccMFmGQ.mjs → workspaces-BxzYlo3P.mjs} +594 -266
- package/dist/{worktree-DQ6Zi2Mv.mjs → worktree-8lqn_lBp.mjs} +850 -551
- package/dist/worktree-BxfVxG_b.mjs +2 -0
- package/dist/{xcode-Zlx3qjEs.mjs → xcode-iQnROM5o.mjs} +5 -5
- package/package.json +7 -7
- package/shim/android-audio/Main.java +24 -0
- package/shim/android-audio/README.md +17 -0
- package/shim/android-audio.jar +0 -0
- package/dist/gc-C-WwL0yi.mjs +0 -3
- package/dist/git-C3iTsJaZ.mjs +0 -73
- package/dist/server-expo-C-90EhcG.mjs +0 -2
- package/dist/settings-DkdmlelE.d.mts +0 -15
- package/dist/swiftpm-macos-p8WZbxKU.mjs +0 -130
- package/dist/toolchain-DhKwp9iI.mjs +0 -2
- package/dist/trigger-Bf3uDcpv.mjs +0 -2
- package/dist/web-DknQETPs.mjs +0 -2
- package/dist/workspace-process-lock-1_1OoVW5.mjs +0 -57
- package/dist/worktree-CK2MpJW5.mjs +0 -2
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { n as isTimeoutError, t as getExecutor } from "./exec-
|
|
1
|
+
import { n as isTimeoutError, r as WorkspaceProcessCleanupError, t as getExecutor } from "./exec-DEoAhcze.mjs";
|
|
2
2
|
import { g as workspaceStateFile$1, m as workspaceLogsDir$1 } from "./paths-DQtTgsBf.mjs";
|
|
3
|
-
import { F as isOnMountedVolume, I as listMountedVolumes,
|
|
4
|
-
import { o as formatLongDuration, u as plural } from "./command-output-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { i as findProjectRoot$1 } from "./project-
|
|
9
|
-
import { a as unregister, n as readManifest } from "./cache-manifest-
|
|
10
|
-
import { A as workspaceBuildInProgress, E as collectOwnedDeviceActivityAsync, St as deleteProjectDevices, T as collectOwnedDeviceActivity, Tt as deviceSweepIsScoped, X as emptyCaches, _r as phase, br as discoverCaches, bt as deleteParkedAvds, ct as deleteGradleVersion, d as trimmableCaches, f as stopOwnedMetro, fr as memorySweepIsScoped, gr as stopIdleGradleDaemons, gt as DEVICE_LIST_TIMEOUT_MS, i as enforceBudget, kt as findStaleProjectDevices, nt as planCacheEmptying, o as machineNumber, pt as waitForGradleExit, r as cacheLabel, sr as collectMemoryReport, st as collectGradleVersions, u as resolveBudget, vt as collectParkedAvds, xr as pruneCache, xt as deleteParkedSims, yt as collectParkedSims } from "./budget-
|
|
3
|
+
import { F as isOnMountedVolume, G as projectDeviceSlots, I as listMountedVolumes, L as measuredDirectorySizeAsync, N as directorySizeAsync, P as formatBytes, _ as loadConfig$1, p as getProject } from "./config-DlrsduwG.mjs";
|
|
4
|
+
import { o as formatLongDuration, u as plural } from "./command-output-Db8BqzxH.mjs";
|
|
5
|
+
import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, r as childEnvironment } from "./operation-exec-BW0em61G.mjs";
|
|
6
|
+
import { r as readWorkspaceState$1, u as workspaceLastUsed } from "./workspace-state-U08dEzhG.mjs";
|
|
7
|
+
import { E as maintenanceKeepSetting, Et as listWorktreesAsync, Ft as resolveFullRefAsync, It as resolveSourceCheckoutAsync, J as resolveProjectSettingsAsync, Rt as sourceCheckoutOf, St as hasUncommittedWorkAsync, Tt as listWorktrees, Wt as removeTemporaryEntryAsync, bt as hasPopulatedSubmodulesAsync, gt as dirtyPathsAsync, q as resolveProjectSettings, zt as unpushedCommitsAsync } from "./settings-C7O8A6ZI.mjs";
|
|
8
|
+
import { i as findProjectRoot$1 } from "./project-CTLNHCfE.mjs";
|
|
9
|
+
import { a as unregister, n as readManifest } from "./cache-manifest-DSeQjt-Q.mjs";
|
|
10
|
+
import { A as workspaceBuildInProgress, E as collectOwnedDeviceActivityAsync, St as deleteProjectDevices, T as collectOwnedDeviceActivity, Tt as deviceSweepIsScoped, X as emptyCaches, _r as phase, br as discoverCaches, bt as deleteParkedAvds, ct as deleteGradleVersion, d as trimmableCaches, f as stopOwnedMetro, fr as memorySweepIsScoped, gr as stopIdleGradleDaemons, gt as DEVICE_LIST_TIMEOUT_MS, i as enforceBudget, kt as findStaleProjectDevices, nt as planCacheEmptying, o as machineNumber, pt as waitForGradleExit, r as cacheLabel, sr as collectMemoryReport, st as collectGradleVersions, u as resolveBudget, vt as collectParkedAvds, xr as pruneCache, xt as deleteParkedSims, yt as collectParkedSims } from "./budget-DnPX3DXj.mjs";
|
|
11
11
|
import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
|
|
12
|
-
import {
|
|
13
|
-
import { N as listBuildLocks, b as leaseIsExpired, g as workspaceActivity, x as listLeaseFiles } from "./activity-
|
|
14
|
-
import {
|
|
15
|
-
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-
|
|
12
|
+
import { V as takeGcResults, a as collectWorkspaceOutputs, c as listWorkspaceDirs, f as withIdleWorkspace, i as collectOrphanedWorkspaces, m as workspaceInUseAsync, o as deleteOrphanedWorkspaces, p as workspaceInUse, r as clearWorkspaceOutputs, s as isInsideWorkspaces, z as GC_OUTPUT } from "./workspaces-BxzYlo3P.mjs";
|
|
13
|
+
import { N as listBuildLocks, b as leaseIsExpired, g as workspaceActivity, x as listLeaseFiles } from "./activity-B5RtpFda.mjs";
|
|
14
|
+
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, P as listAvds, V as ownedAvdDirectory, vt as readParked } from "./android-C7sVmyI9.mjs";
|
|
15
|
+
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-hcBpnEGk.mjs";
|
|
16
16
|
import { s as metroStoreRoot } from "./errors-ccaPc4ox.mjs";
|
|
17
17
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
18
|
-
import { A as
|
|
19
|
-
import { c as FETCH_FRESH_MS, d as localDefaultBranchAsync, l as fetchDefaultBranchAsync, o as recordPullRequestLookup, p as mergeStateAsync, u as lastFetchedAtAsync } from "./warm-progress-
|
|
20
|
-
import { n as describePullRequest,
|
|
18
|
+
import { A as levelFloors, C as measureDisk, E as measurePressureAsync, M as lowestFree, N as protectWindowMs, S as cacheBlocked, T as measurePressure, a as matchWorktreeEntry, c as reclaimKeys, i as excludeWatchmanCookies, k as diskPressureLevel, m as removeWorktreeTarget, o as nestedWorktrees, r as excludePodChurn, s as porcelainPath, w as measureDiskAsync } from "./worktree-8lqn_lBp.mjs";
|
|
19
|
+
import { c as FETCH_FRESH_MS, d as localDefaultBranchAsync, l as fetchDefaultBranchAsync, o as recordPullRequestLookup, p as mergeStateAsync, u as lastFetchedAtAsync } from "./warm-progress-CA3TgT3-.mjs";
|
|
20
|
+
import { n as describePullRequest, r as endedPullRequest, s as pullRequestLookups } from "./pull-request-W1IuLXDt.mjs";
|
|
21
|
+
import { readClaimSet } from "@stim-cli/core/ownership-claim";
|
|
21
22
|
import { existsSync, lstatSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
22
23
|
import { tmpdir } from "node:os";
|
|
23
24
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
24
25
|
import { buildCacheRoot, configDir, metroCacheRoot } from "@stim-cli/core";
|
|
25
26
|
import { LAST_BUILD_KEYS, MAINTENANCE_LOG_NAME, loadConfig, readBuildHistory, readMaintenanceState, readPullRequestCache, settingDefinition, sharedCompilationCache } from "@stim-cli/core/state";
|
|
26
27
|
import { isAbsolute as isAbsolute$1, join as join$1 } from "path";
|
|
27
|
-
import { readClaimSet } from "@stim-cli/core/ownership-claim";
|
|
28
28
|
import chalk from "chalk";
|
|
29
29
|
import { existsSync as existsSync$1, readdirSync as readdirSync$1, statSync as statSync$1 } from "fs";
|
|
30
30
|
import { lstat, readdir, realpath, rename, stat } from "node:fs/promises";
|
|
@@ -175,22 +175,9 @@ function idleDaysOf(keys, now) {
|
|
|
175
175
|
const last = lastUsedOf(keys);
|
|
176
176
|
return Number.isFinite(last) ? Math.max(0, Math.floor((now - last) / DAY_MS)) : null;
|
|
177
177
|
}
|
|
178
|
-
function
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
sims: () => {
|
|
183
|
-
if (sims === void 0) try {
|
|
184
|
-
sims = listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS });
|
|
185
|
-
} catch {
|
|
186
|
-
sims = null;
|
|
187
|
-
}
|
|
188
|
-
return sims;
|
|
189
|
-
},
|
|
190
|
-
avdSerial: (avdName) => (resolver ??= ownedAvdSerialResolver({ timeoutMs: DEVICE_LIST_TIMEOUT_MS }))(avdName)
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
async function reportDeviceReads(keys) {
|
|
178
|
+
async function reportDeviceReads(keys, operation) {
|
|
179
|
+
const signal = operation?.signal;
|
|
180
|
+
signal?.throwIfAborted();
|
|
194
181
|
const slots = keys.flatMap((key) => {
|
|
195
182
|
try {
|
|
196
183
|
return projectDeviceSlots(getProject(key));
|
|
@@ -204,18 +191,34 @@ async function reportDeviceReads(keys) {
|
|
|
204
191
|
}));
|
|
205
192
|
let sims = null;
|
|
206
193
|
if (requestedSims.size) try {
|
|
207
|
-
sims = await listAllIosSimsAsync({
|
|
208
|
-
|
|
194
|
+
sims = await listAllIosSimsAsync({
|
|
195
|
+
timeoutMs: DEVICE_LIST_TIMEOUT_MS,
|
|
196
|
+
operation,
|
|
197
|
+
signal
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (error instanceof WorkspaceProcessCleanupError) throw error;
|
|
201
|
+
signal?.throwIfAborted();
|
|
202
|
+
}
|
|
209
203
|
const names = new Set(slots.flatMap(({ platforms }) => {
|
|
210
204
|
const android = platforms.android;
|
|
211
205
|
return android?.owned && android.avdName ? [android.avdName] : [];
|
|
212
206
|
}));
|
|
213
207
|
const avds = /* @__PURE__ */ new Map();
|
|
214
|
-
const resolver = ownedAvdSerialResolverAsync({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
208
|
+
const resolver = ownedAvdSerialResolverAsync({
|
|
209
|
+
timeoutMs: DEVICE_LIST_TIMEOUT_MS,
|
|
210
|
+
operation,
|
|
211
|
+
signal
|
|
212
|
+
});
|
|
213
|
+
for (const name of names) {
|
|
214
|
+
signal?.throwIfAborted();
|
|
215
|
+
try {
|
|
216
|
+
avds.set(name, { value: await resolver(name) });
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (error instanceof WorkspaceProcessCleanupError) throw error;
|
|
219
|
+
signal?.throwIfAborted();
|
|
220
|
+
avds.set(name, { error });
|
|
221
|
+
}
|
|
219
222
|
}
|
|
220
223
|
return {
|
|
221
224
|
sims: (udid) => requestedSims.has(udid) || sims?.some((sim) => sim.udid === udid) ? sims : null,
|
|
@@ -227,8 +230,10 @@ async function reportDeviceReads(keys) {
|
|
|
227
230
|
}
|
|
228
231
|
};
|
|
229
232
|
}
|
|
230
|
-
function inUseOf(keys, checks, devices
|
|
231
|
-
|
|
233
|
+
async function inUseOf(keys, checks, devices, signal, operation) {
|
|
234
|
+
const reasons = [];
|
|
235
|
+
for (const key of keys) reasons.push(...await workspaceInUseAsync(key, checks, signal, operation));
|
|
236
|
+
return [.../* @__PURE__ */ new Set([...reasons, ...deviceUseOf(keys, devices)])];
|
|
232
237
|
}
|
|
233
238
|
function deviceUseOf(keys, devices) {
|
|
234
239
|
const reasons = [];
|
|
@@ -297,12 +302,18 @@ function worktreeActivityOf(path, keys) {
|
|
|
297
302
|
])?.trim();
|
|
298
303
|
return activityFromGitDir(gitDir, keys);
|
|
299
304
|
}
|
|
300
|
-
async function worktreeActivityOfAsync(path, keys) {
|
|
305
|
+
async function worktreeActivityOfAsync(path, keys, operation) {
|
|
301
306
|
const gitDir = (await gitQuietAsync(path, [
|
|
302
307
|
"rev-parse",
|
|
303
308
|
"--path-format=absolute",
|
|
304
309
|
"--git-dir"
|
|
305
|
-
], {
|
|
310
|
+
], {
|
|
311
|
+
...operation ? childEnvironment(operation.env) : {},
|
|
312
|
+
signal: operation?.signal,
|
|
313
|
+
declareFor: operation,
|
|
314
|
+
cwd: operation?.cwd,
|
|
315
|
+
killSignal: "SIGKILL"
|
|
316
|
+
}))?.trim();
|
|
306
317
|
return activityFromGitDir(gitDir, keys);
|
|
307
318
|
}
|
|
308
319
|
function activityFromGitDir(gitDir, keys) {
|
|
@@ -352,10 +363,14 @@ async function unlessTimedOut(read, unknown) {
|
|
|
352
363
|
throw error;
|
|
353
364
|
}
|
|
354
365
|
}
|
|
355
|
-
async function porcelainOf(path, gitAnswered) {
|
|
366
|
+
async function porcelainOf(path, gitAnswered, operation) {
|
|
356
367
|
if (gitAnswered === null) return null;
|
|
357
368
|
if (!gitAnswered) return [];
|
|
358
|
-
const lines = await unlessTimedOut(() => dirtyPathsAsync(path, { limit: Infinity }
|
|
369
|
+
const lines = await unlessTimedOut(() => dirtyPathsAsync(path, { limit: Infinity }, {
|
|
370
|
+
env: operation?.env,
|
|
371
|
+
signal: operation?.signal,
|
|
372
|
+
declareFor: operation
|
|
373
|
+
}), null);
|
|
359
374
|
return lines?.length ? lines : null;
|
|
360
375
|
}
|
|
361
376
|
function candidateRoots() {
|
|
@@ -367,13 +382,20 @@ function candidateRoots() {
|
|
|
367
382
|
...linkedWorktreesOf(registered)
|
|
368
383
|
])].filter((root) => existsSync$1(root)).toSorted();
|
|
369
384
|
}
|
|
370
|
-
async function candidateRootsAsync() {
|
|
385
|
+
async function candidateRootsAsync(operation) {
|
|
386
|
+
operation?.signal.throwIfAborted();
|
|
387
|
+
const options = {
|
|
388
|
+
env: operation?.env,
|
|
389
|
+
signal: operation?.signal,
|
|
390
|
+
declareFor: operation
|
|
391
|
+
};
|
|
371
392
|
const registered = Object.keys(loadConfig$1()?.projects ?? {}).filter(isAbsolute$1);
|
|
372
393
|
const recorded = listWorkspaceDirs().flatMap((entry) => entry.projectRoot ? [entry.projectRoot] : []);
|
|
373
394
|
const linked = /* @__PURE__ */ new Set();
|
|
374
395
|
for (const root of registered) {
|
|
396
|
+
operation?.signal.throwIfAborted();
|
|
375
397
|
if (!existsSync$1(root)) continue;
|
|
376
|
-
const { entries, ...source } = await resolveSourceCheckoutAsync(root);
|
|
398
|
+
const { entries, ...source } = await resolveSourceCheckoutAsync(root, options);
|
|
377
399
|
if ("refusal" in source) continue;
|
|
378
400
|
for (const entry of entries) if (!entry.bare && !entry.prunable && entry.path !== source.path) linked.add(entry.path);
|
|
379
401
|
}
|
|
@@ -394,8 +416,8 @@ function linkedWorktreesOf(roots) {
|
|
|
394
416
|
}
|
|
395
417
|
return [...linked];
|
|
396
418
|
}
|
|
397
|
-
async function staleFetch(repo, now, freshMs) {
|
|
398
|
-
const at = await lastFetchedAtAsync(repo);
|
|
419
|
+
async function staleFetch(repo, now, freshMs, execution) {
|
|
420
|
+
const at = await lastFetchedAtAsync(repo, execution);
|
|
399
421
|
if (at !== null && now - at < freshMs) return null;
|
|
400
422
|
return at === null ? "the repository has no recorded fetch" : `the repository was last fetched ${formatLongDuration(Math.max(0, now - at))} ago`;
|
|
401
423
|
}
|
|
@@ -412,18 +434,27 @@ function notRefreshedNote(fetch, facts) {
|
|
|
412
434
|
const stale = [fetch, lookup && "unavailable" in lookup && lookup.unavailable === PULL_REQUEST_NOT_CHECKED ? "its pull request was not checked" : null].filter(Boolean);
|
|
413
435
|
return stale.length ? `merge state not refreshed: ${stale.join(", ")}; the next maintenance worktree check, which a stim command starts when it is due, or \`stim gc --delete\` checks again` : null;
|
|
414
436
|
}
|
|
415
|
-
async function checkMergeStates(pending, idle, grace, noOwnCommitsIdleMs, refresh, freshMs) {
|
|
437
|
+
async function checkMergeStates(pending, idle, grace, noOwnCommitsIdleMs, refresh, freshMs, operation) {
|
|
416
438
|
const repos = /* @__PURE__ */ new Map();
|
|
439
|
+
const execution = {
|
|
440
|
+
...operation ? childEnvironment(operation.env) : {},
|
|
441
|
+
signal: operation?.signal,
|
|
442
|
+
declareFor: operation,
|
|
443
|
+
cwd: operation?.cwd,
|
|
444
|
+
killSignal: "SIGKILL"
|
|
445
|
+
};
|
|
417
446
|
for (const entry of pending) repos.set(entry.repo, [...repos.get(entry.repo) ?? [], entry]);
|
|
418
447
|
for (const [repo, entries] of repos) {
|
|
419
|
-
|
|
420
|
-
const
|
|
448
|
+
operation?.signal.throwIfAborted();
|
|
449
|
+
const target = refresh ? await fetchDefaultBranchAsync(repo, grace.now, execution) : await localDefaultBranchAsync(repo, execution);
|
|
450
|
+
const fetch = refresh ? null : await staleFetch(repo, grace.now, freshMs, execution);
|
|
421
451
|
for (const { candidate, facts } of entries) {
|
|
452
|
+
operation?.signal.throwIfAborted();
|
|
422
453
|
const merge = "error" in target ? {
|
|
423
454
|
merged: false,
|
|
424
455
|
unknown: true,
|
|
425
456
|
detail: `merge state unknown: ${target.error}`
|
|
426
|
-
} : await mergeStateAsync(candidate.path, target);
|
|
457
|
+
} : await mergeStateAsync(candidate.path, target, execution);
|
|
427
458
|
const verdict = worktreeSkipReason({
|
|
428
459
|
...facts,
|
|
429
460
|
merge
|
|
@@ -442,8 +473,8 @@ async function checkMergeStates(pending, idle, grace, noOwnCommitsIdleMs, refres
|
|
|
442
473
|
* Classifies each linked worktree of a registered project or its repository. A merged one is removable; with `idle`, so is one unused for
|
|
443
474
|
* `olderThan` days; with `removesNoOwnCommits`, so is one with no commits of its own beyond the default branch whose
|
|
444
475
|
* last activity is older than the grace period, and never younger than 5 minutes. Device use is read last, in one pass against one simulator list and one AVD resolver, so
|
|
445
|
-
* the resolver's time budget covers only device reads. Pull requests are asked once per repository,
|
|
446
|
-
*
|
|
476
|
+
* the resolver's time budget covers only device reads. Pull requests are asked once per repository, sequentially
|
|
477
|
+
* with an operation and concurrently otherwise. Merge state is checked only where it decides the verdict, after one fetch per repository.
|
|
447
478
|
* Without `refresh`, it runs no fetch and no `gh`: merge state comes from the existing remote-tracking ref and pull
|
|
448
479
|
* requests from the cache `status --watch` writes, and a kept verdict that fresher state could change says so.
|
|
449
480
|
*/
|
|
@@ -456,11 +487,18 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
456
487
|
const freshMs = refresh ? 0 : reportFreshMs(operation);
|
|
457
488
|
const noOwnCommitsIdleMs = removesNoOwnCommits ? Math.max(grace.ms, NO_OWN_COMMITS_PRESSURE_FLOOR_MS) : null;
|
|
458
489
|
const groups = /* @__PURE__ */ new Map();
|
|
490
|
+
operation?.signal.throwIfAborted();
|
|
491
|
+
const read = {
|
|
492
|
+
env: operation?.env,
|
|
493
|
+
signal: operation?.signal,
|
|
494
|
+
declareFor: operation
|
|
495
|
+
};
|
|
459
496
|
const outside = [];
|
|
460
|
-
const candidates = await candidateRootsAsync();
|
|
497
|
+
const candidates = await candidateRootsAsync(operation);
|
|
461
498
|
if (candidates.length) phase("worktrees", `checking ${plural(candidates.length, "project")} for merged or idle worktrees`, operation);
|
|
462
499
|
for (const root of candidates) {
|
|
463
|
-
|
|
500
|
+
operation?.signal.throwIfAborted();
|
|
501
|
+
const entry = matchWorktreeEntry(await listWorktreesAsync(root, read), root);
|
|
464
502
|
if (!entry) {
|
|
465
503
|
outside.push({
|
|
466
504
|
path: root,
|
|
@@ -480,22 +518,23 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
480
518
|
}
|
|
481
519
|
const inspected = [];
|
|
482
520
|
for (const [path, roots] of groups) {
|
|
483
|
-
|
|
521
|
+
operation?.signal.throwIfAborted();
|
|
522
|
+
const { entries, ...source } = await resolveSourceCheckoutAsync(path, read);
|
|
484
523
|
const entry = matchWorktreeEntry(entries, path);
|
|
485
524
|
const keys = [.../* @__PURE__ */ new Set([...roots, ...reclaimKeys(path)])];
|
|
486
525
|
const idleDays = idleDaysOf(keys, now);
|
|
487
526
|
const linked = !("refusal" in source) && entry !== null && source.path !== entry.path;
|
|
488
|
-
const activity = linked && (grace.ms > 0 || days !== null || removesNoOwnCommits) ? await worktreeActivityOfAsync(path, keys) : null;
|
|
489
|
-
const gitAnswered = linked ? await unlessTimedOut(() => hasUncommittedWorkAsync(path), null) : null;
|
|
490
|
-
const head = linked ? await resolveFullRefAsync(path, "HEAD") : null;
|
|
527
|
+
const activity = linked && (grace.ms > 0 || days !== null || removesNoOwnCommits) ? await worktreeActivityOfAsync(path, keys, operation) : null;
|
|
528
|
+
const gitAnswered = linked ? await unlessTimedOut(() => hasUncommittedWorkAsync(path, read), null) : null;
|
|
529
|
+
const head = linked ? await resolveFullRefAsync(path, "HEAD", read) : null;
|
|
491
530
|
const facts = {
|
|
492
531
|
source: "refusal" in source ? source : linked ? "linked" : "source",
|
|
493
532
|
bare: Boolean(entry?.bare),
|
|
494
533
|
locked: Boolean(entry?.locked),
|
|
495
534
|
nested: entry ? nestedWorktrees(entries, entry.path) : [],
|
|
496
|
-
porcelain: await porcelainOf(path, gitAnswered),
|
|
497
|
-
unpushed: linked ? await unlessTimedOut(() => unpushedCommitsAsync(path), null) : null,
|
|
498
|
-
submodules: linked ? await unlessTimedOut(() => hasPopulatedSubmodulesAsync(path), null) : false,
|
|
535
|
+
porcelain: await porcelainOf(path, gitAnswered, operation),
|
|
536
|
+
unpushed: linked ? await unlessTimedOut(() => unpushedCommitsAsync(path, read), null) : null,
|
|
537
|
+
submodules: linked ? await unlessTimedOut(() => hasPopulatedSubmodulesAsync(path, read), null) : false,
|
|
499
538
|
inUse: [],
|
|
500
539
|
idleDays,
|
|
501
540
|
merge: null,
|
|
@@ -521,10 +560,10 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
521
560
|
});
|
|
522
561
|
}
|
|
523
562
|
const linked = inspected.filter(({ facts }) => facts.source === "linked");
|
|
524
|
-
for (const { candidate, facts } of linked)
|
|
525
|
-
const devices = await reportDeviceReads(linked.flatMap(({ candidate }) => candidate.keys));
|
|
563
|
+
for (const { candidate, facts } of linked) for (const key of candidate.keys) facts.inUse.push(...await workspaceInUseAsync(key, { managedLocks: true }, operation?.signal, operation));
|
|
564
|
+
const devices = await reportDeviceReads(linked.flatMap(({ candidate }) => candidate.keys), operation);
|
|
526
565
|
for (const { candidate, facts } of linked) facts.inUse = [.../* @__PURE__ */ new Set([...facts.inUse, ...deviceUseOf(candidate.keys, devices)])];
|
|
527
|
-
if (refresh) await lookUpPullRequests(inspected);
|
|
566
|
+
if (refresh) await lookUpPullRequests(inspected, operation);
|
|
528
567
|
else readCachedPullRequests(inspected, now, freshMs);
|
|
529
568
|
const worktrees = [];
|
|
530
569
|
const pending = [];
|
|
@@ -543,7 +582,7 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
543
582
|
});
|
|
544
583
|
worktrees.push(candidate);
|
|
545
584
|
}
|
|
546
|
-
await checkMergeStates(pending, days, grace, noOwnCommitsIdleMs, refresh, freshMs);
|
|
585
|
+
await checkMergeStates(pending, days, grace, noOwnCommitsIdleMs, refresh, freshMs, operation);
|
|
547
586
|
const listed = [...worktrees, ...outside].filter((w) => idle || w.skipCode !== "not-a-worktree" && w.skipCode !== "source-checkout");
|
|
548
587
|
return {
|
|
549
588
|
idle: days === null ? null : {
|
|
@@ -556,7 +595,7 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
556
595
|
worktrees: listed
|
|
557
596
|
};
|
|
558
597
|
}
|
|
559
|
-
async function lookUpPullRequests(inspected) {
|
|
598
|
+
async function lookUpPullRequests(inspected, operation) {
|
|
560
599
|
const repos = /* @__PURE__ */ new Map();
|
|
561
600
|
for (const { candidate, facts, repo, branch } of inspected) {
|
|
562
601
|
if (repo === null || branch === null || candidate.head === null) continue;
|
|
@@ -570,11 +609,12 @@ async function lookUpPullRequests(inspected) {
|
|
|
570
609
|
query
|
|
571
610
|
}]);
|
|
572
611
|
}
|
|
573
|
-
const lookup = pullRequestLookups();
|
|
574
|
-
|
|
612
|
+
const lookup = pullRequestLookups({ operation });
|
|
613
|
+
const probes = [...repos].map(([repo, entries]) => async () => {
|
|
575
614
|
const answers = await lookup(repo, entries.map(({ query }) => query));
|
|
576
615
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
577
616
|
entries.forEach(({ facts, query }, i) => {
|
|
617
|
+
operation?.signal.throwIfAborted();
|
|
578
618
|
const answer = answers[i] ?? null;
|
|
579
619
|
facts.pullRequest = answer;
|
|
580
620
|
if (answer && "pullRequest" in answer) recordPullRequestLookup({
|
|
@@ -583,7 +623,12 @@ async function lookUpPullRequests(inspected) {
|
|
|
583
623
|
head: query.head
|
|
584
624
|
}, answer.pullRequest, at);
|
|
585
625
|
});
|
|
586
|
-
})
|
|
626
|
+
});
|
|
627
|
+
if (operation) for (const probe of probes) {
|
|
628
|
+
operation.signal.throwIfAborted();
|
|
629
|
+
await probe();
|
|
630
|
+
}
|
|
631
|
+
else await Promise.all(probes.map((probe) => probe()));
|
|
587
632
|
}
|
|
588
633
|
function readCachedPullRequests(inspected, now, freshMs) {
|
|
589
634
|
let gh;
|
|
@@ -613,33 +658,43 @@ function cachedPullRequest(cached, branch, head, now, freshMs) {
|
|
|
613
658
|
endedAt: open ? null : endedAt ?? null
|
|
614
659
|
} };
|
|
615
660
|
}
|
|
616
|
-
function noOwnCommitsRecheck(sweep, path, keys, now) {
|
|
661
|
+
async function noOwnCommitsRecheck(sweep, path, keys, now, operation) {
|
|
617
662
|
if (!sweep.idle) {
|
|
618
663
|
if (sweep.noOwnCommitsIdleMs === null) return "it has no commits of its own and is not idle";
|
|
619
|
-
return noOwnCommitsActivityBlocker(
|
|
664
|
+
return noOwnCommitsActivityBlocker(await worktreeActivityOfAsync(path, keys, operation), sweep.noOwnCommitsIdleMs, now)?.text ?? null;
|
|
620
665
|
}
|
|
621
666
|
const idleDays = idleDaysOf(keys, now);
|
|
622
667
|
if (idleDays !== null) return idleDays < sweep.idle.olderThan ? `used ${idleDays}d ago since gc checked it` : null;
|
|
623
|
-
const activity =
|
|
668
|
+
const activity = await worktreeActivityOfAsync(path, keys, operation);
|
|
624
669
|
if (!activity) return "its last activity could not be read";
|
|
625
670
|
const days = activityIdleDays(activity, now);
|
|
626
671
|
return days < sweep.idle.olderThan ? `active ${days}d ago since gc checked it: ${activity.basis}` : null;
|
|
627
672
|
}
|
|
628
|
-
async function removeWorktrees(sweep, { now = Date.now() } = {}) {
|
|
673
|
+
async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, output = GC_OUTPUT) {
|
|
629
674
|
let failures = 0;
|
|
630
675
|
for (const candidate of sweep.worktrees) {
|
|
676
|
+
operation?.signal.throwIfAborted();
|
|
631
677
|
if (candidate.skipped) continue;
|
|
632
678
|
let kept = [];
|
|
633
|
-
const guard = (lockedKeys) => {
|
|
679
|
+
const guard = async (lockedKeys) => {
|
|
634
680
|
const keys = [.../* @__PURE__ */ new Set([...candidate.keys, ...lockedKeys])];
|
|
635
681
|
const unlocked = keys.filter((key) => !lockedKeys.includes(key));
|
|
636
|
-
const
|
|
682
|
+
const devices = await reportDeviceReads(keys, operation);
|
|
683
|
+
const reasons = [...await inUseOf(lockedKeys, { managedLocks: false }, devices, operation?.signal, operation), ...await inUseOf(unlocked, { managedLocks: true }, devices, operation?.signal, operation)].map((r) => `in use: ${r}`);
|
|
637
684
|
const mergedHead = candidate.merge?.merged ? candidate.merge.head : endedPullRequest(candidate.pullRequest) ? candidate.head : null;
|
|
638
685
|
if (mergedHead) {
|
|
639
|
-
if (
|
|
686
|
+
if (await resolveFullRefAsync(candidate.path, "HEAD", {
|
|
687
|
+
env: operation?.env,
|
|
688
|
+
signal: operation?.signal,
|
|
689
|
+
declareFor: operation
|
|
690
|
+
}) !== mergedHead) reasons.push("its HEAD moved since gc checked it");
|
|
640
691
|
} else if (hasNoOwnCommits(candidate.merge)) {
|
|
641
|
-
if (
|
|
642
|
-
|
|
692
|
+
if (await resolveFullRefAsync(candidate.path, "HEAD", {
|
|
693
|
+
env: operation?.env,
|
|
694
|
+
signal: operation?.signal,
|
|
695
|
+
declareFor: operation
|
|
696
|
+
}) !== candidate.head) reasons.push("its HEAD moved since gc checked it");
|
|
697
|
+
const recent = await noOwnCommitsRecheck(sweep, candidate.path, keys, Date.now(), operation);
|
|
643
698
|
if (recent) reasons.push(recent);
|
|
644
699
|
} else {
|
|
645
700
|
const idleDays = idleDaysOf(keys, now);
|
|
@@ -649,7 +704,7 @@ async function removeWorktrees(sweep, { now = Date.now() } = {}) {
|
|
|
649
704
|
const recent = graceBlocker({
|
|
650
705
|
merge: candidate.merge,
|
|
651
706
|
pullRequest: candidate.pullRequest,
|
|
652
|
-
activity:
|
|
707
|
+
activity: await worktreeActivityOfAsync(candidate.path, keys, operation)
|
|
653
708
|
}, {
|
|
654
709
|
ms: sweep.graceMs,
|
|
655
710
|
now: Date.now()
|
|
@@ -669,22 +724,26 @@ async function removeWorktrees(sweep, { now = Date.now() } = {}) {
|
|
|
669
724
|
linkedOnly: true,
|
|
670
725
|
guard,
|
|
671
726
|
mergedHead,
|
|
672
|
-
expectedHead
|
|
727
|
+
expectedHead,
|
|
728
|
+
output,
|
|
729
|
+
operation
|
|
673
730
|
});
|
|
674
731
|
} catch (thrown) {
|
|
732
|
+
if (thrown instanceof WorkspaceProcessCleanupError || thrown instanceof Error && "reportCleanup" in thrown) throw thrown;
|
|
733
|
+
operation?.signal.throwIfAborted();
|
|
675
734
|
error = thrown?.message || String(thrown);
|
|
676
|
-
|
|
735
|
+
output.error(chalk.red(`Could not remove ${candidate.path}: ${error}`));
|
|
677
736
|
}
|
|
678
737
|
if (removed) {
|
|
679
|
-
|
|
680
|
-
|
|
738
|
+
output.log(chalk.green(`Removed the worktree ${candidate.path} (${worktreeRemovalReason(candidate, sweep)})`));
|
|
739
|
+
output.record("worktree", "done", candidate.path, { detail: worktreeRemovalReason(candidate, sweep) });
|
|
681
740
|
} else if (kept.length) {
|
|
682
|
-
|
|
683
|
-
|
|
741
|
+
output.log(chalk.yellow(`Kept the worktree ${candidate.path}: ${kept.join("; ")}`));
|
|
742
|
+
output.record("worktree", "kept", candidate.path, { detail: kept.join("; ") });
|
|
684
743
|
} else {
|
|
685
744
|
failures++;
|
|
686
|
-
|
|
687
|
-
|
|
745
|
+
output.error(chalk.yellow(`Kept the worktree ${candidate.path}; see the lines above for why.`));
|
|
746
|
+
output.record("worktree", "failed", candidate.path, { detail: error ?? "stim worktree remove did not remove it; see the details" });
|
|
688
747
|
}
|
|
689
748
|
}
|
|
690
749
|
return failures;
|
|
@@ -874,9 +933,11 @@ async function maintenancePinnedAsync(root, operation) {
|
|
|
874
933
|
try {
|
|
875
934
|
return maintenanceKeepSetting((await resolveProjectSettingsAsync(root, {
|
|
876
935
|
env: operation.env,
|
|
877
|
-
signal: operation.signal
|
|
936
|
+
signal: operation.signal,
|
|
937
|
+
declareFor: operation
|
|
878
938
|
})).settings);
|
|
879
|
-
} catch {
|
|
939
|
+
} catch (error) {
|
|
940
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
880
941
|
operation.signal.throwIfAborted();
|
|
881
942
|
return true;
|
|
882
943
|
}
|
|
@@ -909,14 +970,19 @@ function cachedDeviceActivity(now) {
|
|
|
909
970
|
return answer.devices;
|
|
910
971
|
};
|
|
911
972
|
}
|
|
912
|
-
function cachedDeviceActivityAsync(now, env) {
|
|
973
|
+
function cachedDeviceActivityAsync(now, env, signal, operation) {
|
|
913
974
|
const answers = /* @__PURE__ */ new Map();
|
|
914
975
|
return (withSims) => {
|
|
915
976
|
let answer = answers.get(withSims);
|
|
916
977
|
if (!answer) {
|
|
917
978
|
answer = (async () => {
|
|
918
|
-
|
|
919
|
-
|
|
979
|
+
signal?.throwIfAborted();
|
|
980
|
+
const sims = withSims ? await listAllIosSimsAsync({
|
|
981
|
+
timeoutMs: DEVICE_LIST_TIMEOUT_MS,
|
|
982
|
+
signal,
|
|
983
|
+
operation
|
|
984
|
+
}) : [];
|
|
985
|
+
return collectOwnedDeviceActivityAsync(loadConfig$1(), sims, now, env, signal, operation);
|
|
920
986
|
})();
|
|
921
987
|
answers.set(withSims, answer);
|
|
922
988
|
}
|
|
@@ -955,12 +1021,15 @@ function workspaceActiveReason(root, now, windowMs, devices = (withSims) => read
|
|
|
955
1021
|
}
|
|
956
1022
|
return step.value;
|
|
957
1023
|
}
|
|
958
|
-
async function workspaceActiveReasonAsync(root, now, windowMs, devices) {
|
|
1024
|
+
async function workspaceActiveReasonAsync(root, now, windowMs, devices, signal) {
|
|
959
1025
|
const checks = workspaceActiveChecks(root, now, windowMs);
|
|
960
1026
|
let step = checks.next();
|
|
961
1027
|
while (!step.done) try {
|
|
1028
|
+
signal?.throwIfAborted();
|
|
962
1029
|
step = checks.next(await devices(step.value));
|
|
963
1030
|
} catch (error) {
|
|
1031
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1032
|
+
signal?.throwIfAborted();
|
|
964
1033
|
step = checks.throw(error);
|
|
965
1034
|
}
|
|
966
1035
|
return step.value;
|
|
@@ -1105,13 +1174,13 @@ function planDeviceDeletion(options) {
|
|
|
1105
1174
|
while (!step.done) step = checks.next(workspaceActiveReason(step.value, options.now, options.windowMs, activity));
|
|
1106
1175
|
return step.value;
|
|
1107
1176
|
}
|
|
1108
|
-
async function planDeviceDeletionAsync(options, signal) {
|
|
1109
|
-
const activity = cachedDeviceActivityAsync(options.now, options.env ?? process.env);
|
|
1177
|
+
async function planDeviceDeletionAsync(options, signal, operation) {
|
|
1178
|
+
const activity = cachedDeviceActivityAsync(options.now, options.env ?? process.env, signal, operation);
|
|
1110
1179
|
const checks = deviceDeletionChecks(options);
|
|
1111
1180
|
let step = checks.next();
|
|
1112
1181
|
while (!step.done) {
|
|
1113
1182
|
signal.throwIfAborted();
|
|
1114
|
-
step = checks.next(await workspaceActiveReasonAsync(step.value, options.now, options.windowMs, activity));
|
|
1183
|
+
step = checks.next(await workspaceActiveReasonAsync(step.value, options.now, options.windowMs, activity, signal));
|
|
1115
1184
|
}
|
|
1116
1185
|
return step.value;
|
|
1117
1186
|
}
|
|
@@ -1151,11 +1220,14 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1151
1220
|
const skips = [];
|
|
1152
1221
|
const blocked = [];
|
|
1153
1222
|
const days = settings.olderThanDays;
|
|
1154
|
-
|
|
1223
|
+
const outputs = await collectWorkspaceOutputs({
|
|
1155
1224
|
olderThan: days,
|
|
1156
1225
|
now,
|
|
1157
|
-
measure: false
|
|
1158
|
-
|
|
1226
|
+
measure: false,
|
|
1227
|
+
signal: operation?.signal,
|
|
1228
|
+
operation
|
|
1229
|
+
});
|
|
1230
|
+
for (const entry of outputs.workspaces) {
|
|
1159
1231
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
1160
1232
|
if (root === null || !entry.willClear || root === protectedRoot) continue;
|
|
1161
1233
|
if (pinned(root)) {
|
|
@@ -1187,7 +1259,10 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1187
1259
|
check: "sweep"
|
|
1188
1260
|
});
|
|
1189
1261
|
try {
|
|
1190
|
-
const orphans = collectOrphanedWorkspaces(Object.keys(loadConfig$1()?.projects ?? {}), listMountedVolumes(), {
|
|
1262
|
+
const orphans = await collectOrphanedWorkspaces(Object.keys(loadConfig$1()?.projects ?? {}), listMountedVolumes(), {
|
|
1263
|
+
measure: false,
|
|
1264
|
+
operation
|
|
1265
|
+
});
|
|
1191
1266
|
for (const orphan of orphans.orphaned) actions.push({
|
|
1192
1267
|
kind: "would-remove-orphan",
|
|
1193
1268
|
target: orphan.dir,
|
|
@@ -1200,6 +1275,8 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1200
1275
|
reason: kept.reason
|
|
1201
1276
|
});
|
|
1202
1277
|
} catch (error) {
|
|
1278
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1279
|
+
operation?.signal.throwIfAborted();
|
|
1203
1280
|
blocked.push(`Could not look for orphaned workspace directories: ${error instanceof Error ? error.message : error}`);
|
|
1204
1281
|
}
|
|
1205
1282
|
if (devices && settings.deviceIdleDays > 0) {
|
|
@@ -1217,7 +1294,7 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1217
1294
|
},
|
|
1218
1295
|
env: operation?.env
|
|
1219
1296
|
};
|
|
1220
|
-
const reaped = operation ? await planDeviceDeletionAsync(options, operation.signal) : planDeviceDeletion(options);
|
|
1297
|
+
const reaped = operation ? await planDeviceDeletionAsync(options, operation.signal, operation) : planDeviceDeletion(options);
|
|
1221
1298
|
actions.push(...reaped.actions);
|
|
1222
1299
|
skips.push(...reaped.skips);
|
|
1223
1300
|
}
|
|
@@ -1285,7 +1362,7 @@ async function planWorktrees({ protectedRoot, pinned, now, level, graceMs, sizes
|
|
|
1285
1362
|
extra: { check: "worktree" },
|
|
1286
1363
|
env: operation?.env
|
|
1287
1364
|
};
|
|
1288
|
-
const devices = operation ? await planDeviceDeletionAsync(options, operation.signal) : planDeviceDeletion(options);
|
|
1365
|
+
const devices = operation ? await planDeviceDeletionAsync(options, operation.signal, operation) : planDeviceDeletion(options);
|
|
1289
1366
|
actions.push(...devices.actions);
|
|
1290
1367
|
skips.push(...devices.skips);
|
|
1291
1368
|
}
|
|
@@ -1343,11 +1420,15 @@ function artifactWorktree(root, entries, source = sourceCheckoutOf(entries)) {
|
|
|
1343
1420
|
keys
|
|
1344
1421
|
};
|
|
1345
1422
|
}
|
|
1346
|
-
async function artifactWorktreesAsync(signal) {
|
|
1423
|
+
async function artifactWorktreesAsync(signal, operation) {
|
|
1347
1424
|
const found = /* @__PURE__ */ new Map();
|
|
1348
|
-
for (const root of await candidateRootsAsync()) {
|
|
1425
|
+
for (const root of await candidateRootsAsync(operation)) {
|
|
1349
1426
|
signal.throwIfAborted();
|
|
1350
|
-
const { entries, ...source } = await resolveSourceCheckoutAsync(root
|
|
1427
|
+
const { entries, ...source } = await resolveSourceCheckoutAsync(root, {
|
|
1428
|
+
env: operation?.env,
|
|
1429
|
+
signal,
|
|
1430
|
+
declareFor: operation
|
|
1431
|
+
});
|
|
1351
1432
|
const entry = artifactWorktree(root, entries, source);
|
|
1352
1433
|
if (entry) found.set(entry.path, entry);
|
|
1353
1434
|
}
|
|
@@ -1440,10 +1521,10 @@ function artifactGuard(candidate, kind, pinned, locked) {
|
|
|
1440
1521
|
if (inUse.length) return `in use: ${inUse.join("; ")}`;
|
|
1441
1522
|
return null;
|
|
1442
1523
|
}
|
|
1443
|
-
async function collectArtifactsAsync(kind, options, signal) {
|
|
1524
|
+
async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
1444
1525
|
const candidates = [];
|
|
1445
1526
|
const skips = [];
|
|
1446
|
-
for (const worktree of await artifactWorktreesAsync(signal)) {
|
|
1527
|
+
for (const worktree of await artifactWorktreesAsync(signal, operation)) {
|
|
1447
1528
|
if (kind === "dependencies" && !worktree.linked) continue;
|
|
1448
1529
|
const root = canonicalPath(worktree.path);
|
|
1449
1530
|
const protectedHere = options.protectedRoot === root || options.protectedRoot.startsWith(`${root}${sep}`);
|
|
@@ -1479,11 +1560,17 @@ async function collectArtifactsAsync(kind, options, signal) {
|
|
|
1479
1560
|
"ls-files",
|
|
1480
1561
|
"--",
|
|
1481
1562
|
relative(worktree.path, path)
|
|
1482
|
-
]
|
|
1563
|
+
], {
|
|
1564
|
+
...operation ? childEnvironment(operation.env) : {},
|
|
1565
|
+
cwd: operation?.cwd,
|
|
1566
|
+
signal,
|
|
1567
|
+
declareFor: operation,
|
|
1568
|
+
killSignal: "SIGKILL"
|
|
1569
|
+
});
|
|
1483
1570
|
const untracked = tracked !== null && !tracked.trim();
|
|
1484
1571
|
reason = keptReason(candidate, kind, options, {
|
|
1485
1572
|
tracked,
|
|
1486
|
-
activity: untracked ? await worktreeActivityOfAsync(worktree.path, worktree.keys) : null,
|
|
1573
|
+
activity: untracked ? await worktreeActivityOfAsync(worktree.path, worktree.keys, operation) : null,
|
|
1487
1574
|
written: untracked ? await newestWriteAsync(path, SCAN_DEPTH[kind], signal) : null
|
|
1488
1575
|
});
|
|
1489
1576
|
}
|
|
@@ -1691,17 +1778,18 @@ function inside(parent, path) {
|
|
|
1691
1778
|
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
1692
1779
|
}
|
|
1693
1780
|
/** Basenames of running executables, or null when the process list cannot be read. */
|
|
1694
|
-
async function runningExecutables() {
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1781
|
+
async function runningExecutables(operation, signal) {
|
|
1782
|
+
const out = await runOperationFileQuiet(operation, getExecutor(), "ps", [
|
|
1783
|
+
"-axww",
|
|
1784
|
+
"-o",
|
|
1785
|
+
"comm="
|
|
1786
|
+
], {
|
|
1787
|
+
timeoutMs: 1e4,
|
|
1788
|
+
cwd: operation?.cwd,
|
|
1789
|
+
signal
|
|
1790
|
+
});
|
|
1791
|
+
if (out === null) return null;
|
|
1792
|
+
return new Set(out.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => basename(line)));
|
|
1705
1793
|
}
|
|
1706
1794
|
function stimKept(identity, scan, projects) {
|
|
1707
1795
|
const registered = projects.find((root) => inside(identity, root) || inside(root, identity));
|
|
@@ -1728,7 +1816,7 @@ function temporaryRoot(env) {
|
|
|
1728
1816
|
* 24 hours. Null with STIM_HOME set, because TMPDIR is shared by every Stim home, and for the real TMPDIR a test
|
|
1729
1817
|
* process recorded in STIM_TEST_GUARD_REAL_TMPDIR.
|
|
1730
1818
|
*/
|
|
1731
|
-
async function collectTempLeftovers({ now = Date.now(), env = process.env, signal } = {}) {
|
|
1819
|
+
async function collectTempLeftovers({ now = Date.now(), env = process.env, signal, operation } = {}) {
|
|
1732
1820
|
if (deviceSweepIsScoped(env)) return null;
|
|
1733
1821
|
let root;
|
|
1734
1822
|
let names;
|
|
@@ -1746,7 +1834,7 @@ async function collectTempLeftovers({ now = Date.now(), env = process.env, signa
|
|
|
1746
1834
|
let projects = registeredProjects();
|
|
1747
1835
|
let executables;
|
|
1748
1836
|
const traceBusy = async () => {
|
|
1749
|
-
if (executables === void 0) executables = await runningExecutables();
|
|
1837
|
+
if (executables === void 0) executables = await runningExecutables(operation, signal);
|
|
1750
1838
|
const listed = executables;
|
|
1751
1839
|
if (listed === null) return "the running processes could not be listed";
|
|
1752
1840
|
const running = [...TRACE_PROCESSES].filter((name) => listed.has(name));
|
|
@@ -1775,7 +1863,11 @@ async function collectTempLeftovers({ now = Date.now(), env = process.env, signa
|
|
|
1775
1863
|
const kind = kindOf(name, stat, jestName);
|
|
1776
1864
|
if (!kind) continue;
|
|
1777
1865
|
if (kind === "jest") {
|
|
1778
|
-
const bytes = await directorySizeAsync(path, {
|
|
1866
|
+
const bytes = await directorySizeAsync(path, {
|
|
1867
|
+
timeoutMs: 1e4,
|
|
1868
|
+
signal,
|
|
1869
|
+
operation
|
|
1870
|
+
});
|
|
1779
1871
|
entries.push({
|
|
1780
1872
|
kind,
|
|
1781
1873
|
path,
|
|
@@ -1845,7 +1937,7 @@ function tempLeftoverSection(report) {
|
|
|
1845
1937
|
} : null;
|
|
1846
1938
|
}
|
|
1847
1939
|
/** Deletes what a fresh `collectTempLeftovers` marks for deletion. Returns the bytes freed and the failures. */
|
|
1848
|
-
async function deleteTempLeftovers(options = {}) {
|
|
1940
|
+
async function deleteTempLeftovers(options = {}, output = GC_OUTPUT) {
|
|
1849
1941
|
const report = await collectTempLeftovers(options);
|
|
1850
1942
|
const done = {
|
|
1851
1943
|
count: 0,
|
|
@@ -1861,7 +1953,7 @@ async function deleteTempLeftovers(options = {}) {
|
|
|
1861
1953
|
const staged = entry.kind === "xctrace" || name.startsWith(STAGING_PREFIX) ? entry.path : join(report.root, `${STAGING_PREFIX}${name}`);
|
|
1862
1954
|
const before = staged === entry.path ? null : await report.recheck?.(entry.path, entry.path, entry.kind) ?? null;
|
|
1863
1955
|
if (before) {
|
|
1864
|
-
|
|
1956
|
+
output.record("tempLeftover", "kept", entry.path, {
|
|
1865
1957
|
bytes: entry.bytes,
|
|
1866
1958
|
detail: before
|
|
1867
1959
|
});
|
|
@@ -1873,6 +1965,7 @@ async function deleteTempLeftovers(options = {}) {
|
|
|
1873
1965
|
const original = name.startsWith(STAGING_PREFIX) ? join(report.root, name.slice(13)) : entry.path;
|
|
1874
1966
|
kept = await report.recheck?.(staged, original, entry.kind) ?? null;
|
|
1875
1967
|
} catch (error) {
|
|
1968
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1876
1969
|
kept = `it could not be checked again: ${errorCode(error)}`;
|
|
1877
1970
|
if (options.signal?.aborted) {
|
|
1878
1971
|
if (staged !== entry.path) await rename(staged, entry.path).catch(() => {});
|
|
@@ -1885,32 +1978,33 @@ async function deleteTempLeftovers(options = {}) {
|
|
|
1885
1978
|
if (staged !== entry.path) await rename(staged, entry.path);
|
|
1886
1979
|
} catch (error) {
|
|
1887
1980
|
detail = `${kept}; it stays at ${staged} because it could not be renamed back: ${errorCode(error)}`;
|
|
1888
|
-
|
|
1981
|
+
output.log(chalk.yellow(`Kept ${entry.path} at ${staged}: ${detail}`));
|
|
1889
1982
|
}
|
|
1890
|
-
|
|
1983
|
+
output.record("tempLeftover", "kept", entry.path, {
|
|
1891
1984
|
bytes: entry.bytes,
|
|
1892
1985
|
detail
|
|
1893
1986
|
});
|
|
1894
1987
|
continue;
|
|
1895
1988
|
}
|
|
1896
|
-
|
|
1989
|
+
await removeTemporaryEntryAsync(staged, options.signal);
|
|
1897
1990
|
done.count++;
|
|
1898
1991
|
done.bytes += entry.bytes;
|
|
1899
1992
|
} catch (error) {
|
|
1993
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1900
1994
|
if (options.signal?.aborted) throw error;
|
|
1901
1995
|
if (errorCode(error) === "ENOENT") continue;
|
|
1902
1996
|
done.failures++;
|
|
1903
1997
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1904
|
-
|
|
1905
|
-
|
|
1998
|
+
output.log(chalk.red(`Could not delete ${entry.path}: ${detail}`));
|
|
1999
|
+
output.record("tempLeftover", "failed", entry.path, {
|
|
1906
2000
|
bytes: entry.bytes,
|
|
1907
2001
|
detail
|
|
1908
2002
|
});
|
|
1909
2003
|
}
|
|
1910
2004
|
}
|
|
1911
2005
|
if (done.count) {
|
|
1912
|
-
|
|
1913
|
-
|
|
2006
|
+
output.log(chalk.green(`Deleted ${plural(done.count, "TMPDIR leftover")} (${formatBytes(done.bytes)}) in ${report.root}`));
|
|
2007
|
+
output.record("tempLeftover", "done", report.root, {
|
|
1914
2008
|
bytes: done.bytes,
|
|
1915
2009
|
detail: `${plural(done.count, "entry", "entries")} deleted`
|
|
1916
2010
|
});
|
|
@@ -1924,11 +2018,13 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
1924
2018
|
const actions = [];
|
|
1925
2019
|
const skips = [];
|
|
1926
2020
|
const reason = `disk pressure level 2, idle for ${settings.pressureProtectMinutes} minutes`;
|
|
1927
|
-
const outputs = collectWorkspaceOutputs({
|
|
2021
|
+
const outputs = (await collectWorkspaceOutputs({
|
|
1928
2022
|
olderThan: null,
|
|
1929
2023
|
now,
|
|
1930
|
-
measure: false
|
|
1931
|
-
|
|
2024
|
+
measure: false,
|
|
2025
|
+
signal: operation?.signal,
|
|
2026
|
+
operation
|
|
2027
|
+
})).workspaces.flatMap((entry) => {
|
|
1932
2028
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
1933
2029
|
if (root === null || !entry.willClear || root === protectedRoot || pinned(root)) return [];
|
|
1934
2030
|
const used = workspaceLastUsed(root);
|
|
@@ -1958,7 +2054,8 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
1958
2054
|
const leftovers = await collectTempLeftovers({
|
|
1959
2055
|
now,
|
|
1960
2056
|
env: operation?.env,
|
|
1961
|
-
signal: operation?.signal
|
|
2057
|
+
signal: operation?.signal,
|
|
2058
|
+
operation
|
|
1962
2059
|
});
|
|
1963
2060
|
const deletable = leftovers?.entries.filter((entry) => entry.willDelete) ?? [];
|
|
1964
2061
|
if (leftovers && deletable.length) actions.push({
|
|
@@ -1974,7 +2071,7 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
1974
2071
|
protectedRoot,
|
|
1975
2072
|
pinned
|
|
1976
2073
|
};
|
|
1977
|
-
const build = operation ? await collectArtifactsAsync("build", options, operation.signal) : collectArtifacts("build", options);
|
|
2074
|
+
const build = operation ? await collectArtifactsAsync("build", options, operation.signal, operation) : collectArtifacts("build", options);
|
|
1978
2075
|
for (const candidate of build.candidates) actions.push({
|
|
1979
2076
|
kind: "would-clear-build-dirs",
|
|
1980
2077
|
target: candidate.path,
|
|
@@ -1994,7 +2091,7 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
1994
2091
|
extra: { level: 2 },
|
|
1995
2092
|
env: operation?.env
|
|
1996
2093
|
};
|
|
1997
|
-
const devices = operation ? await planDeviceDeletionAsync(deviceOptions, operation.signal) : planDeviceDeletion(deviceOptions);
|
|
2094
|
+
const devices = operation ? await planDeviceDeletionAsync(deviceOptions, operation.signal, operation) : planDeviceDeletion(deviceOptions);
|
|
1998
2095
|
actions.push(...devices.actions);
|
|
1999
2096
|
skips.push(...devices.skips);
|
|
2000
2097
|
return {
|
|
@@ -2049,7 +2146,7 @@ async function planLevel3({ settings, sizes, protectedRoot, pinned, now, refresh
|
|
|
2049
2146
|
}) : null;
|
|
2050
2147
|
actions.push(...worktrees?.actions ?? []);
|
|
2051
2148
|
skips.push(...worktrees?.skips ?? []);
|
|
2052
|
-
const activity = operation ? cachedDeviceActivityAsync(now, operation.env) : null;
|
|
2149
|
+
const activity = operation ? cachedDeviceActivityAsync(now, operation.env, operation.signal, operation) : null;
|
|
2053
2150
|
for (const root of Object.keys(loadConfig$1()?.projects ?? {}).map(canonicalPath)) {
|
|
2054
2151
|
if (root === protectedRoot || pinned(root)) continue;
|
|
2055
2152
|
if (workspaceInUse(root, {
|
|
@@ -2057,7 +2154,7 @@ async function planLevel3({ settings, sizes, protectedRoot, pinned, now, refresh
|
|
|
2057
2154
|
hosted: false,
|
|
2058
2155
|
nativeRun: false
|
|
2059
2156
|
}).length === 0) continue;
|
|
2060
|
-
const active = activity ? await workspaceActiveReasonAsync(root, now, windowMs, activity) : workspaceActiveReason(root, now, windowMs);
|
|
2157
|
+
const active = activity ? await workspaceActiveReasonAsync(root, now, windowMs, activity, operation?.signal) : workspaceActiveReason(root, now, windowMs);
|
|
2061
2158
|
if (active) skips.push({
|
|
2062
2159
|
target: root,
|
|
2063
2160
|
reason: active,
|
|
@@ -2078,7 +2175,7 @@ async function planLevel3({ settings, sizes, protectedRoot, pinned, now, refresh
|
|
|
2078
2175
|
protectedRoot,
|
|
2079
2176
|
pinned
|
|
2080
2177
|
};
|
|
2081
|
-
const dependencies = operation ? await collectArtifactsAsync("dependencies", artifactOptions, operation.signal) : collectArtifacts("dependencies", artifactOptions);
|
|
2178
|
+
const dependencies = operation ? await collectArtifactsAsync("dependencies", artifactOptions, operation.signal, operation) : collectArtifacts("dependencies", artifactOptions);
|
|
2082
2179
|
for (const candidate of dependencies.candidates) actions.push({
|
|
2083
2180
|
kind: "would-delete-dependencies",
|
|
2084
2181
|
target: candidate.path,
|
|
@@ -2163,13 +2260,17 @@ async function plannedMaintenance(pressure, sizes, settings, { devices = true, s
|
|
|
2163
2260
|
dryRun: true,
|
|
2164
2261
|
budget,
|
|
2165
2262
|
env,
|
|
2166
|
-
cwd: operation?.cwd
|
|
2263
|
+
cwd: operation?.cwd,
|
|
2264
|
+
signal: operation?.signal,
|
|
2265
|
+
operation
|
|
2167
2266
|
}, { volumes: () => pressure.disk }) : null;
|
|
2168
2267
|
if (outcome && outcome.status !== "ok") throw new Error(outcome.refusal.message);
|
|
2169
|
-
const outputs = collectWorkspaceOutputs({
|
|
2268
|
+
const outputs = await collectWorkspaceOutputs({
|
|
2170
2269
|
olderThan: null,
|
|
2171
2270
|
now: Date.now(),
|
|
2172
|
-
measure: false
|
|
2271
|
+
measure: false,
|
|
2272
|
+
signal: operation?.signal,
|
|
2273
|
+
operation
|
|
2173
2274
|
});
|
|
2174
2275
|
const currentSizes = sizes.map((size) => {
|
|
2175
2276
|
if (size.category === "compilation-cache") return {
|
|
@@ -2182,14 +2283,18 @@ async function plannedMaintenance(pressure, sizes, settings, { devices = true, s
|
|
|
2182
2283
|
});
|
|
2183
2284
|
const pins = /* @__PURE__ */ new Map();
|
|
2184
2285
|
if (operation) {
|
|
2185
|
-
const candidates = await candidateRootsAsync();
|
|
2286
|
+
const candidates = await candidateRootsAsync(operation);
|
|
2186
2287
|
const roots = /* @__PURE__ */ new Set([
|
|
2187
2288
|
...Object.keys(loadConfig()?.projects ?? {}),
|
|
2188
2289
|
...candidates,
|
|
2189
2290
|
...sizes.flatMap((size) => size.workspace ? [size.workspace] : []),
|
|
2190
2291
|
...outputs.workspaces.flatMap((entry) => entry.projectRoot ? [entry.projectRoot] : [])
|
|
2191
2292
|
]);
|
|
2192
|
-
for (const path of candidates) for (const entry of await listWorktreesAsync(path
|
|
2293
|
+
for (const path of candidates) for (const entry of await listWorktreesAsync(path, {
|
|
2294
|
+
env: operation.env,
|
|
2295
|
+
signal: operation.signal,
|
|
2296
|
+
declareFor: operation
|
|
2297
|
+
})) roots.add(entry.path);
|
|
2193
2298
|
for (const path of Array.from(roots, canonicalPath)) roots.add(path);
|
|
2194
2299
|
for (const path of roots) pins.set(path, await maintenancePinnedAsync(path, operation));
|
|
2195
2300
|
}
|
|
@@ -2294,6 +2399,8 @@ async function previewMaintenance({ devices = true, refresh = true, operation }
|
|
|
2294
2399
|
note: settings.invalid ?? (state === null ? "no pass has run yet; sizes have not been measured" : null)
|
|
2295
2400
|
};
|
|
2296
2401
|
} catch (error) {
|
|
2402
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
2403
|
+
operation?.signal.throwIfAborted();
|
|
2297
2404
|
return {
|
|
2298
2405
|
mode: settings?.mode ?? "off",
|
|
2299
2406
|
...settings?.invalid ? { invalid: settings.invalid } : {},
|
|
@@ -2307,8 +2414,8 @@ async function previewMaintenance({ devices = true, refresh = true, operation }
|
|
|
2307
2414
|
}
|
|
2308
2415
|
//#endregion
|
|
2309
2416
|
//#region src/maintenance/act.ts
|
|
2310
|
-
function freedSince(beforeMb) {
|
|
2311
|
-
const freed = lowestFree(
|
|
2417
|
+
function freedSince(beforeMb, disk = measureDisk()) {
|
|
2418
|
+
const freed = lowestFree(disk) - beforeMb;
|
|
2312
2419
|
return Number.isFinite(freed) && freed > 0 ? Math.round(freed * 1024 * 1024) : 0;
|
|
2313
2420
|
}
|
|
2314
2421
|
const kept = (detail) => ({
|
|
@@ -2470,8 +2577,9 @@ async function deleteParkedDevice(action) {
|
|
|
2470
2577
|
const { results } = await quietly(async () => await deleteParkedSims(sims) + await deleteParkedAvds(avds));
|
|
2471
2578
|
return outcomeOf(results, freedSince(before));
|
|
2472
2579
|
}
|
|
2473
|
-
async function deleteOwnedDevicesOf(root, { noneIsKept = false } = {}) {
|
|
2474
|
-
|
|
2580
|
+
async function deleteOwnedDevicesOf(root, { noneIsKept = false, operation, output = GC_OUTPUT } = {}) {
|
|
2581
|
+
operation?.signal.throwIfAborted();
|
|
2582
|
+
if (deviceSweepIsScoped(operation?.env ?? process.env)) return null;
|
|
2475
2583
|
const config = loadConfig$1();
|
|
2476
2584
|
const project = config?.projects?.[root];
|
|
2477
2585
|
if (!config || !project) return null;
|
|
@@ -2479,9 +2587,20 @@ async function deleteOwnedDevicesOf(root, { noneIsKept = false } = {}) {
|
|
|
2479
2587
|
let sims = [];
|
|
2480
2588
|
let avds = [];
|
|
2481
2589
|
try {
|
|
2482
|
-
if (owns("ios")) sims =
|
|
2483
|
-
|
|
2590
|
+
if (owns("ios")) sims = await listAllIosSimsAsync({
|
|
2591
|
+
timeoutMs: DEVICE_LIST_TIMEOUT_MS,
|
|
2592
|
+
operation,
|
|
2593
|
+
signal: operation?.signal
|
|
2594
|
+
});
|
|
2595
|
+
operation?.signal.throwIfAborted();
|
|
2596
|
+
if (owns("android")) avds = await listAvdsAsync({
|
|
2597
|
+
operation,
|
|
2598
|
+
signal: operation?.signal
|
|
2599
|
+
});
|
|
2600
|
+
operation?.signal.throwIfAborted();
|
|
2484
2601
|
} catch (error) {
|
|
2602
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
2603
|
+
operation?.signal.throwIfAborted();
|
|
2485
2604
|
return {
|
|
2486
2605
|
status: "failed",
|
|
2487
2606
|
bytes: 0,
|
|
@@ -2499,7 +2618,7 @@ async function deleteOwnedDevicesOf(root, { noneIsKept = false } = {}) {
|
|
|
2499
2618
|
lastTouched: () => 0
|
|
2500
2619
|
});
|
|
2501
2620
|
if (noneIsKept && devices.length === 0) return kept("it owns no listed devices any more");
|
|
2502
|
-
const failures = await deleteProjectDevices([], devices, []);
|
|
2621
|
+
const failures = await deleteProjectDevices([], devices, [], output, operation);
|
|
2503
2622
|
return failures ? {
|
|
2504
2623
|
status: "failed",
|
|
2505
2624
|
bytes: 0,
|
|
@@ -2541,16 +2660,31 @@ async function stopWorkspace(action, context) {
|
|
|
2541
2660
|
* Deletes the owned simulators and emulators of a workspace that stays idle for `windowMs`, under its native-run
|
|
2542
2661
|
* claim, without stopping anything: a running dev server, lease, lock or driver keeps every device.
|
|
2543
2662
|
*/
|
|
2544
|
-
async function deleteIdleWorkspaceDevices(root, { windowMs, protectedRoot, purpose }) {
|
|
2663
|
+
async function deleteIdleWorkspaceDevices(root, { windowMs, protectedRoot, purpose, operation, output }) {
|
|
2664
|
+
operation?.signal.throwIfAborted();
|
|
2545
2665
|
if (root === protectedRoot) return kept("the command that started this pass runs in it");
|
|
2546
|
-
if (maintenancePinned(root)) return kept("pinned by maintenance.keep");
|
|
2547
|
-
if (deviceSweepIsScoped()) return kept("STIM_HOME scopes this config, and devices are machine-wide");
|
|
2548
|
-
const
|
|
2666
|
+
if (operation ? await maintenancePinnedAsync(root, operation) : maintenancePinned(root)) return kept("pinned by maintenance.keep");
|
|
2667
|
+
if (deviceSweepIsScoped(operation?.env ?? process.env)) return kept("STIM_HOME scopes this config, and devices are machine-wide");
|
|
2668
|
+
const activeReason = async () => {
|
|
2669
|
+
const now = Date.now();
|
|
2670
|
+
if (!operation) return workspaceActiveReason(root, now, windowMs);
|
|
2671
|
+
const reason = await workspaceActiveReasonAsync(root, now, windowMs, cachedDeviceActivityAsync(now, operation.env, operation.signal, operation), operation.signal);
|
|
2672
|
+
operation.signal.throwIfAborted();
|
|
2673
|
+
return reason;
|
|
2674
|
+
};
|
|
2675
|
+
const active = await activeReason();
|
|
2549
2676
|
if (active) return kept(active);
|
|
2550
|
-
const before = lowestFree(measureDisk());
|
|
2551
|
-
const run = await withIdleWorkspace(root, async () =>
|
|
2677
|
+
const before = lowestFree(operation ? await measureDiskAsync(operation) : measureDisk());
|
|
2678
|
+
const run = await withIdleWorkspace(root, async () => await activeReason() ? kept("it became active") : deleteOwnedDevicesOf(root, {
|
|
2679
|
+
noneIsKept: true,
|
|
2680
|
+
operation,
|
|
2681
|
+
output
|
|
2682
|
+
}), {
|
|
2683
|
+
purpose,
|
|
2684
|
+
operation
|
|
2685
|
+
});
|
|
2552
2686
|
if (!run.ran) return kept(`in use: ${run.reasons.join("; ")}`);
|
|
2553
|
-
const bytes = freedSince(before);
|
|
2687
|
+
const bytes = operation ? freedSince(before, await measureDiskAsync(operation)) : freedSince(before);
|
|
2554
2688
|
return run.value ? {
|
|
2555
2689
|
...run.value,
|
|
2556
2690
|
bytes
|