stim 1.26.0 → 1.28.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/dist/{acquire-artifact-DVsvSwf7.mjs → acquire-artifact-CKByBnTD.mjs} +2 -2
- package/dist/{act-C-BqJEpu.mjs → act-8iswyfRa.mjs} +319 -126
- package/dist/{activity-Lnb_EoRY.mjs → activity-DRMg4_mD.mjs} +6 -6
- package/dist/{agent-device-usage-output-DbXy5tg8.mjs → agent-device-usage-output-tE90fDdo.mjs} +5 -5
- package/dist/{android-CiNQw3kq.mjs → android-CHmSU4B4.mjs} +101 -45
- package/dist/{android-DTAcRwBC.mjs → android-CsPs-7Mg.mjs} +23 -18
- package/dist/{android-B5P81yI-.mjs → android-D577ApKG.mjs} +37 -15
- package/dist/{android-CSbLRD53.mjs → android-YWCbmkVK.mjs} +5 -5
- package/dist/{android-cas-BTVhZ0Qs.mjs → android-cas-_aDifWW0.mjs} +4 -4
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api.d.mts +14 -4
- package/dist/api.mjs +39 -29
- package/dist/{apk-signed-tail-B46U9hXc.mjs → apk-signed-tail-CQbwM0qO.mjs} +2 -2
- package/dist/{artifact-CsAP6AGK.mjs → artifact-DYtHjxsn.mjs} +19 -24
- package/dist/{artifact-BxREhAaV.mjs → artifact-bFkfD3vf.mjs} +18 -23
- package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
- package/dist/auto-placement-BVqs8AJi.mjs +350 -0
- package/dist/{browser-web-rYPyqhTf.mjs → browser-web-BUaLcafY.mjs} +16 -16
- package/dist/{build-DPhApsjV.mjs → build-cQURy_KW.mjs} +35 -31
- package/dist/{build-cache-DrXNCy3T.mjs → build-cache-CZULpXVl.mjs} +43 -21
- package/dist/{build-plan-DrMMdayj.mjs → build-plan-CxoYfxsc.mjs} +7 -6
- package/dist/{cache-manifest-BEZ9Bpl1.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{budget-k2mZGvvk.mjs → ccache-Bm_A1xX9.mjs} +562 -1604
- package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
- package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
- package/dist/{cli-BBKFGOFl.mjs → cli-CpbaLDa7.mjs} +24 -23
- package/dist/cli.mjs +1 -1
- package/dist/{client-D9CaRks-.mjs → client-YxCer6ab.mjs} +84 -65
- package/dist/collector-run.d.mts +10 -9
- package/dist/collector-run.mjs +42 -27
- package/dist/{command-output-BF5AR2dL.mjs → command-output-C8R1KIvi.mjs} +1 -1
- package/dist/{config-BktkY_zC.mjs → config-Cn94Jc0g.mjs} +23 -4
- package/dist/{dependencies-Dw6wfQdv.mjs → dependencies-DKeMzwXY.mjs} +108 -60
- package/dist/{dependency-state-DFB41vfr.mjs → dependency-state-CojA2o0t.mjs} +14 -7
- package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
- package/dist/{dev-client-DXR_tPVY.mjs → dev-client-D-BW5uiq.mjs} +2 -2
- package/dist/{device-BK-zwyd_.mjs → device-CgXfbcz5.mjs} +25 -24
- package/dist/{device-capacity-DCSvUF0l.mjs → device-capacity-Cd8lMSn3.mjs} +175 -22
- package/dist/{device-BcYeHSFu.mjs → device-eeK95Lir.mjs} +16 -16
- package/dist/device-host-worker.mjs +22 -20
- package/dist/{device-ios-BLGfXQeK.mjs → device-ios-Cc9ulihb.mjs} +251 -23
- package/dist/{device-lease-run-BmvIl7bI.mjs → device-lease-run-Mtzp4THX.mjs} +5 -5
- package/dist/{device-pool-Dluix4H3.mjs → device-pool-eRz6DtCg.mjs} +3 -3
- package/dist/{doctor-Bhg1ii70.mjs → doctor-Bz_ouYAW.mjs} +28 -16
- package/dist/{doctor-Cp-BhzTS.mjs → doctor-C2QyhejJ.mjs} +1 -1
- package/dist/{doctor-fingerprint-D3a04Mhu.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +1 -1
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-watchman-BStK05nt.mjs → doctor-watchman-BTW82PDC.mjs} +5 -5
- package/dist/{doctor-OnwP94ne.mjs → doctor-xf7ht-5n.mjs} +76 -32
- package/dist/{eas-build-Dsj93iM9.mjs → eas-build-Dm6q68QY.mjs} +4 -4
- package/dist/eas-fallback-DajNpxf-.mjs +87 -0
- package/dist/{eas-session-ledger-B5vygTiD.mjs → eas-session-ledger-CBFo_Uo1.mjs} +37 -8
- package/dist/{error-diagnostics-BOOm9Db7.mjs → error-diagnostics-D1QfyJzQ.mjs} +51 -25
- package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
- package/dist/{gc-ldgr-hXU.mjs → gc-DM5oMm-J.mjs} +161 -45
- package/dist/{gc-C_79zvz4.mjs → gc-PLFwb0k4.mjs} +2 -2
- package/dist/{guide-D7K0X6KG.mjs → guide-C4I46XAk.mjs} +674 -213
- package/dist/{hosted-android-Bk54ej6n.mjs → hosted-android-DlaKLbW0.mjs} +6 -7
- package/dist/{hosted-client-fHO8yqzc.mjs → hosted-client-DDRm9hPJ.mjs} +51 -20
- package/dist/{hosted-logs-BfbmDM4M.mjs → hosted-logs-bSebOKbz.mjs} +8 -8
- package/dist/{hosted-logs-sync-B0pvmOk-.mjs → hosted-logs-sync-B0c53W_c.mjs} +5 -5
- package/dist/{hosted-macos-CPl0OZ9h.mjs → hosted-macos-B7-8Pv4H.mjs} +6 -6
- package/dist/{hosted-native-CpDB3-PO.mjs → hosted-native-CDe33CSr.mjs} +22 -18
- package/dist/{idle-shutdown-FfxL1KdG.mjs → idle-shutdown-CQ0QwU9J.mjs} +7 -8
- package/dist/{ios-WxpDJ5T1.mjs → ios-B1DYuOjh.mjs} +27 -11
- package/dist/{ios-B7-lToDu.mjs → ios-B1HvafEG.mjs} +8 -8
- package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
- package/dist/{ios-device-CsyryvpT.mjs → ios-device-B4elVFKi.mjs} +3 -3
- package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
- package/dist/{ios-project-Ty5pHl9O.mjs → ios-project-CR4mZ7CH.mjs} +22 -9
- package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
- package/dist/{ios-state-Cw7-WQf2.mjs → ios-state-BPHqMDdZ.mjs} +1 -1
- package/dist/{ios-ftxdQbJS.mjs → ios-tg4tp3q1.mjs} +94 -37
- package/dist/{js-swap-BMhXYVDS.mjs → js-swap-CVpSW1fn.mjs} +8 -7
- package/dist/{launch-DOp8RjDz.mjs → launch-DoySmhjz.mjs} +42 -38
- package/dist/lightened-DFAJgfIk.mjs +171 -0
- package/dist/{logs-s1dRIG1E.mjs → logs-BGsW7iPe.mjs} +46 -21
- package/dist/{logs-dQDki6Tt.mjs → logs-DI5ILkYB.mjs} +7 -7
- package/dist/{macos-DBBPNnIA.mjs → macos-Bo9st9Di.mjs} +73 -38
- package/dist/{macos-B0VEV3Gf.mjs → macos-C12RMJQF.mjs} +1 -1
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +7 -7
- package/dist/{metro-CjC10t6E.mjs → metro-BnhXV2Mj.mjs} +4 -4
- package/dist/{metro-gateway-B6_PgD0L.mjs → metro-request-DXyKjVDF.mjs} +26 -47
- package/dist/{named-ports-BG0j1X4g.mjs → named-ports-Phoi2POD.mjs} +3 -3
- package/dist/{native-android-CL2NGiik.mjs → native-android-vxgtLD7w.mjs} +17 -18
- package/dist/{native-gradle-artifact-inputs-btSUulme.mjs → native-gradle-artifact-inputs-BN96IVw8.mjs} +5 -5
- package/dist/{native-runtime-Dq3RBcON.mjs → native-runtime-DG4Rodzj.mjs} +9 -8
- package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
- package/dist/{native-xcode-inputs-BW7H8JGu.mjs → native-xcode-inputs-BKarCoKg.mjs} +3 -3
- package/dist/{native-xcode-ios-CBXJAxfC.mjs → native-xcode-ios-8A-efGa5.mjs} +17 -17
- package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
- package/dist/offload-worker.mjs +23 -24
- package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
- package/dist/{ownership-BjYvMNX_.mjs → ownership-DJCq48IJ.mjs} +3 -3
- package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
- package/dist/{phone-reverses-lmj6kcPm.mjs → phone-reverses-BzTa8g1F.mjs} +18 -4
- package/dist/{placement-log-DIFPQAXp.mjs → placement-log-Cvhta5ib.mjs} +3 -3
- package/dist/{plan-placement-IiiSQhtz.mjs → plan-placement-WkZdccuN.mjs} +36 -10
- package/dist/{ports-C2_w1Z0Z.mjs → ports-UV4mJgyC.mjs} +3 -3
- package/dist/{prebuild-gmouvmJZ.mjs → prebuild-k8d_tqOq.mjs} +16 -17
- package/dist/{project-BUu6Is4k.mjs → project-Sui52ywT.mjs} +17 -17
- package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
- package/dist/pull-requests.mjs +1 -1
- package/dist/{react-native-android-Cgg99REN.mjs → react-native-android-DANlGGQf.mjs} +32 -26
- package/dist/{react-native-build-oNwqF5Wb.mjs → react-native-build-jUHnIfZ9.mjs} +9 -9
- package/dist/{react-native-doctor-BhA3KUte.mjs → react-native-doctor-DCWRjS7K.mjs} +6 -6
- package/dist/{react-native-ios-B-nf4rjN.mjs → react-native-ios-BwMsFMXi.mjs} +23 -17
- package/dist/{recordings-BldzVKq0.mjs → recordings-iy0mkm7b.mjs} +1 -1
- package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
- package/dist/{reload-C9OduiNc.mjs → reload-Bj7QyuDy.mjs} +1 -1
- package/dist/{reload-CCR7KC_l.mjs → reload-c_uEyc_X.mjs} +16 -16
- package/dist/{remote-C8S7FlPF.mjs → remote-DFlpAqdV.mjs} +23 -10
- package/dist/{result-7F5hEwQJ.mjs → result-BIcXREyC.mjs} +32 -21
- package/dist/{run-BqB0v3pt.mjs → run-y2HwyNvg.mjs} +3 -3
- package/dist/{selection-BNPBZ6T5.mjs → selection-CXgM_VK_.mjs} +37 -29
- package/dist/{server-bare-A75rDIdD.mjs → server-bare-2N4vSRZG.mjs} +2 -2
- package/dist/{server-command-CssKFOD7.mjs → server-command-qneHPcRI.mjs} +6 -6
- package/dist/{server-expo-eQfOdydb.mjs → server-expo-Ccm9zB0o.mjs} +4 -4
- package/dist/server-expo-WulkyAwT.mjs +2 -0
- package/dist/{settings-CosW5X-S.mjs → settings-CY5JZlNN.mjs} +375 -62
- package/dist/{settings-OaGQF-ri.mjs → settings-Cfd_Q6ys.mjs} +24 -3
- package/dist/settings-payload-DwQiEMCn.mjs +257 -0
- package/dist/settings-write-CJpjkeAd.mjs +185 -0
- package/dist/settings.schema.json +51 -33
- package/dist/{simslim-Bax1qcxu.mjs → simslim-DCQwzoPy.mjs} +2 -2
- package/dist/{slot-launch-CYCEhfBY.mjs → slot-launch-BpmanOnk.mjs} +6 -6
- package/dist/{stage-jKQ7CP_B.mjs → stage-CmugrSG5.mjs} +2 -2
- package/dist/{start-C_wefNKB.mjs → start-CHH3zgIU.mjs} +1 -1
- package/dist/{start-_BdJ32cZ.mjs → start-DYLk6GXn.mjs} +27 -22
- package/dist/{state-C1i2nMOP.mjs → state-B2QJbDwz.mjs} +4 -4
- package/dist/{state-C4OdpOTF.mjs → state-BXC1Lfxw.mjs} +2 -2
- package/dist/{stats-tEpEEH-u.mjs → stats-DxKqhcGp.mjs} +5 -5
- package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
- package/dist/{status-CRXz-Gtj.mjs → status-7ULDEJ1e.mjs} +1 -1
- package/dist/{status-DQrqodLj.mjs → status-BHCkOZga.mjs} +51 -28
- package/dist/{status-B9M7x4CZ.mjs → status-D_Ljc89p.mjs} +1 -1
- package/dist/{status-watch-B5wDIH_o.mjs → status-watch-BmsPqYSU.mjs} +18 -7
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-6Dqp-gjX.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
- package/dist/{stop-DRqQVqDJ.mjs → stop-D-dGE9gh.mjs} +21 -20
- package/dist/{stop-ySNQHXMG.mjs → stop-DQvE-P76.mjs} +10 -6
- package/dist/{stop-CmdNhGlC.mjs → stop-b2pouxAO.mjs} +2 -2
- package/dist/supervisor-run.mjs +237 -63
- package/dist/{support-BGSCBoib.mjs → support-04IhBUTT.mjs} +6 -6
- package/dist/{support-CVOCp0Ft.mjs → support-BtlJKjyQ.mjs} +12 -11
- package/dist/{swiftpm-artifact-inputs-CfUzt_0Z.mjs → swiftpm-artifact-inputs-Cj2UpmPN.mjs} +4 -4
- package/dist/{swiftpm-macos-x6HPpl_2.mjs → swiftpm-macos-BhF2stxY.mjs} +11 -12
- package/dist/{toolchain-J4J8MrAr.mjs → toolchain-mLA_km-b.mjs} +321 -15
- package/dist/{toolchain-DoavrvIA.mjs → toolchain-qktiV8xc.mjs} +1 -1
- package/dist/{trigger-KVaWWNyn.mjs → trigger-DMou-X7j.mjs} +2 -2
- package/dist/trigger-qp2ji5wE.mjs +2 -0
- package/dist/{warm-progress-DvhTX_eu.mjs → warm-progress-B0Vpuvpl.mjs} +731 -727
- package/dist/{web-Bihbf7-u.mjs → web-BYmK0TjL.mjs} +9 -9
- package/dist/web-CrVLVQZY.mjs +2 -0
- package/dist/web-run.mjs +9 -9
- package/dist/windows-report.mjs +1 -1
- package/dist/{workspace-state-pUg3_RRA.mjs → workspace-state-kIZrdlSg.mjs} +3 -3
- package/dist/{workspaces-g2lhdBXF.mjs → workspaces-CmOcceDN.mjs} +1879 -74
- package/dist/{worktree-BKuklFh_.mjs → worktree-2dk5edza.mjs} +933 -534
- package/dist/worktree-nliAoHxB.mjs +2 -0
- package/package.json +7 -7
- package/dist/ccache-Bx5TbxwG.mjs +0 -143
- package/dist/eas-fallback-FwkeqqGi.mjs +0 -381
- package/dist/hosted-ios-D55QhYaD.mjs +0 -15
- package/dist/native-run-BfIDFKLH.mjs +0 -275
- package/dist/server-expo-wvcj5tiZ.mjs +0 -2
- package/dist/settings-write-QjYfSrjF.mjs +0 -360
- package/dist/trigger-DzJu208Q.mjs +0 -2
- package/dist/web-BFLueSh-.mjs +0 -2
- package/dist/worktree-Bm4cb-nU.mjs +0 -2
|
@@ -1,62 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { j as workspaceStateFile$1, k as workspaceLogsDir$1, r as readWorkspaceState$1, u as workspaceLastUsed } from "./workspace-state-
|
|
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-
|
|
4
|
-
import { o as formatLongDuration, u as plural } from "./command-output-
|
|
5
|
-
import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, r as childEnvironment } from "./operation-exec-
|
|
6
|
-
import {
|
|
7
|
-
import { i as findProjectRoot$1 } from "./project-
|
|
8
|
-
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, P as listAvds, V as ownedAvdDirectory, yt as readParked } from "./android-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { l as WorkspaceProcessCleanupError, n as isTimeoutError, t as getExecutor } from "./exec-aULwtNly.mjs";
|
|
2
|
+
import { j as workspaceStateFile$1, k as workspaceLogsDir$1, r as readWorkspaceState$1, u as workspaceLastUsed } from "./workspace-state-kIZrdlSg.mjs";
|
|
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-Cn94Jc0g.mjs";
|
|
4
|
+
import { o as formatLongDuration, u as plural } from "./command-output-C8R1KIvi.mjs";
|
|
5
|
+
import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, r as childEnvironment } from "./operation-exec-Dp4FuIGR.mjs";
|
|
6
|
+
import { At as listWorktrees, Et as hasUncommittedWorkAsync, Ft as matchWorktreeEntry, Kt as sourceCheckoutOf, O as maintenanceKeepSetting, Pt as lockReason, Ut as resolveFullRefAsync, Wt as resolveSourceCheckoutAsync, X as resolveProjectSettings, Xt as worktreeLockAsync, Z as resolveProjectSettingsAsync, bt as dirtyPathsAsync, h as deviceIdleShutdownMinutesSetting, jt as listWorktreesAsync, mt as LOCKED_REASON, qt as unpushedCommitsAsync, sn as removeTemporaryEntryAsync, wt as hasPopulatedSubmodulesAsync } from "./settings-CY5JZlNN.mjs";
|
|
7
|
+
import { i as findProjectRoot$1 } from "./project-Sui52ywT.mjs";
|
|
8
|
+
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, P as listAvds, V as ownedAvdDirectory, yt as readParked } from "./android-CsPs-7Mg.mjs";
|
|
9
|
+
import { A as diskPressureLevel, G as planCacheEmptying, N as lowestFree, P as protectWindowMs, X as collectGradleVersions, Z as deleteGradleVersion, Zn as collectMemoryReport, _ as resolveBudget, at as DEVICE_LIST_TIMEOUT_MS, ct as collectParkedSims, d as enforceBudget, dr as pruneCache, dt as deleteProjectDevices, j as levelFloors, lt as deleteParkedAvds, mt as deviceSweepIsScoped, nr as memorySweepIsScoped, nt as waitForGradleExit, or as stopIdleGradleDaemons, p as machineNumber, sr as phase, st as collectParkedAvds, u as cacheLabel, ur as discoverCaches, ut as deleteParkedSims, v as trimmableCaches, vt as findStaleProjectDevices, y as stopOwnedMetro, z as emptyCaches } from "./ccache-Bm_A1xX9.mjs";
|
|
10
|
+
import { a as unregister, n as readManifest } from "./cache-manifest-DEjqGGat.mjs";
|
|
11
|
+
import { B as workspaceBuildInProgress, Et as GC_OUTPUT, F as collectOwnedDeviceActivityAsync, Ot as takeGcResults, P as collectOwnedDeviceActivity, a as collectOrphanedWorkspaces, b as workspaceInUseAsync, c as isInsideWorkspaces, d as recentNativeUseReason, g as ARTIFACT_DIRS, h as workspaceDirRemoved, i as clearWorkspaceOutputs, jt as readConcurrency, kt as eachLimited, l as keptByLock, m as workspaceBuildReasons, o as collectWorkspaceOutputs, s as deleteOrphanedWorkspaces, t as LIGHTEN_AFTER_MS, u as listWorkspaceDirs, v as withIdleWorkspace, y as workspaceInUse } from "./workspaces-CmOcceDN.mjs";
|
|
11
12
|
import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-WxpDJ5T1.mjs";
|
|
13
|
+
import { N as listBuildLocks, _ as workspaceDeviceLastUseAt, b as leaseIsExpired, g as workspaceActivity, x as listLeaseFiles } from "./activity-DRMg4_mD.mjs";
|
|
14
|
+
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-B1DYuOjh.mjs";
|
|
15
15
|
import { s as metroStoreRoot } from "./errors-DHm_U5gv.mjs";
|
|
16
16
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
17
|
-
import { i as
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
17
|
+
import { D as stimCliUseOf, E as stimCliEntries, M as worktreeArchiveLimits, T as serviceRunningFrom, _ as cacheBlocked, a as nestedWorktrees, b as measurePressure, i as excludeWatchmanCookies, o as porcelainPath, p as removeWorktreeTarget, r as excludePodChurn, s as reclaimKeys, v as measureDisk, w as uncommittedActivityOf, x as measurePressureAsync, y as measureDiskAsync } from "./worktree-2dk5edza.mjs";
|
|
18
|
+
import { n as describePullRequest, r as endedPullRequest, s as pullRequestLookups } from "./pull-request-BzLmzAIQ.mjs";
|
|
19
|
+
import { a as lastFetchedAtAsync, c as mergeStateAsync, f as recordPullRequestLookup, i as fetchDefaultBranchAsync, o as localDefaultBranchAsync, r as FETCH_FRESH_MS } from "./warm-progress-B0Vpuvpl.mjs";
|
|
20
|
+
import { a as restoreProblem, r as recordLightened, t as finishLightened } from "./lightened-DFAJgfIk.mjs";
|
|
21
|
+
import { i as writeIdleShutdownEvent, n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-CQ0QwU9J.mjs";
|
|
21
22
|
import { readClaimSet } from "@stim-cli/core/ownership-claim";
|
|
22
|
-
import { existsSync, lstatSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
23
|
+
import { existsSync, lstatSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
23
24
|
import { tmpdir } from "node:os";
|
|
24
25
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
25
26
|
import { buildCacheRoot, configDir, metroCacheRoot } from "@stim-cli/core";
|
|
26
|
-
import { LAST_BUILD_KEYS, MAINTENANCE_LOG_NAME, loadConfig, readBuildHistory, readMaintenanceState, readPullRequestCache, settingDefinition, sharedCompilationCache } from "@stim-cli/core/state";
|
|
27
|
+
import { LAST_BUILD_KEYS, MAINTENANCE_LOG_NAME, lastNativeUseFrom, loadConfig, readBuildHistory, readMaintenanceState, readPullRequestCache, settingDefinition, sharedCompilationCache } from "@stim-cli/core/state";
|
|
27
28
|
import { isAbsolute as isAbsolute$1, join as join$1 } from "path";
|
|
28
29
|
import chalk from "chalk";
|
|
29
30
|
import { existsSync as existsSync$1, readdirSync as readdirSync$1, statSync as statSync$1 } from "fs";
|
|
30
31
|
import { lstat, readdir, realpath, rename, stat } from "node:fs/promises";
|
|
31
|
-
//#region src/commands/gc/limited.ts
|
|
32
|
-
const isCleanupFailure = (error) => error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error;
|
|
33
|
-
async function eachLimited(items, limit, run) {
|
|
34
|
-
const queue = items[Symbol.iterator]();
|
|
35
|
-
let failed = false;
|
|
36
|
-
const worker = async () => {
|
|
37
|
-
for (const item of queue) {
|
|
38
|
-
if (failed) return;
|
|
39
|
-
try {
|
|
40
|
-
await run(item);
|
|
41
|
-
} catch (error) {
|
|
42
|
-
failed = true;
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
const errors = (await Promise.allSettled(Array.from({ length: Math.min(limit, items.length) }, worker))).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
48
|
-
if (errors.length) throw errors.find(isCleanupFailure) ?? errors[0];
|
|
49
|
-
}
|
|
50
|
-
function readConcurrency(operation) {
|
|
51
|
-
return operationState(operation).declaring.size ? 1 : 6;
|
|
52
|
-
}
|
|
53
|
-
//#endregion
|
|
54
32
|
//#region src/commands/gc/worktrees.ts
|
|
55
33
|
const DEFAULT_WORKTREE_IDLE_DAYS = 7;
|
|
56
34
|
const DIRTY_PATHS_SHOWN = 3;
|
|
57
35
|
const DAY_MS = 864e5;
|
|
58
36
|
const MINUTE_MS = 6e4;
|
|
59
37
|
const GRACE_SETTING = "gc.worktreeGraceMinutes";
|
|
38
|
+
const PROTECT_SETTING = "maintenance.protectRecentHours";
|
|
60
39
|
const NO_OWN_COMMITS_PRESSURE_FLOOR_MS = 5 * MINUTE_MS;
|
|
61
40
|
const PULL_REQUEST_NOT_CHECKED = "not checked since the last maintenance worktree check";
|
|
62
41
|
const WORKTREE_CHECK_SETTING = "maintenance.worktreeCheckMinutes";
|
|
@@ -101,6 +80,18 @@ function noOwnCommitsActivityBlocker(activity, idleMs, now) {
|
|
|
101
80
|
eligibleAt
|
|
102
81
|
};
|
|
103
82
|
}
|
|
83
|
+
function dirtyLines(porcelain) {
|
|
84
|
+
return excludePodChurn(excludeWatchmanCookies(porcelain).lines).lines;
|
|
85
|
+
}
|
|
86
|
+
function finished(facts) {
|
|
87
|
+
return Boolean(facts.merge?.merged || endedPullRequest(facts.pullRequest));
|
|
88
|
+
}
|
|
89
|
+
function openPullRequest(lookup) {
|
|
90
|
+
return Boolean(lookup && "pullRequest" in lookup && lookup.pullRequest?.state === "open");
|
|
91
|
+
}
|
|
92
|
+
function newerActivity(a, b) {
|
|
93
|
+
return a && b ? b.at > a.at ? b : a : a ?? b;
|
|
94
|
+
}
|
|
104
95
|
function hasNoOwnCommits(merge) {
|
|
105
96
|
return merge?.merged === false && merge.noOwnCommits === true;
|
|
106
97
|
}
|
|
@@ -135,15 +126,20 @@ function removalBlocker(facts, olderThan, now, noOwnCommitsIdleMs) {
|
|
|
135
126
|
if (facts.bare) return skip("bare-repository", "bare repository");
|
|
136
127
|
if (typeof facts.source === "object") return skip("source-checkout-unknown", `source checkout unknown: ${facts.source.refusal}`);
|
|
137
128
|
if (facts.source === "source") return skip("source-checkout", "source checkout");
|
|
138
|
-
if (facts.locked) return skip("locked",
|
|
129
|
+
if (facts.locked) return skip("locked", LOCKED_REASON);
|
|
139
130
|
if (facts.nested?.length) return skip("nested-worktree", `contains the worktree ${facts.nested.join(", ")}`);
|
|
140
131
|
if (facts.inUse.length) return skip("in-use", `in use: ${facts.inUse.join("; ")}`);
|
|
141
132
|
if (facts.porcelain === null) return skip("status-unreadable", "git status could not be read");
|
|
142
|
-
const dirty =
|
|
133
|
+
const dirty = dirtyLines(facts.porcelain);
|
|
143
134
|
if (dirty.length) {
|
|
144
135
|
const paths = dirty.slice(0, DIRTY_PATHS_SHOWN).flatMap((line) => porcelainPath(line) ?? []);
|
|
145
136
|
const more = dirty.length > DIRTY_PATHS_SHOWN ? ", ..." : "";
|
|
146
|
-
|
|
137
|
+
const kept = skip("dirty", `dirty: ${plural(dirty.length, "uncommitted or untracked file")} (${paths.join(", ")}${more})`);
|
|
138
|
+
if (!facts.archiveDirty) return kept;
|
|
139
|
+
return removalBlocker({
|
|
140
|
+
...facts,
|
|
141
|
+
porcelain: []
|
|
142
|
+
}, olderThan, now, noOwnCommitsIdleMs) === null && finished(facts) ? null : kept;
|
|
147
143
|
}
|
|
148
144
|
if (facts.unpushed === null) return skip("unpushed-unchecked", "unpushed commits could not be checked");
|
|
149
145
|
const merged = facts.merge?.merged ? facts.merge : null;
|
|
@@ -154,17 +150,9 @@ function removalBlocker(facts, olderThan, now, noOwnCommitsIdleMs) {
|
|
|
154
150
|
if (merged || ended) return null;
|
|
155
151
|
const notMerged = facts.merge && !facts.merge.merged ? facts.merge : null;
|
|
156
152
|
const details = [notMerged?.detail, pullRequestNote(facts.pullRequest)].filter(Boolean);
|
|
157
|
-
|
|
158
|
-
if (olderThan === null)
|
|
159
|
-
if (noOwnCommits && noOwnCommitsIdleMs !== null) return noOwnCommitsActivityBlocker(facts.activity, noOwnCommitsIdleMs, now);
|
|
160
|
-
return skip(notMerged?.unknown ? "merge-unknown" : "not-merged", details.join("; ") || "not merged");
|
|
161
|
-
}
|
|
153
|
+
if (hasNoOwnCommits(notMerged) && !openPullRequest(facts.pullRequest) && noOwnCommitsIdleMs !== null) return noOwnCommitsActivityBlocker(facts.activity, noOwnCommitsIdleMs, now);
|
|
154
|
+
if (olderThan === null) return skip(notMerged?.unknown ? "merge-unknown" : "not-merged", details.join("; ") || "not merged");
|
|
162
155
|
const also = details.map((detail) => `; ${detail}`).join("");
|
|
163
|
-
if (facts.idleDays === null && noOwnCommits && facts.activity) {
|
|
164
|
-
const days = activityIdleDays(facts.activity, now);
|
|
165
|
-
if (days < olderThan) return skip("recently-used", `recently active: ${facts.activity.basis} ${days}d ago${also}`);
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
156
|
if (facts.idleDays === null) return skip("last-use-unknown", `recently used: its last use is unknown${also}`);
|
|
169
157
|
if (facts.idleDays < olderThan) return skip("recently-used", `recently used ${facts.idleDays}d ago${also}`);
|
|
170
158
|
return null;
|
|
@@ -176,11 +164,16 @@ function removalBlocker(facts, olderThan, now, noOwnCommitsIdleMs) {
|
|
|
176
164
|
*/
|
|
177
165
|
function worktreeRemovalReason(candidate, sweep) {
|
|
178
166
|
const { merge, activity } = candidate;
|
|
179
|
-
|
|
167
|
+
const archived = candidate.dirty ? `, ${plural(candidate.dirty, "uncommitted file")} archived first` : "";
|
|
168
|
+
if (merge?.merged) return `merged into ${merge.into}${archived}`;
|
|
180
169
|
const ended = endedPullRequest(candidate.pullRequest);
|
|
181
|
-
if (ended) return describePullRequest(ended)
|
|
170
|
+
if (ended) return `${describePullRequest(ended)}${archived}`;
|
|
182
171
|
if (merge && hasNoOwnCommits(merge)) {
|
|
183
|
-
if (sweep.noOwnCommitsIdleMs !== null && activity)
|
|
172
|
+
if (sweep.noOwnCommitsIdleMs !== null && activity) {
|
|
173
|
+
const age = Math.max(0, sweep.now - activity.at);
|
|
174
|
+
if (sweep.underPressure) return `${merge.detail}, inactive for ${formatLongDuration(age)} under disk pressure`;
|
|
175
|
+
return age >= DAY_MS ? `${merge.detail}, idle ${activityIdleDays(activity, sweep.now)}d` : `${merge.detail}, inactive for ${formatLongDuration(age)}`;
|
|
176
|
+
}
|
|
184
177
|
const days = candidate.idleDays ?? (activity ? activityIdleDays(activity, sweep.now) : null);
|
|
185
178
|
return days === null ? merge.detail : `${merge.detail}, idle ${days}d`;
|
|
186
179
|
}
|
|
@@ -366,6 +359,10 @@ function activityFromGitDir(gitDir, keys) {
|
|
|
366
359
|
const newest = newestMtime(paths);
|
|
367
360
|
return newest === "unreadable" ? null : newest;
|
|
368
361
|
}
|
|
362
|
+
function protectRecentMs(operation) {
|
|
363
|
+
const { value, error } = machineNumber(PROTECT_SETTING, loadConfig$1(), operation?.env ?? process.env);
|
|
364
|
+
return (error ? Number(settingDefinition(PROTECT_SETTING)?.default) : value ?? 0) * 60 * MINUTE_MS;
|
|
365
|
+
}
|
|
369
366
|
function graceMsSetting(operation) {
|
|
370
367
|
const { value, error } = machineNumber(GRACE_SETTING, loadConfig$1(), operation?.env ?? process.env);
|
|
371
368
|
if (error) {
|
|
@@ -493,22 +490,25 @@ async function checkMergeStates(pending, idle, grace, noOwnCommitsIdleMs, refres
|
|
|
493
490
|
}
|
|
494
491
|
}
|
|
495
492
|
/**
|
|
496
|
-
* Classifies each linked worktree of a registered project or its repository. A merged one is removable
|
|
497
|
-
*
|
|
498
|
-
*
|
|
493
|
+
* Classifies each linked worktree of a registered project or its repository. A merged one is removable, a dirty one
|
|
494
|
+
* after archiving its uncommitted work when archives are on; with `idle`, so is one unused for `olderThan` days. One
|
|
495
|
+
* with no commits of its own beyond the default branch is removable once its last activity is older than the grace
|
|
496
|
+
* period and `maintenance.protectRecentHours`, or, `underPressure`, than the grace period alone; never younger than 5
|
|
497
|
+
* minutes. Device use is read last, in one pass against one simulator list and one AVD resolver, so
|
|
499
498
|
* the resolver's time budget covers only device reads. Pull requests are asked once per repository, sequentially
|
|
500
499
|
* with an operation and concurrently otherwise. Merge state is checked only where it decides the verdict, after one fetch per repository.
|
|
501
500
|
* Without `refresh`, it runs no fetch and no `gh`: merge state comes from the existing remote-tracking ref and pull
|
|
502
501
|
* requests from the cache `status --watch` writes, and a kept verdict that fresher state could change says so.
|
|
503
502
|
*/
|
|
504
|
-
async function collectWorktreeSweep({ idle, olderThan, now, graceMs,
|
|
503
|
+
async function collectWorktreeSweep({ idle, olderThan, now, graceMs, underPressure = false, refresh = true, operation }) {
|
|
505
504
|
const days = idle ? olderThan ?? DEFAULT_WORKTREE_IDLE_DAYS : null;
|
|
506
505
|
const grace = {
|
|
507
506
|
ms: graceMs ?? graceMsSetting(operation),
|
|
508
507
|
now
|
|
509
508
|
};
|
|
510
509
|
const freshMs = refresh ? 0 : reportFreshMs(operation);
|
|
511
|
-
const noOwnCommitsIdleMs =
|
|
510
|
+
const noOwnCommitsIdleMs = Math.max(grace.ms, underPressure ? 0 : protectRecentMs(operation), NO_OWN_COMMITS_PRESSURE_FLOOR_MS);
|
|
511
|
+
const cli = stimCliEntries(operation?.env);
|
|
512
512
|
const groups = /* @__PURE__ */ new Map();
|
|
513
513
|
operation?.signal.throwIfAborted();
|
|
514
514
|
const read = {
|
|
@@ -551,22 +551,29 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
551
551
|
const keys = [.../* @__PURE__ */ new Set([...roots, ...reclaimKeys(path)])];
|
|
552
552
|
const idleDays = idleDaysOf(keys, now);
|
|
553
553
|
const linked = !("refusal" in source) && entry !== null && source.path !== entry.path;
|
|
554
|
-
const
|
|
555
|
-
const
|
|
554
|
+
const porcelain = await porcelainOf(path, linked ? await unlessTimedOut(() => hasUncommittedWorkAsync(path, read), null) : null, operation);
|
|
555
|
+
const dirty = linked ? dirtyLines(porcelain).length : 0;
|
|
556
|
+
const archiveDirty = dirty > 0 && !underPressure && !("refusal" in worktreeArchiveLimits(path, operation?.env));
|
|
557
|
+
let activity = linked ? await worktreeActivityOfAsync(path, keys, operation) : null;
|
|
558
|
+
if (activity && archiveDirty) {
|
|
559
|
+
const edited = await uncommittedActivityOf(path, operation);
|
|
560
|
+
activity = edited === "unreadable" ? null : newerActivity(activity, edited);
|
|
561
|
+
}
|
|
556
562
|
const head = linked ? await resolveFullRefAsync(path, "HEAD", read) : null;
|
|
557
563
|
const facts = {
|
|
558
564
|
source: "refusal" in source ? source : linked ? "linked" : "source",
|
|
559
565
|
bare: Boolean(entry?.bare),
|
|
560
566
|
locked: Boolean(entry?.locked),
|
|
561
567
|
nested: entry ? nestedWorktrees(entries, entry.path) : [],
|
|
562
|
-
porcelain
|
|
568
|
+
porcelain,
|
|
563
569
|
unpushed: linked ? await unlessTimedOut(() => unpushedCommitsAsync(path, read), null) : null,
|
|
564
570
|
submodules: linked ? await unlessTimedOut(() => hasPopulatedSubmodulesAsync(path, read), null) : false,
|
|
565
|
-
inUse: [],
|
|
571
|
+
inUse: linked ? stimCliUseOf(path, canonicalPath, cli) : [],
|
|
566
572
|
idleDays,
|
|
567
573
|
merge: null,
|
|
568
574
|
pullRequest: null,
|
|
569
|
-
activity
|
|
575
|
+
activity,
|
|
576
|
+
archiveDirty
|
|
570
577
|
};
|
|
571
578
|
inspected[index] = {
|
|
572
579
|
candidate: {
|
|
@@ -579,7 +586,8 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
579
586
|
skipCode: null,
|
|
580
587
|
skipped: null,
|
|
581
588
|
eligibleAt: null,
|
|
582
|
-
activity
|
|
589
|
+
activity,
|
|
590
|
+
...archiveDirty ? { dirty } : {}
|
|
583
591
|
},
|
|
584
592
|
facts,
|
|
585
593
|
repo: "refusal" in source ? null : source.path,
|
|
@@ -602,7 +610,7 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
602
610
|
skipped: verdict?.text ?? null,
|
|
603
611
|
eligibleAt: verdict?.eligibleAt ?? null
|
|
604
612
|
});
|
|
605
|
-
if (verdict && MERGE_DECIDES.has(verdict.code) && repo !== null) pending.push({
|
|
613
|
+
if (verdict && (MERGE_DECIDES.has(verdict.code) || verdict.code === "dirty" && facts.archiveDirty) && repo !== null) pending.push({
|
|
606
614
|
candidate,
|
|
607
615
|
facts,
|
|
608
616
|
repo
|
|
@@ -619,6 +627,7 @@ async function collectWorktreeSweep({ idle, olderThan, now, graceMs, removesNoOw
|
|
|
619
627
|
graceMs: grace.ms,
|
|
620
628
|
now,
|
|
621
629
|
noOwnCommitsIdleMs,
|
|
630
|
+
underPressure,
|
|
622
631
|
worktrees: listed
|
|
623
632
|
};
|
|
624
633
|
}
|
|
@@ -686,16 +695,8 @@ function cachedPullRequest(cached, branch, head, now, freshMs) {
|
|
|
686
695
|
} };
|
|
687
696
|
}
|
|
688
697
|
async function noOwnCommitsRecheck(sweep, path, keys, now, operation) {
|
|
689
|
-
if (
|
|
690
|
-
|
|
691
|
-
return noOwnCommitsActivityBlocker(await worktreeActivityOfAsync(path, keys, operation), sweep.noOwnCommitsIdleMs, now)?.text ?? null;
|
|
692
|
-
}
|
|
693
|
-
const idleDays = idleDaysOf(keys, now);
|
|
694
|
-
if (idleDays !== null) return idleDays < sweep.idle.olderThan ? `used ${idleDays}d ago since gc checked it` : null;
|
|
695
|
-
const activity = await worktreeActivityOfAsync(path, keys, operation);
|
|
696
|
-
if (!activity) return "its last activity could not be read";
|
|
697
|
-
const days = activityIdleDays(activity, now);
|
|
698
|
-
return days < sweep.idle.olderThan ? `active ${days}d ago since gc checked it: ${activity.basis}` : null;
|
|
698
|
+
if (sweep.noOwnCommitsIdleMs === null) return "it has no commits of its own and is not idle";
|
|
699
|
+
return noOwnCommitsActivityBlocker(await worktreeActivityOfAsync(path, keys, operation), sweep.noOwnCommitsIdleMs, now)?.text ?? null;
|
|
699
700
|
}
|
|
700
701
|
async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, output = GC_OUTPUT) {
|
|
701
702
|
let failures = 0;
|
|
@@ -707,7 +708,11 @@ async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, outp
|
|
|
707
708
|
const keys = [.../* @__PURE__ */ new Set([...candidate.keys, ...lockedKeys])];
|
|
708
709
|
const unlocked = keys.filter((key) => !lockedKeys.includes(key));
|
|
709
710
|
const devices = await reportDeviceReads(keys, operation);
|
|
710
|
-
const reasons = [
|
|
711
|
+
const reasons = [
|
|
712
|
+
...stimCliUseOf(candidate.path, canonicalPath, stimCliEntries(operation?.env)),
|
|
713
|
+
...await inUseOf(lockedKeys, { managedLocks: false }, devices, operation?.signal, operation),
|
|
714
|
+
...await inUseOf(unlocked, { managedLocks: true }, devices, operation?.signal, operation)
|
|
715
|
+
].map((r) => `in use: ${r}`);
|
|
711
716
|
const mergedHead = candidate.merge?.merged ? candidate.merge.head : endedPullRequest(candidate.pullRequest) ? candidate.head : null;
|
|
712
717
|
if (mergedHead) {
|
|
713
718
|
if (await resolveFullRefAsync(candidate.path, "HEAD", {
|
|
@@ -728,10 +733,12 @@ async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, outp
|
|
|
728
733
|
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`);
|
|
729
734
|
}
|
|
730
735
|
if (sweep.graceMs > 0) {
|
|
736
|
+
const activity = await worktreeActivityOfAsync(candidate.path, keys, operation);
|
|
737
|
+
const edited = candidate.dirty && activity ? await uncommittedActivityOf(candidate.path, operation) : null;
|
|
731
738
|
const recent = graceBlocker({
|
|
732
739
|
merge: candidate.merge,
|
|
733
740
|
pullRequest: candidate.pullRequest,
|
|
734
|
-
activity:
|
|
741
|
+
activity: edited === "unreadable" ? null : newerActivity(activity, edited)
|
|
735
742
|
}, {
|
|
736
743
|
ms: sweep.graceMs,
|
|
737
744
|
now: Date.now()
|
|
@@ -743,6 +750,7 @@ async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, outp
|
|
|
743
750
|
};
|
|
744
751
|
let removed = false;
|
|
745
752
|
let error = null;
|
|
753
|
+
const archived = { archive: null };
|
|
746
754
|
try {
|
|
747
755
|
const ended = endedPullRequest(candidate.pullRequest);
|
|
748
756
|
const mergedHead = candidate.merge?.merged && candidate.merge.coversUnpushed ? candidate.merge.head : ended?.state === "merged" ? candidate.head ?? void 0 : void 0;
|
|
@@ -753,7 +761,17 @@ async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, outp
|
|
|
753
761
|
mergedHead,
|
|
754
762
|
expectedHead,
|
|
755
763
|
output,
|
|
756
|
-
operation
|
|
764
|
+
operation,
|
|
765
|
+
...candidate.dirty ? { archiveDirty: {
|
|
766
|
+
pullRequest: ended ? {
|
|
767
|
+
number: ended.number,
|
|
768
|
+
url: ended.url,
|
|
769
|
+
state: ended.state
|
|
770
|
+
} : null,
|
|
771
|
+
onArchived: (saved) => {
|
|
772
|
+
archived.archive = saved;
|
|
773
|
+
}
|
|
774
|
+
} } : {}
|
|
757
775
|
});
|
|
758
776
|
} catch (thrown) {
|
|
759
777
|
if (thrown instanceof WorkspaceProcessCleanupError || thrown instanceof Error && "reportCleanup" in thrown) throw thrown;
|
|
@@ -762,8 +780,16 @@ async function removeWorktrees(sweep, { now = Date.now(), operation } = {}, outp
|
|
|
762
780
|
output.error(chalk.red(`Could not remove ${candidate.path}: ${error}`));
|
|
763
781
|
}
|
|
764
782
|
if (removed) {
|
|
765
|
-
|
|
766
|
-
|
|
783
|
+
const saved = archived.archive;
|
|
784
|
+
const reason = saved ? `${worktreeRemovalReason({
|
|
785
|
+
...candidate,
|
|
786
|
+
dirty: 0
|
|
787
|
+
}, sweep)}; archived ${plural(saved.tracked.length + saved.untracked.length, "uncommitted file")} to ${saved.dir}; restore: ${saved.restore.join(" && ")}` : worktreeRemovalReason({
|
|
788
|
+
...candidate,
|
|
789
|
+
dirty: 0
|
|
790
|
+
}, sweep);
|
|
791
|
+
output.log(chalk.green(`Removed the worktree ${candidate.path} (${reason})`));
|
|
792
|
+
output.record("worktree", "done", candidate.path, { detail: reason });
|
|
767
793
|
} else if (kept.length) {
|
|
768
794
|
output.log(chalk.yellow(`Kept the worktree ${candidate.path}: ${kept.join("; ")}`));
|
|
769
795
|
output.record("worktree", "kept", candidate.path, { detail: kept.join("; ") });
|
|
@@ -1294,6 +1320,11 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1294
1320
|
}) : { workspaces: [] };
|
|
1295
1321
|
for (const entry of outputs.workspaces) {
|
|
1296
1322
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
1323
|
+
if (root !== null && keptByLock(entry) && entry.keptReason) skips.push({
|
|
1324
|
+
target: root,
|
|
1325
|
+
reason: entry.keptReason,
|
|
1326
|
+
workspace: root
|
|
1327
|
+
});
|
|
1297
1328
|
if (root === null || !entry.willClear || root === protectedRoot) continue;
|
|
1298
1329
|
if (pinned(root)) {
|
|
1299
1330
|
skips.push({
|
|
@@ -1399,7 +1430,7 @@ async function planWorktrees({ protectedRoot, pinned, now, level, graceMs, sizes
|
|
|
1399
1430
|
idle: idleDays !== null,
|
|
1400
1431
|
olderThan: idleDays,
|
|
1401
1432
|
now,
|
|
1402
|
-
|
|
1433
|
+
underPressure: level === 3,
|
|
1403
1434
|
operation,
|
|
1404
1435
|
...graceMs === void 0 ? {} : { graceMs },
|
|
1405
1436
|
...refresh === void 0 ? {} : { refresh }
|
|
@@ -1455,18 +1486,118 @@ async function planWorktrees({ protectedRoot, pinned, now, level, graceMs, sizes
|
|
|
1455
1486
|
};
|
|
1456
1487
|
}
|
|
1457
1488
|
//#endregion
|
|
1489
|
+
//#region src/workspace/running-from.ts
|
|
1490
|
+
const LIST_TIMEOUT_MS = 1e4;
|
|
1491
|
+
function parsePs(text) {
|
|
1492
|
+
return text.split("\n").flatMap((row) => {
|
|
1493
|
+
const match = /^\s*(\d+)\s+(.*)$/.exec(row);
|
|
1494
|
+
return match ? [{
|
|
1495
|
+
pid: Number(match[1]),
|
|
1496
|
+
line: match[2] ?? ""
|
|
1497
|
+
}] : [];
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
/** `lsof -Fpn` output: a `p<pid>` line, then the `n<path>` of its working directory. */
|
|
1501
|
+
function parseLsof(text) {
|
|
1502
|
+
const cwds = [];
|
|
1503
|
+
let pid = 0;
|
|
1504
|
+
for (const row of text.split("\n")) if (row.startsWith("p")) pid = Number(row.slice(1));
|
|
1505
|
+
else if (row.startsWith("n") && pid) cwds.push({
|
|
1506
|
+
pid,
|
|
1507
|
+
path: row.slice(1)
|
|
1508
|
+
});
|
|
1509
|
+
return cwds;
|
|
1510
|
+
}
|
|
1511
|
+
function procCwds() {
|
|
1512
|
+
try {
|
|
1513
|
+
return readdirSync("/proc").filter((name) => /^\d+$/.test(name)).flatMap((name) => {
|
|
1514
|
+
try {
|
|
1515
|
+
return [{
|
|
1516
|
+
pid: Number(name),
|
|
1517
|
+
path: readlinkSync(join("/proc", name, "cwd"))
|
|
1518
|
+
}];
|
|
1519
|
+
} catch {
|
|
1520
|
+
return [];
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
} catch {
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
function listsSelf(list) {
|
|
1528
|
+
return list.some(({ pid }) => pid === process.pid);
|
|
1529
|
+
}
|
|
1530
|
+
function runningFrom(ps, cwds) {
|
|
1531
|
+
if (ps === null || cwds === null) return null;
|
|
1532
|
+
const commands = parsePs(ps);
|
|
1533
|
+
return listsSelf(commands) && listsSelf(cwds) ? {
|
|
1534
|
+
commands,
|
|
1535
|
+
cwds
|
|
1536
|
+
} : null;
|
|
1537
|
+
}
|
|
1538
|
+
const PS_ARGS = [
|
|
1539
|
+
"-axww",
|
|
1540
|
+
"-o",
|
|
1541
|
+
"pid=,args="
|
|
1542
|
+
];
|
|
1543
|
+
const LSOF_ARGS = [
|
|
1544
|
+
"-a",
|
|
1545
|
+
"-d",
|
|
1546
|
+
"cwd",
|
|
1547
|
+
"-Fpn",
|
|
1548
|
+
"-w"
|
|
1549
|
+
];
|
|
1550
|
+
function readRunningProcesses(platform = process.platform) {
|
|
1551
|
+
if (platform !== "darwin" && platform !== "linux") return null;
|
|
1552
|
+
const exec = getExecutor();
|
|
1553
|
+
const ps = exec.runFileQuiet("ps", PS_ARGS, { timeoutMs: LIST_TIMEOUT_MS });
|
|
1554
|
+
if (platform === "linux") return runningFrom(ps, procCwds());
|
|
1555
|
+
const lsof = exec.runFileQuiet("lsof", LSOF_ARGS, { timeoutMs: LIST_TIMEOUT_MS });
|
|
1556
|
+
return runningFrom(ps, lsof === null ? null : parseLsof(lsof));
|
|
1557
|
+
}
|
|
1558
|
+
async function readRunningProcessesAsync(signal, platform = process.platform) {
|
|
1559
|
+
if (platform !== "darwin" && platform !== "linux") return null;
|
|
1560
|
+
const exec = getExecutor();
|
|
1561
|
+
const ps = await exec.runFileQuietAsync("ps", PS_ARGS, {
|
|
1562
|
+
timeoutMs: LIST_TIMEOUT_MS,
|
|
1563
|
+
signal
|
|
1564
|
+
});
|
|
1565
|
+
if (platform === "linux") return runningFrom(ps, procCwds());
|
|
1566
|
+
const lsof = await exec.runFileQuietAsync("lsof", LSOF_ARGS, {
|
|
1567
|
+
timeoutMs: LIST_TIMEOUT_MS,
|
|
1568
|
+
signal
|
|
1569
|
+
});
|
|
1570
|
+
return runningFrom(ps, lsof === null ? null : parseLsof(lsof));
|
|
1571
|
+
}
|
|
1572
|
+
function stimOnPath() {
|
|
1573
|
+
const found = getExecutor().findExecutable("stim");
|
|
1574
|
+
if (!found) return null;
|
|
1575
|
+
try {
|
|
1576
|
+
return realpathSync(found);
|
|
1577
|
+
} catch {
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Why something installed in or running from `folder` still needs it, or null: an installed stim-server service, the
|
|
1583
|
+
* `stim` on PATH, or a live process whose command line or working directory is inside it.
|
|
1584
|
+
*/
|
|
1585
|
+
function runningFromReason(folder, running) {
|
|
1586
|
+
const root = canonicalPath(folder);
|
|
1587
|
+
const inside = (path) => path === root || path.startsWith(`${root}${sep}`);
|
|
1588
|
+
const service = serviceRunningFrom(root, canonicalPath);
|
|
1589
|
+
if (service) return `the stim-server service ${service.label} runs from it`;
|
|
1590
|
+
const stim = stimOnPath();
|
|
1591
|
+
if (stim && inside(stim)) return `the stim on PATH runs from it (${stim})`;
|
|
1592
|
+
if (!running) return "the running processes cannot be listed to prove nothing runs from it";
|
|
1593
|
+
const command = running.commands.find(({ line }) => line.includes(`${root}${sep}`));
|
|
1594
|
+
if (command) return `process ${command.pid} runs from it`;
|
|
1595
|
+
const cwd = running.cwds.find(({ path }) => inside(canonicalPath(path)));
|
|
1596
|
+
if (cwd) return `process ${cwd.pid} works in it`;
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
//#endregion
|
|
1458
1600
|
//#region src/maintenance/artifacts.ts
|
|
1459
|
-
/** Directories that hold only what a build or an install regenerates, relative to an app or package root. */
|
|
1460
|
-
const ARTIFACT_DIRS = {
|
|
1461
|
-
build: [
|
|
1462
|
-
"ios/build",
|
|
1463
|
-
"android/app/build",
|
|
1464
|
-
"android/build",
|
|
1465
|
-
"android/.gradle",
|
|
1466
|
-
".build"
|
|
1467
|
-
],
|
|
1468
|
-
dependencies: ["node_modules", "ios/Pods"]
|
|
1469
|
-
};
|
|
1470
1601
|
const PACKAGE_PARENTS = ["apps", "packages"];
|
|
1471
1602
|
const SCAN_DEPTH = {
|
|
1472
1603
|
build: 3,
|
|
@@ -1480,6 +1611,14 @@ function isDirectory(path) {
|
|
|
1480
1611
|
return false;
|
|
1481
1612
|
}
|
|
1482
1613
|
}
|
|
1614
|
+
function pathExists(path) {
|
|
1615
|
+
try {
|
|
1616
|
+
lstatSync(path);
|
|
1617
|
+
return true;
|
|
1618
|
+
} catch {
|
|
1619
|
+
return false;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1483
1622
|
function artifactWorktrees() {
|
|
1484
1623
|
const found = /* @__PURE__ */ new Map();
|
|
1485
1624
|
for (const root of candidateRoots()) {
|
|
@@ -1495,6 +1634,7 @@ function artifactWorktree(root, entries, source = sourceCheckoutOf(entries)) {
|
|
|
1495
1634
|
return {
|
|
1496
1635
|
path: entry.path,
|
|
1497
1636
|
linked: entry.path !== source.path,
|
|
1637
|
+
locked: Boolean(entry.locked),
|
|
1498
1638
|
keys
|
|
1499
1639
|
};
|
|
1500
1640
|
}
|
|
@@ -1565,8 +1705,8 @@ async function newestWriteAsync(dir, maxDepth, signal) {
|
|
|
1565
1705
|
};
|
|
1566
1706
|
return await walk(dir, 0) ? newest : null;
|
|
1567
1707
|
}
|
|
1568
|
-
function keptReason(candidate, kind, { now, windowMs, pinned, locked }, reads) {
|
|
1569
|
-
const guarded = artifactGuard(candidate, kind, pinned, locked);
|
|
1708
|
+
function keptReason(candidate, kind, { now, windowMs, pinned, locked, running }, reads) {
|
|
1709
|
+
const guarded = artifactGuard(candidate, kind, pinned, locked, running);
|
|
1570
1710
|
if (guarded) return guarded;
|
|
1571
1711
|
const { worktree, path, keys } = candidate;
|
|
1572
1712
|
const tracked = reads ? reads.tracked : gitQuiet(worktree, [
|
|
@@ -1576,15 +1716,23 @@ function keptReason(candidate, kind, { now, windowMs, pinned, locked }, reads) {
|
|
|
1576
1716
|
]);
|
|
1577
1717
|
if (tracked === null) return "git cannot tell whether it holds tracked files";
|
|
1578
1718
|
if (tracked.trim()) return "it holds files git tracks";
|
|
1719
|
+
if (kind === "build") return buildNativeUseReason(keys, now);
|
|
1579
1720
|
const activity = reads ? reads.activity : worktreeActivityOf(worktree, keys);
|
|
1580
1721
|
const written = reads ? reads.written : newestWrite(path, SCAN_DEPTH[kind]);
|
|
1581
1722
|
if (!activity || written === null) return "its last activity cannot be read";
|
|
1582
1723
|
if (now - Math.max(activity.at, written) < windowMs) return `used within the last ${Math.round(windowMs / 6e4)} minutes`;
|
|
1583
1724
|
return null;
|
|
1584
1725
|
}
|
|
1585
|
-
function
|
|
1726
|
+
function buildNativeUseReason(keys, now) {
|
|
1727
|
+
const states = keys.map((key) => readWorkspaceState$1(key)).filter((state) => state !== null);
|
|
1728
|
+
if (!states.length) return "no Stim workspace records when it last ran ios, android or macos";
|
|
1729
|
+
return recentNativeUseReason(Math.max(...states.map((state) => lastNativeUseFrom(state)).filter(Number.isFinite)), now);
|
|
1730
|
+
}
|
|
1731
|
+
function artifactGuard(candidate, kind, pinned, locked, running) {
|
|
1586
1732
|
const { worktree, path, keys } = candidate;
|
|
1587
1733
|
if (keys.some(pinned)) return "pinned by maintenance.keep";
|
|
1734
|
+
if (candidate.locked) return LOCKED_REASON;
|
|
1735
|
+
if (!pathExists(path)) return "it is already gone";
|
|
1588
1736
|
let real;
|
|
1589
1737
|
try {
|
|
1590
1738
|
real = canonicalPath(path);
|
|
@@ -1592,16 +1740,15 @@ function artifactGuard(candidate, kind, pinned, locked) {
|
|
|
1592
1740
|
return "its path cannot be resolved";
|
|
1593
1741
|
}
|
|
1594
1742
|
if (!isDirectory(path) || real !== join(canonicalPath(worktree), relative(worktree, path))) return "it or a directory above it is a link, or it lies outside its worktree";
|
|
1595
|
-
const inUse = keys.flatMap((key) => workspaceInUse(key, {
|
|
1596
|
-
supervisor: kind === "dependencies",
|
|
1597
|
-
nativeRun: key !== locked
|
|
1598
|
-
}));
|
|
1743
|
+
const inUse = keys.flatMap((key) => kind === "build" ? workspaceBuildReasons(key, { nativeRun: key !== locked }) : workspaceInUse(key, { nativeRun: key !== locked }));
|
|
1599
1744
|
if (inUse.length) return `in use: ${inUse.join("; ")}`;
|
|
1745
|
+
if (kind === "dependencies") return runningFromReason(worktree, running === void 0 ? readRunningProcesses() : running);
|
|
1600
1746
|
return null;
|
|
1601
1747
|
}
|
|
1602
1748
|
async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
1603
1749
|
const candidates = [];
|
|
1604
1750
|
const skips = [];
|
|
1751
|
+
const running = kind === "dependencies" ? await readRunningProcessesAsync(signal) : null;
|
|
1605
1752
|
for (const worktree of await artifactWorktreesAsync(signal, operation)) {
|
|
1606
1753
|
if (kind === "dependencies" && !worktree.linked) continue;
|
|
1607
1754
|
const root = canonicalPath(worktree.path);
|
|
@@ -1630,9 +1777,10 @@ async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
|
1630
1777
|
const candidate = {
|
|
1631
1778
|
worktree: worktree.path,
|
|
1632
1779
|
path,
|
|
1633
|
-
keys: worktree.keys
|
|
1780
|
+
keys: worktree.keys,
|
|
1781
|
+
locked: worktree.locked
|
|
1634
1782
|
};
|
|
1635
|
-
let reason = protectedHere ? "the command that started this pass runs inside its worktree" : artifactGuard(candidate, kind, options.pinned);
|
|
1783
|
+
let reason = protectedHere ? "the command that started this pass runs inside its worktree" : artifactGuard(candidate, kind, options.pinned, void 0, running);
|
|
1636
1784
|
if (!reason) {
|
|
1637
1785
|
const tracked = await gitQuietAsync(worktree.path, [
|
|
1638
1786
|
"ls-files",
|
|
@@ -1645,11 +1793,16 @@ async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
|
1645
1793
|
declareFor: operation,
|
|
1646
1794
|
killSignal: "SIGKILL"
|
|
1647
1795
|
});
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1796
|
+
const windowed = tracked !== null && !tracked.trim() && kind === "dependencies";
|
|
1797
|
+
const activity = windowed ? await worktreeActivityOfAsync(worktree.path, worktree.keys, operation) : null;
|
|
1798
|
+
const written = windowed ? await newestWriteAsync(path, SCAN_DEPTH[kind], signal) : null;
|
|
1799
|
+
reason = keptReason(candidate, kind, {
|
|
1800
|
+
...options,
|
|
1801
|
+
running
|
|
1802
|
+
}, {
|
|
1650
1803
|
tracked,
|
|
1651
|
-
activity
|
|
1652
|
-
written
|
|
1804
|
+
activity,
|
|
1805
|
+
written
|
|
1653
1806
|
});
|
|
1654
1807
|
}
|
|
1655
1808
|
if (reason) skips.push({
|
|
@@ -1668,6 +1821,7 @@ async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
|
1668
1821
|
function collectArtifacts(kind, options) {
|
|
1669
1822
|
const candidates = [];
|
|
1670
1823
|
const skips = [];
|
|
1824
|
+
const running = kind === "dependencies" ? readRunningProcesses() : null;
|
|
1671
1825
|
for (const worktree of artifactWorktrees()) {
|
|
1672
1826
|
if (kind === "dependencies" && !worktree.linked) continue;
|
|
1673
1827
|
const root = canonicalPath(worktree.path);
|
|
@@ -1682,9 +1836,13 @@ function collectArtifacts(kind, options) {
|
|
|
1682
1836
|
const candidate = {
|
|
1683
1837
|
worktree: worktree.path,
|
|
1684
1838
|
path,
|
|
1685
|
-
keys: worktree.keys
|
|
1839
|
+
keys: worktree.keys,
|
|
1840
|
+
locked: worktree.locked
|
|
1686
1841
|
};
|
|
1687
|
-
const reason = protectedHere ? "the command that started this pass runs inside its worktree" : keptReason(candidate, kind,
|
|
1842
|
+
const reason = protectedHere ? "the command that started this pass runs inside its worktree" : keptReason(candidate, kind, {
|
|
1843
|
+
...options,
|
|
1844
|
+
running
|
|
1845
|
+
});
|
|
1688
1846
|
if (reason) skips.push({
|
|
1689
1847
|
target: path,
|
|
1690
1848
|
reason
|
|
@@ -1718,36 +1876,55 @@ async function clearArtifact(action, kind, options) {
|
|
|
1718
1876
|
const candidate = {
|
|
1719
1877
|
worktree: worktree.path,
|
|
1720
1878
|
path: action.target,
|
|
1721
|
-
keys: worktree.keys
|
|
1879
|
+
keys: worktree.keys,
|
|
1880
|
+
locked: worktree.locked
|
|
1722
1881
|
};
|
|
1882
|
+
const running = kind === "dependencies" ? await readRunningProcessesAsync() : null;
|
|
1723
1883
|
const early = keptReason(candidate, kind, {
|
|
1724
1884
|
...options,
|
|
1725
|
-
now: Date.now()
|
|
1885
|
+
now: Date.now(),
|
|
1886
|
+
running
|
|
1726
1887
|
});
|
|
1727
1888
|
if (early) return {
|
|
1728
1889
|
status: "kept",
|
|
1729
1890
|
bytes: 0,
|
|
1730
1891
|
detail: early
|
|
1731
1892
|
};
|
|
1893
|
+
const unrestorable = kind === "dependencies" ? await restoreProblem(candidate, options.restoreCache) : null;
|
|
1894
|
+
if (unrestorable && options.requireRestorable) return {
|
|
1895
|
+
status: "kept",
|
|
1896
|
+
bytes: 0,
|
|
1897
|
+
detail: unrestorable
|
|
1898
|
+
};
|
|
1732
1899
|
const before = lowestFree(measureDisk());
|
|
1733
1900
|
const [key] = candidate.keys;
|
|
1734
|
-
const remove = () => {
|
|
1901
|
+
const remove = async () => {
|
|
1902
|
+
const lock = candidate.locked ? "locked" : await worktreeLockAsync(candidate.worktree);
|
|
1903
|
+
if (lock) return lockReason(lock);
|
|
1735
1904
|
const reason = keptReason(candidate, kind, {
|
|
1736
1905
|
...options,
|
|
1737
1906
|
now: Date.now(),
|
|
1907
|
+
running: kind === "dependencies" ? await readRunningProcessesAsync() : null,
|
|
1738
1908
|
...key ? { locked: key } : {}
|
|
1739
1909
|
});
|
|
1740
1910
|
if (reason) return reason;
|
|
1911
|
+
const record = kind === "dependencies" && !unrestorable;
|
|
1912
|
+
if (record) recordLightened(candidate.keys, candidate.path);
|
|
1741
1913
|
rmSync(candidate.path, {
|
|
1742
1914
|
recursive: true,
|
|
1743
1915
|
force: true
|
|
1744
1916
|
});
|
|
1917
|
+
if (record) finishLightened(candidate.keys, candidate.path);
|
|
1745
1918
|
return null;
|
|
1746
1919
|
};
|
|
1747
1920
|
const kept = key ? await withIdleWorkspace(key, remove, {
|
|
1748
1921
|
purpose: "maintenance",
|
|
1749
|
-
supervisor: kind === "dependencies"
|
|
1750
|
-
|
|
1922
|
+
supervisor: kind === "dependencies",
|
|
1923
|
+
...kind === "build" ? {
|
|
1924
|
+
hosted: false,
|
|
1925
|
+
managedLocks: false
|
|
1926
|
+
} : {}
|
|
1927
|
+
}).then((run) => run.ran ? run.value : `in use: ${run.reasons.join("; ")}`) : await remove();
|
|
1751
1928
|
if (kept) return {
|
|
1752
1929
|
status: "kept",
|
|
1753
1930
|
bytes: 0,
|
|
@@ -2110,17 +2287,24 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
2110
2287
|
const actions = [];
|
|
2111
2288
|
const skips = [];
|
|
2112
2289
|
const reason = `disk pressure level 2, idle for ${settings.pressureProtectMinutes} minutes`;
|
|
2290
|
+
const lightenReason = `disk pressure level 2, no ios, android or macos run in the last ${LIGHTEN_AFTER_MS / 6e4} minutes`;
|
|
2113
2291
|
const outputs = (await collectWorkspaceOutputs({
|
|
2114
2292
|
olderThan: null,
|
|
2115
2293
|
now,
|
|
2116
2294
|
measure: false,
|
|
2117
2295
|
signal: operation?.signal,
|
|
2118
|
-
operation
|
|
2296
|
+
operation,
|
|
2297
|
+
lighten: true
|
|
2119
2298
|
})).workspaces.flatMap((entry) => {
|
|
2120
2299
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
2300
|
+
if (root !== null && keptByLock(entry) && entry.keptReason) skips.push({
|
|
2301
|
+
target: root,
|
|
2302
|
+
reason: entry.keptReason,
|
|
2303
|
+
workspace: root
|
|
2304
|
+
});
|
|
2121
2305
|
if (root === null || !entry.willClear || root === protectedRoot || pinned(root)) return [];
|
|
2122
2306
|
const used = workspaceLastUsed(root);
|
|
2123
|
-
return Number.isFinite(used)
|
|
2307
|
+
return Number.isFinite(used) ? [{
|
|
2124
2308
|
root,
|
|
2125
2309
|
used
|
|
2126
2310
|
}] : [];
|
|
@@ -2132,7 +2316,7 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
2132
2316
|
target: root,
|
|
2133
2317
|
workspace: root,
|
|
2134
2318
|
bytes: size?.bytes ?? 0,
|
|
2135
|
-
reason,
|
|
2319
|
+
reason: lightenReason,
|
|
2136
2320
|
level: 2
|
|
2137
2321
|
});
|
|
2138
2322
|
}
|
|
@@ -2168,7 +2352,7 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
2168
2352
|
kind: "would-clear-build-dirs",
|
|
2169
2353
|
target: candidate.path,
|
|
2170
2354
|
bytes: 0,
|
|
2171
|
-
reason,
|
|
2355
|
+
reason: lightenReason,
|
|
2172
2356
|
level: 2
|
|
2173
2357
|
});
|
|
2174
2358
|
skips.push(...build.skips);
|
|
@@ -2628,14 +2812,17 @@ async function clearOutputs(action, context) {
|
|
|
2628
2812
|
if (!root) return kept("the action names no workspace");
|
|
2629
2813
|
if (root === context.protectedRoot) return kept("the command that started this pass runs in it");
|
|
2630
2814
|
if (maintenancePinned(root)) return kept("pinned by maintenance.keep");
|
|
2631
|
-
const
|
|
2815
|
+
const lighten = action.level === 2;
|
|
2816
|
+
const recent = lighten ? null : recentUse(root, context.settings, protectWindowMs(action, context.settings));
|
|
2632
2817
|
if (recent) return kept(recent);
|
|
2633
2818
|
const olderThan = action.olderThanDays ?? null;
|
|
2634
2819
|
const now = Date.now();
|
|
2635
2820
|
const report = collectWorkspaceOutputs({
|
|
2636
2821
|
olderThan,
|
|
2637
2822
|
now,
|
|
2638
|
-
measure: false
|
|
2823
|
+
measure: false,
|
|
2824
|
+
lighten,
|
|
2825
|
+
only: root
|
|
2639
2826
|
});
|
|
2640
2827
|
const entry = report.workspaces.find((candidate) => candidate.projectRoot && canonicalPath(candidate.projectRoot) === root);
|
|
2641
2828
|
if (!entry) return kept("it has no build outputs any more");
|
|
@@ -2644,7 +2831,8 @@ async function clearOutputs(action, context) {
|
|
|
2644
2831
|
workspaces: [entry]
|
|
2645
2832
|
}, {
|
|
2646
2833
|
olderThan,
|
|
2647
|
-
now
|
|
2834
|
+
now,
|
|
2835
|
+
lighten
|
|
2648
2836
|
}));
|
|
2649
2837
|
return outcomeOf(results, action.bytes);
|
|
2650
2838
|
}
|
|
@@ -2660,7 +2848,12 @@ async function removeWorktree(action, context) {
|
|
|
2660
2848
|
...sweep,
|
|
2661
2849
|
worktrees: [worktree]
|
|
2662
2850
|
}));
|
|
2663
|
-
|
|
2851
|
+
const outcome = outcomeOf(results, freedSince(before));
|
|
2852
|
+
const removal = results.find((result) => result.status === "done")?.detail;
|
|
2853
|
+
return outcome.status === "done" ? {
|
|
2854
|
+
...outcome,
|
|
2855
|
+
detail: removal ?? action.reason
|
|
2856
|
+
} : outcome;
|
|
2664
2857
|
}
|
|
2665
2858
|
async function removeOrphan(action) {
|
|
2666
2859
|
const orphan = (await collectOrphanedWorkspaces(Object.keys(loadConfig$1()?.projects ?? {}), listMountedVolumes())).orphaned.find((candidate) => candidate.dir === action.target);
|
|
@@ -2935,4 +3128,4 @@ function diskRecovered(budget) {
|
|
|
2935
3128
|
return measureDisk().every((disk) => disk.freeMb >= floor);
|
|
2936
3129
|
}
|
|
2937
3130
|
//#endregion
|
|
2938
|
-
export {
|
|
3131
|
+
export { worktreeRemovalReason as C, worktreePullRequestNote as S, ownedDeviceUsage as _, previewMaintenance as a, collectWorktreeSweep as b, deleteTempLeftovers as c, appRoots as d, artifactWorktrees as f, measureOwnedDevices as g, finishedWorkspaces as h, plannedMaintenance as i, tempLeftoverLines as l, collectArtifactsAsync as m, diskRecovered as n, triggeringRoot as o, clearArtifact as p, executeAction as r, collectTempLeftovers as s, deleteIdleWorkspaceDevices as t, tempLeftoverSection as u, maintenancePinned as v, removeWorktrees as x, candidateRootsAsync as y };
|