stim 1.20.2 → 1.22.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 +141 -8
- package/dist/acquire-artifact-Co2k4f7O.mjs +171 -0
- package/dist/act-DsuqEkiM.mjs +2801 -0
- package/dist/activity-CMLmzp7o.mjs +1397 -0
- package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-DUFaTMdd.mjs} +23 -67
- package/dist/{android-DCKZrNvV.mjs → android-ByRMUoiJ.mjs} +157 -93
- package/dist/{android-Mz_Inn3w.mjs → android-C7sVmyI9.mjs} +299 -116
- package/dist/{android-Dlzxshgp.mjs → android-DGkNqa_c.mjs} +5 -5
- package/dist/{android-HqP1_vB_.mjs → android-DR5lZ2Az.mjs} +2 -2
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-ngferVq2.mjs} +7 -6
- package/dist/android-project-BCAAmMwz.mjs +12 -0
- package/dist/android-project-DVWyCbWU.d.mts +391 -0
- package/dist/api.d.mts +810 -64
- package/dist/api.mjs +782 -1
- package/dist/{artifact-HSwkIWEQ.mjs → artifact-8EY8SAPw.mjs} +240 -213
- package/dist/{artifact-D3czlUvT.mjs → artifact-DJPy518Y.mjs} +203 -164
- package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
- package/dist/{browser-web-CA-F1GQo.mjs → browser-web-Bcv99PBM.mjs} +194 -64
- package/dist/budget-Cvwn54qV.mjs +9285 -0
- package/dist/{build-DYDbfkk5.mjs → build-CabC3G23.mjs} +153 -98
- package/dist/build-cache-Dv7RN200.mjs +602 -0
- package/dist/build-plan-DUC8Ka9y.mjs +248 -0
- package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DSeQjt-Q.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-zdKiYQ3E.mjs → ccache-Btwc36-I.mjs} +10 -9
- package/dist/{cdp-Dq_ypAlJ.mjs → cdp-3fwICjzi.mjs} +18 -5
- package/dist/{chrome-BnzZMqsR.mjs → chrome-Bbw689-6.mjs} +7 -4
- package/dist/{cli-CLP3diBm.mjs → cli-CHZa9Lvk.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/client-OyRoEuSr.mjs +1577 -0
- package/dist/collector-run.d.mts +4 -40
- package/dist/collector-run.mjs +9 -8
- package/dist/{command-output-BTy8hZ0F.mjs → command-output-gwpm28fu.mjs} +1 -1
- package/dist/config-DlrsduwG.mjs +955 -0
- package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-x9rN6bhs.mjs} +14 -4
- package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-1I9KZT1Y.mjs} +20 -5
- package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
- package/dist/{dev-client-DAWVIGBu.mjs → dev-client-BSDR5h3F.mjs} +2 -2
- package/dist/{device-BECOiufl.mjs → device-B-L3Fbxy.mjs} +91 -34
- package/dist/device-DklWZLqb.mjs +1068 -0
- package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-DK5_EwRS.mjs} +42 -13
- package/dist/device-host-worker.mjs +76 -79
- package/dist/{device-ios-COSi6oS1.mjs → device-ios-DoB6KFCO.mjs} +77 -51
- package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-xJPQ_QQG.mjs} +14 -26
- package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-BMkdsefq.mjs} +5 -5
- package/dist/{doctor-kfMBnUw6.mjs → doctor-Bo7BXLux.mjs} +271 -320
- package/dist/{doctor-CB8oZKCk.mjs → doctor-D5_EzwfA.mjs} +186 -91
- package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
- package/dist/doctor-fingerprint.mjs +19 -0
- package/dist/doctor-thjWAV0z.mjs +2 -0
- package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-N2wDotwQ.mjs} +40 -21
- package/dist/{eas-build-JyfqyHfC.mjs → eas-build-CwknaQYj.mjs} +53 -20
- package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-CSgAulr5.mjs} +41 -214
- package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-DlY_serQ.mjs} +230 -11
- package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-DBWO2rxE.mjs} +172 -82
- package/dist/exec-DEoAhcze.mjs +858 -0
- package/dist/exec-DnYc4HGH.d.mts +78 -0
- package/dist/{gc-qWOMdnER.mjs → gc-CXxN-4SE.mjs} +1091 -1029
- package/dist/gc-DnNDQyaP.mjs +3 -0
- package/dist/{guide-G9cAbVAc.mjs → guide-Br0LEfKy.mjs} +1165 -297
- package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-B-9f-jkd.mjs} +10 -8
- package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DZAPrcro.mjs} +34 -19
- package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CsCS21hn.mjs} +1 -1
- package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-FIRx9X2f.mjs} +77 -43
- package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-_awYSpfv.mjs} +35 -22
- package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-BdzE668-.mjs} +49 -27
- package/dist/idle-C4cZ757K.d.mts +24 -0
- package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DDg3SdvY.mjs} +11 -10
- package/dist/ios-CDvlmUs7.d.mts +24 -0
- package/dist/{ios-BwVCF7oA.mjs → ios-Ds1clbIt.mjs} +8 -8
- package/dist/{ios-device-D7pi2Sca.mjs → ios-device--h_-8ENa.mjs} +51 -26
- package/dist/{ios-device-B5veSDDQ.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
- package/dist/{ios-RkW4pnQf.mjs → ios-hcBpnEGk.mjs} +200 -93
- package/dist/{ios-Ce7bc7br.mjs → ios-pm4nL6By.mjs} +160 -108
- package/dist/{ios-project-K9hY_Jab.mjs → ios-project-CZhKODF3.mjs} +13 -13
- package/dist/ios-signing-BtAffm0A.mjs +489 -0
- package/dist/{ios-state-CBLe1xYw.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
- package/dist/{ios-nOLJGVdy.mjs → ios-xtlRHaeB.mjs} +1 -1
- package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Bwhh4S7V.mjs} +30 -25
- package/dist/{launch-C3qJ6Agb.mjs → launch-BjxemNpK.mjs} +85 -543
- package/dist/{launch-F4sOqAhB.mjs → launch-CCzXlc8r.mjs} +91 -90
- package/dist/logs-BfwwadsZ.mjs +479 -0
- package/dist/logs-jTS_lHSo.mjs +248 -0
- package/dist/{macos-D7uDvO-z.mjs → macos-DVlSSyUg.mjs} +1 -1
- package/dist/macos-NfV2D7dO.mjs +694 -0
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +123 -248
- package/dist/{metro-DnCEjCxs.mjs → metro-DiXtA3Ty.mjs} +107 -30
- package/dist/metro-gateway-CKZqKqx7.mjs +209 -0
- package/dist/{named-ports-4WopRPg-.mjs → named-ports-DkEzOfzO.mjs} +42 -90
- package/dist/native-android-CqgnOgsT.mjs +645 -0
- package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
- package/dist/native-gradle-inputs-Dnh84Zbd.mjs +211 -0
- package/dist/native-inputs-TRTTTRxt.mjs +91 -0
- package/dist/native-run-NwUuxbkg.mjs +276 -0
- package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-B7KIafpM.mjs} +11 -9
- package/dist/native-source-Y0yLhFyQ.mjs +133 -0
- package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-D_VOfFL7.mjs} +26 -18
- package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-BYDOHWLN.mjs} +104 -60
- package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
- package/dist/offload-worker.d.mts +59 -41
- package/dist/offload-worker.mjs +478 -115
- package/dist/operation-exec-BW0em61G.mjs +171 -0
- package/dist/{ownership-DCtw_2IA.mjs → ownership-C5fo5Edb.mjs} +3 -3
- package/dist/{page-DRHy329N.mjs → page-DBL2PiUU.mjs} +12 -5
- package/dist/paths-BsJMoPP2.mjs +12 -0
- package/dist/paths-DQtTgsBf.mjs +42 -0
- package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BnGgJRRZ.mjs} +5 -5
- package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-DIsMtN-d.mjs} +15 -11
- package/dist/{ports-DdSUicVo.mjs → ports-Cy1RkmuQ.mjs} +3 -3
- package/dist/prebuild-D4JoEAEs.mjs +484 -0
- package/dist/{project-_phNIJfs.mjs → project-wM_XFTvE.mjs} +65 -37
- package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-W1IuLXDt.mjs} +102 -20
- package/dist/pull-request-eODyIqZF.d.mts +124 -0
- package/dist/pull-requests.d.mts +2 -120
- package/dist/pull-requests.mjs +2 -2
- package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-6OZ7MSM7.mjs} +121 -72
- package/dist/{gradle-DSrXb6lG.mjs → react-native-build-Dvd8hC21.mjs} +292 -15
- package/dist/react-native-doctor-DsoSF1Y9.mjs +234 -0
- package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-4u1Rn-GR.mjs} +71 -39
- package/dist/{recordings-D0d5aQt0.mjs → recordings-CQmfzAh7.mjs} +12 -9
- package/dist/registration-BcRgF6Ox.mjs +51 -0
- package/dist/{reload-C8JhxjSh.mjs → reload-BzkYabB-.mjs} +94 -47
- package/dist/reload-D7AVlb8N.mjs +2 -0
- package/dist/{remote-BiR6aYjy.mjs → remote-DjGDmlTZ.mjs} +26 -18
- package/dist/result-D2Ykz_iD.mjs +435 -0
- package/dist/{run-BtPgpKks.mjs → run-DidHghD1.mjs} +5 -5
- package/dist/selection-DSMbWEX2.mjs +620 -0
- package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CafzuyFB.mjs} +3 -4
- package/dist/{server-command-CTtCkmcQ.mjs → server-command-C6QjeupS.mjs} +14 -7
- package/dist/{server-expo-DsguMGUF.mjs → server-expo-CrjB29pq.mjs} +54 -11
- package/dist/server-expo-D58c9L0M.mjs +2 -0
- package/dist/{settings-B717odTD.mjs → settings-C7O8A6ZI.mjs} +309 -119
- package/dist/settings-DpR-1Wnn.mjs +114 -0
- package/dist/settings-write-CzD60rOD.mjs +360 -0
- package/dist/settings.schema.json +176 -16
- package/dist/{simslim-CCr3rE-A.mjs → simslim-BNckWpXi.mjs} +14 -12
- package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-CbfmNgM6.mjs} +15 -20
- package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
- package/dist/stage-Bps5oius.mjs +200 -0
- package/dist/{start-TXeMmmO2.mjs → start-Br-oxqMD.mjs} +1 -1
- package/dist/start-EojN4WFz.mjs +1364 -0
- package/dist/{state-D1Icyjlu.mjs → state--smjFSTL.mjs} +55 -13
- package/dist/{state-CG_OFoaA.mjs → state-08I3hw3_.mjs} +3 -2
- package/dist/{stats-BoY5sEPU.mjs → stats-D3GerlFW.mjs} +7 -13
- package/dist/stats-report-BzaPrRm6.mjs +16 -0
- package/dist/{status-BTA7kKiQ.mjs → status-BRROykC8.mjs} +7 -5
- package/dist/status-EvrK72L2.mjs +2 -0
- package/dist/{status-WgFbkRzj.mjs → status-WBDajew2.mjs} +554 -452
- package/dist/{status-watch-C23ILtf9.mjs → status-watch-Bg_u-pwR.mjs} +222 -25
- package/dist/status-worker.d.mts +1 -0
- package/dist/status-worker.mjs +19 -0
- package/dist/stim-desktop-D5OGpYZM.mjs +112 -0
- package/dist/{stop-DR6VoDIk.mjs → stop-DTZ9uTw3.mjs} +2 -2
- package/dist/{stop-DPEhunlw.mjs → stop-Dky10AEJ.mjs} +33 -23
- package/dist/{stop-BNmBMi1F.mjs → stop-Mv6W9FAk.mjs} +137 -98
- package/dist/supervisor-run.d.mts +8 -17
- package/dist/supervisor-run.mjs +56 -28
- package/dist/{support-CwjbFs9H.mjs → support-CNioewsd.mjs} +14 -14
- package/dist/{support-DMTqj3Hm.mjs → support-yUiOjnVY.mjs} +20 -13
- package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
- package/dist/swiftpm-macos-BIak-Rxv.mjs +532 -0
- package/dist/toolchain-BY8X8HXx.mjs +2 -0
- package/dist/toolchain-DpJMHq0n.mjs +876 -0
- package/dist/{trigger-CigAYjeL.mjs → trigger-Cbyc41d_.mjs} +21 -6
- package/dist/trigger-yb_nFzPF.mjs +2 -0
- package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-CA3TgT3-.mjs} +263 -156
- package/dist/web-CZ07gd77.mjs +2 -0
- package/dist/{web-BDBMxDpx.mjs → web-DKx6yoFA.mjs} +20 -14
- package/dist/web-run.mjs +13 -12
- package/dist/windows-report.d.mts +1 -0
- package/dist/windows-report.mjs +18 -0
- package/dist/windows-report.ps1 +43 -0
- package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-U08dEzhG.mjs} +62 -58
- package/dist/{workspaces-C36s2jb9.mjs → workspaces-CpANmBlq.mjs} +1723 -1286
- package/dist/{worktree-CgvJYJ-Q.mjs → worktree-CHecZ4Oq.mjs} +1097 -547
- package/dist/worktree-ZqZVjD9K.mjs +2 -0
- package/dist/xcode-BXn9-xYx.mjs +896 -0
- package/package.json +7 -5
- package/shim/android-audio/Main.java +24 -0
- package/shim/android-audio/README.md +17 -0
- package/shim/android-audio.jar +0 -0
- package/shim/android-optimizations.gradle +7 -5
- package/dist/activity-BSV745Kz.mjs +0 -629
- package/dist/api-qvOzWyfO.mjs +0 -154
- package/dist/api-run.mjs +0 -294
- package/dist/app-install-BIKtMfPq.mjs +0 -896
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
- package/dist/budget-f7516Zk0.mjs +0 -4106
- package/dist/build-facts-DcLv2HSd.d.mts +0 -111
- package/dist/cancellation-C_22VQTH.mjs +0 -24
- package/dist/client-qQAaXSUs.mjs +0 -1771
- package/dist/config-BYDxlMY3.mjs +0 -562
- package/dist/device-DuiPJQSn.mjs +0 -290
- package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
- package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
- package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
- package/dist/exec-DqKo9GKJ.mjs +0 -268
- package/dist/git-DDfFzkMm.mjs +0 -45
- package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
- package/dist/logs-BGrEUaEs.mjs +0 -383
- package/dist/macos-Ch5VJmcS.mjs +0 -584
- package/dist/metro-gateway-CX9Xlkq2.mjs +0 -103
- package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
- package/dist/native-android-D5qc3-_v.mjs +0 -226
- package/dist/native-gradle-inputs-BsLRrl7u.mjs +0 -349
- package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
- package/dist/plan-C4TjdPsR.mjs +0 -260
- package/dist/prebuild-DYbucPXy.mjs +0 -212
- package/dist/preview-78a9kR_-.mjs +0 -1011
- package/dist/react-native-build-CtCccJtb.mjs +0 -239
- package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
- package/dist/remote-cache-OyOyVIS3.mjs +0 -526
- package/dist/result-CaJg5Iat.mjs +0 -186
- package/dist/server-expo-Bigriskl.mjs +0 -2
- package/dist/settings-BORNaaCO.mjs +0 -402
- package/dist/settings-vk3mJGSm.d.mts +0 -13
- package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
- package/dist/stage-KNTQopqv.mjs +0 -157
- package/dist/start-BWqzODpb.mjs +0 -1116
- package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
- package/dist/swiftpm-macos-DRNVJWlb.mjs +0 -119
- package/dist/tailnet-Dh-qiYzG.mjs +0 -265
- package/dist/toolchain-BFkAcstd.mjs +0 -2
- package/dist/toolchain-DxSsNssu.mjs +0 -1657
- package/dist/trigger-9_USgmxz.mjs +0 -2
- package/dist/web-Dq-i3wzJ.mjs +0 -2
- package/dist/worktree-DpLdCHga.mjs +0 -2
- package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
- package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
package/dist/maintenance-run.mjs
CHANGED
|
@@ -1,236 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { r as createNdjsonWriter } from "./ndjson-GOnbyvso.mjs";
|
|
6
|
-
import { t as relaunchWithLogFile } from "./detached-entry-B9C_zeQC.mjs";
|
|
7
|
-
import { F as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-RkW4pnQf.mjs";
|
|
1
|
+
import { P as formatBytes } from "./config-DlrsduwG.mjs";
|
|
2
|
+
import { Tt as deviceSweepIsScoped, u as resolveBudget } from "./budget-Cvwn54qV.mjs";
|
|
3
|
+
import { I as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-hcBpnEGk.mjs";
|
|
4
|
+
import { v as maintenanceLogger } from "./client-OyRoEuSr.mjs";
|
|
8
5
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
6
|
+
import { t as relaunchWithLogFile } from "./detached-entry-BwNEtIrP.mjs";
|
|
7
|
+
import { A as levelFloors, C as measureDisk, D as measureSizes, M as lowestFree, O as sizeScanDeferred, T as measurePressure, j as levelStillShort, k as diskPressureLevel } from "./worktree-CHecZ4Oq.mjs";
|
|
8
|
+
import { i as plannedMaintenance, m as measureOwnedDevices, n as diskRecovered, o as triggeringRoot, r as executeAction } from "./act-DsuqEkiM.mjs";
|
|
9
9
|
import { r as due, t as capChildLog } from "./attempt-DW-mQqM7.mjs";
|
|
10
|
-
import { a as maintenancePinned, c as removeWorktrees, d as cacheBlocked, f as measureDisk, h as sizeScanDeferred, i as cacheEntryProtection, m as measureSizes, o as recentUse, p as measurePressure, r as triggeringRoot, t as plannedMaintenance } from "./preview-78a9kR_-.mjs";
|
|
11
|
-
import { appendFileSync, existsSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
12
|
-
import { basename, join, resolve, sep } from "node:path";
|
|
13
|
-
import { MAINTENANCE_LOG_NAME, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState, sharedCompilationCache, workspaceLogsDir } from "@stim-cli/core/state";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { LOG_ROTATE_BYTES, buildCacheRoot, metroCacheRoot, rotatedLogPath, withDirLock } from "@stim-cli/core";
|
|
16
10
|
import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
async function quietly(run) {
|
|
24
|
-
const { log, error } = {
|
|
25
|
-
log: console.log,
|
|
26
|
-
error: console.error
|
|
27
|
-
};
|
|
28
|
-
const exitCode = process.exitCode;
|
|
29
|
-
takeGcResults();
|
|
30
|
-
console.log = () => {};
|
|
31
|
-
console.error = () => {};
|
|
32
|
-
try {
|
|
33
|
-
return {
|
|
34
|
-
value: await run(),
|
|
35
|
-
results: takeGcResults()
|
|
36
|
-
};
|
|
37
|
-
} finally {
|
|
38
|
-
console.log = log;
|
|
39
|
-
console.error = error;
|
|
40
|
-
process.exitCode = exitCode;
|
|
41
|
-
takeGcResults();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function outcomeOf(results, fallbackBytes) {
|
|
45
|
-
const failed = results.find((result) => result.status === "failed");
|
|
46
|
-
if (failed) return {
|
|
47
|
-
status: "failed",
|
|
48
|
-
bytes: 0,
|
|
49
|
-
detail: failed.detail ?? `could not process ${failed.label}`
|
|
50
|
-
};
|
|
51
|
-
const done = results.filter((result) => result.status === "done");
|
|
52
|
-
if (done.length) return {
|
|
53
|
-
status: "done",
|
|
54
|
-
bytes: done.reduce((sum, result) => sum + (result.bytes ?? 0), 0) || fallbackBytes,
|
|
55
|
-
detail: done.map((result) => result.label).join(", ")
|
|
56
|
-
};
|
|
57
|
-
return kept(results.find((result) => result.detail)?.detail ?? "nothing was eligible when the action ran");
|
|
58
|
-
}
|
|
59
|
-
function rootCache(dir) {
|
|
60
|
-
const name = canonicalPath(dir) === canonicalPath(buildCacheRoot()) ? "Build cache" : canonicalPath(dir) === canonicalPath(metroCacheRoot()) ? "Metro transform caches" : null;
|
|
61
|
-
return name ? {
|
|
62
|
-
name,
|
|
63
|
-
dir,
|
|
64
|
-
prune: "entries",
|
|
65
|
-
entriesDepth: name === "Build cache" ? 2 : 3,
|
|
66
|
-
note: ""
|
|
67
|
-
} : null;
|
|
68
|
-
}
|
|
69
|
-
function cacheOf(action) {
|
|
70
|
-
const discovered = discoverCaches();
|
|
71
|
-
if (action.dir) {
|
|
72
|
-
const dir = canonicalPath(action.dir);
|
|
73
|
-
return discovered.find((cache) => canonicalPath(cache.dir) === dir) ?? rootCache(action.dir);
|
|
74
|
-
}
|
|
75
|
-
return discovered.find((cache) => cacheLabel(cache) === action.target) ?? null;
|
|
76
|
-
}
|
|
77
|
-
function trimCache(action, context) {
|
|
78
|
-
const cache = cacheOf(action);
|
|
79
|
-
if (!cache) return kept("it is no longer a cache Stim may trim");
|
|
80
|
-
const [planned] = planCacheEmptying([cache], false);
|
|
81
|
-
if (!planned || planned.machineGlobal) return kept(planned?.machineGlobal ?? "it is no longer a cache Stim may trim");
|
|
82
|
-
const aged = action.olderThanDays !== void 0;
|
|
83
|
-
const result = pruneCache(cache, {
|
|
84
|
-
olderThanDays: Math.max(action.olderThanDays ?? 0, context.settings.protectRecentHours / 24),
|
|
85
|
-
byMtime: true,
|
|
86
|
-
protect: context.protect ??= cacheEntryProtection(),
|
|
87
|
-
...aged ? {} : { evictBytes: action.bytes }
|
|
88
|
-
});
|
|
89
|
-
if (result.skipped) return kept(result.skipped);
|
|
90
|
-
if (result.failed) return {
|
|
91
|
-
status: "failed",
|
|
92
|
-
bytes: result.bytes,
|
|
93
|
-
detail: `${result.failed} entries could not be removed`
|
|
94
|
-
};
|
|
95
|
-
const protectedNote = result.protectedEntries ? `; ${result.protectedEntries} protected entries kept` : "";
|
|
96
|
-
if (result.removed === 0) return kept(`no unprotected entry was old enough${protectedNote}`);
|
|
97
|
-
return {
|
|
98
|
-
status: "done",
|
|
99
|
-
bytes: result.bytes,
|
|
100
|
-
detail: `${result.removed} entries${protectedNote}`,
|
|
101
|
-
...!aged && result.bytes < action.bytes ? { shortfall: `${action.target} reached ${result.bytes} of ${action.bytes} bytes${protectedNote}` } : {}
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
async function emptyCompilationCache(action, context) {
|
|
105
|
-
if (!measureDisk().some((disk) => disk.freeMb < context.budget.hardFloorDiskMb)) return kept("free disk is above budget.hardFloorDiskGb, and this cache can only be emptied whole");
|
|
106
|
-
const dir = sharedCompilationCache();
|
|
107
|
-
const blocked = cacheBlocked({
|
|
108
|
-
name: "Swift compilation cache",
|
|
109
|
-
dir,
|
|
110
|
-
category: "compilation-cache"
|
|
111
|
-
});
|
|
112
|
-
if (blocked) return kept(blocked);
|
|
113
|
-
const cache = discoverCaches().find((candidate) => canonicalPath(candidate.dir) === canonicalPath(dir));
|
|
114
|
-
if (cache?.prune !== "atomic") return kept("it is not a registered cache Stim empties whole");
|
|
115
|
-
const [planned] = planCacheEmptying([{
|
|
116
|
-
...cache,
|
|
117
|
-
bytes: action.bytes
|
|
118
|
-
}], true);
|
|
119
|
-
const { results } = await quietly(() => emptyCaches(planned ? [planned] : []));
|
|
120
|
-
return outcomeOf(results, action.bytes);
|
|
121
|
-
}
|
|
122
|
-
async function clearOutputs(action, context) {
|
|
123
|
-
const root = action.workspace;
|
|
124
|
-
if (!root) return kept("the action names no workspace");
|
|
125
|
-
if (root === context.protectedRoot) return kept("the command that started this pass runs in it");
|
|
126
|
-
if (maintenancePinned(root)) return kept("pinned by maintenance.keep");
|
|
127
|
-
const recent = recentUse(root, context.settings);
|
|
128
|
-
if (recent) return kept(recent);
|
|
129
|
-
const olderThan = action.olderThanDays ?? null;
|
|
130
|
-
const now = Date.now();
|
|
131
|
-
const report = collectWorkspaceOutputs({
|
|
132
|
-
olderThan,
|
|
133
|
-
now,
|
|
134
|
-
measure: false
|
|
135
|
-
});
|
|
136
|
-
const entry = report.workspaces.find((candidate) => candidate.projectRoot && canonicalPath(candidate.projectRoot) === root);
|
|
137
|
-
if (!entry) return kept("it has no build outputs any more");
|
|
138
|
-
const { results } = await quietly(() => clearWorkspaceOutputs({
|
|
139
|
-
...report,
|
|
140
|
-
workspaces: [entry]
|
|
141
|
-
}, {
|
|
142
|
-
olderThan,
|
|
143
|
-
now
|
|
144
|
-
}));
|
|
145
|
-
return outcomeOf(results, action.bytes);
|
|
146
|
-
}
|
|
147
|
-
async function removeWorktree(action, context) {
|
|
148
|
-
const sweep = context.worktreeSweep;
|
|
149
|
-
const worktree = sweep?.worktrees.find((candidate) => candidate.path === action.target);
|
|
150
|
-
if (!sweep || !worktree) return kept("it is not in this pass's worktree check");
|
|
151
|
-
const path = canonicalPath(worktree.path);
|
|
152
|
-
if (context.protectedRoot === path || context.protectedRoot.startsWith(`${path}${sep}`)) return kept("the command that started this pass runs inside it");
|
|
153
|
-
if (worktree.keys.some(maintenancePinned)) return kept("pinned by maintenance.keep");
|
|
154
|
-
const { results } = await quietly(() => removeWorktrees({
|
|
155
|
-
...sweep,
|
|
156
|
-
worktrees: [worktree]
|
|
157
|
-
}));
|
|
158
|
-
return outcomeOf(results, 0);
|
|
159
|
-
}
|
|
160
|
-
async function removeOrphan(action) {
|
|
161
|
-
const orphan = collectOrphanedWorkspaces(Object.keys(loadConfig$1()?.projects ?? {}), listMountedVolumes()).orphaned.find((candidate) => candidate.dir === action.target);
|
|
162
|
-
if (!orphan) return kept("it is no longer an orphaned workspace directory");
|
|
163
|
-
const { results } = await quietly(() => deleteOrphanedWorkspaces([orphan]));
|
|
164
|
-
return outcomeOf(results, orphan.bytes ?? 0);
|
|
165
|
-
}
|
|
166
|
-
function unregisterCache(action) {
|
|
167
|
-
const dir = action.dir ?? action.target;
|
|
168
|
-
if (existsSync(dir) || !isOnMountedVolume(dir, listMountedVolumes()) || !readManifest().caches.some((c) => c.dir === dir)) return kept("it can no longer be shown to be a stale registration");
|
|
169
|
-
return unregister(dir) ? {
|
|
170
|
-
status: "done",
|
|
171
|
-
bytes: 0,
|
|
172
|
-
detail: dir
|
|
173
|
-
} : kept("it was already unregistered");
|
|
174
|
-
}
|
|
175
|
-
async function executeAction(action, context) {
|
|
176
|
-
switch (action.kind) {
|
|
177
|
-
case "would-clear-outputs": return clearOutputs(action, context);
|
|
178
|
-
case "would-trim-cache": return trimCache(action, context);
|
|
179
|
-
case "would-empty-cache": return emptyCompilationCache(action, context);
|
|
180
|
-
case "would-remove-worktree": return removeWorktree(action, context);
|
|
181
|
-
case "would-remove-orphan": return removeOrphan(action);
|
|
182
|
-
case "would-unregister-cache": return unregisterCache(action);
|
|
183
|
-
default: return kept("automatic maintenance does not stop devices or dev servers yet");
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
function diskRecovered(budget) {
|
|
187
|
-
const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
|
|
188
|
-
return measureDisk().every((disk) => disk.freeMb >= floor);
|
|
189
|
-
}
|
|
190
|
-
//#endregion
|
|
191
|
-
//#region src/maintenance/log.ts
|
|
192
|
-
function maintenanceLogger(settings, pass, trigger) {
|
|
193
|
-
const file = maintenanceNdjsonFile();
|
|
194
|
-
const rotated = rotatedLogPath(file);
|
|
195
|
-
withDirLock(`${file}.lock`, () => {
|
|
196
|
-
try {
|
|
197
|
-
if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
|
|
198
|
-
} catch {}
|
|
199
|
-
});
|
|
200
|
-
const writer = createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
|
|
201
|
-
return {
|
|
202
|
-
write(event, level, msg, fields = {}) {
|
|
203
|
-
if (level === "debug" && !settings.logChecks) return null;
|
|
204
|
-
const record = {
|
|
205
|
-
...fields,
|
|
206
|
-
ts: Date.now(),
|
|
207
|
-
src: "maintenance",
|
|
208
|
-
level,
|
|
209
|
-
msg,
|
|
210
|
-
event,
|
|
211
|
-
pass,
|
|
212
|
-
trigger,
|
|
213
|
-
mode: settings.mode === "on" ? "on" : "report"
|
|
214
|
-
};
|
|
215
|
-
if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
|
|
216
|
-
if (typeof fields.workspace === "string" && [
|
|
217
|
-
"maintenance_action",
|
|
218
|
-
"maintenance_failure",
|
|
219
|
-
"maintenance_skip"
|
|
220
|
-
].includes(event)) {
|
|
221
|
-
const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
|
|
222
|
-
try {
|
|
223
|
-
if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
|
|
224
|
-
} finally {
|
|
225
|
-
workspace.close();
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return record;
|
|
229
|
-
},
|
|
230
|
-
close: () => writer.close()
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
//#endregion
|
|
11
|
+
import { randomBytes } from "node:crypto";
|
|
12
|
+
import { appendFileSync, mkdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { basename, join, resolve } from "node:path";
|
|
14
|
+
import { withDirLock } from "@stim-cli/core";
|
|
15
|
+
import { maintenanceChildLogFile, maintenanceDir, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState } from "@stim-cli/core/state";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
234
17
|
//#region src/maintenance/run.ts
|
|
235
18
|
function writeState(state) {
|
|
236
19
|
mkdirSync(maintenanceDir(), { recursive: true });
|
|
@@ -247,14 +30,65 @@ function writeState(state) {
|
|
|
247
30
|
}
|
|
248
31
|
});
|
|
249
32
|
}
|
|
33
|
+
const RESERVE_BYTES = 1048576;
|
|
34
|
+
const reserveFile = () => join(maintenanceDir(), "disk-reserve");
|
|
35
|
+
function releaseReserve() {
|
|
36
|
+
try {
|
|
37
|
+
const bytes = statSync(reserveFile()).size;
|
|
38
|
+
rmSync(reserveFile());
|
|
39
|
+
return bytes > 0;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function keepReserve() {
|
|
45
|
+
try {
|
|
46
|
+
if (statSync(reserveFile()).size === RESERVE_BYTES) return;
|
|
47
|
+
} catch {}
|
|
48
|
+
try {
|
|
49
|
+
mkdirSync(maintenanceDir(), { recursive: true });
|
|
50
|
+
writeFileSync(reserveFile(), randomBytes(RESERVE_BYTES));
|
|
51
|
+
} catch {
|
|
52
|
+
try {
|
|
53
|
+
rmSync(reserveFile(), { force: true });
|
|
54
|
+
} catch {}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function claimPass(trigger) {
|
|
58
|
+
const take = () => {
|
|
59
|
+
const attempt = tryAcquireClaim({
|
|
60
|
+
root: maintenanceRunClaims(),
|
|
61
|
+
mode: "exclusive",
|
|
62
|
+
label: "maintenance",
|
|
63
|
+
details: { trigger }
|
|
64
|
+
});
|
|
65
|
+
if (attempt.pending) releaseClaim(attempt.pending);
|
|
66
|
+
return attempt.acquired;
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
return take();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (!(error instanceof Error && "code" in error && (error.code === "ENOSPC" || error.code === "EDQUOT")) || !releaseReserve()) throw error;
|
|
72
|
+
return take();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
250
75
|
const EXECUTION_ORDER = {
|
|
251
76
|
"would-unregister-cache": 0,
|
|
252
77
|
"would-remove-orphan": 0,
|
|
253
78
|
"would-clear-outputs": 1,
|
|
79
|
+
"would-delete-parked-device": 2,
|
|
80
|
+
"would-delete-temp-leftovers": 2,
|
|
254
81
|
"would-trim-cache": 2,
|
|
82
|
+
"would-clear-build-dirs": 3,
|
|
255
83
|
"would-empty-cache": 3,
|
|
256
|
-
"would-remove-worktree": 4
|
|
84
|
+
"would-remove-worktree": 4,
|
|
85
|
+
"would-stop-workspace": 5,
|
|
86
|
+
"would-delete-devices": 5,
|
|
87
|
+
"would-delete-dependencies": 6,
|
|
88
|
+
"would-stop-gradle-daemons": 7,
|
|
89
|
+
"would-delete-gradle-version": 8
|
|
257
90
|
};
|
|
91
|
+
const executionRank = (action) => (action.level ?? 1) * 10 + (EXECUTION_ORDER[action.kind] ?? 9);
|
|
258
92
|
function shrinkSizes(state, action, outcome) {
|
|
259
93
|
state.sizes = state.sizes.flatMap((size) => {
|
|
260
94
|
if (action.kind === "would-clear-outputs" && size.category === "workspace-outputs" && size.workspace === action.workspace) return [];
|
|
@@ -263,6 +97,7 @@ function shrinkSizes(state, action, outcome) {
|
|
|
263
97
|
bytes: Math.max(0, size.bytes - outcome.bytes)
|
|
264
98
|
}];
|
|
265
99
|
if (action.kind === "would-empty-cache" && size.dir === action.target) return [];
|
|
100
|
+
if (action.kind === "would-delete-devices" && outcome.status === "done" && size.category === "owned-devices" && size.workspace === action.workspace) return [];
|
|
266
101
|
return [size];
|
|
267
102
|
});
|
|
268
103
|
}
|
|
@@ -275,6 +110,14 @@ function describeDone(action) {
|
|
|
275
110
|
case "would-empty-cache": return `Emptied ${action.target}`;
|
|
276
111
|
case "would-remove-worktree": return `Removed the worktree ${action.target}`;
|
|
277
112
|
case "would-remove-orphan": return `Removed the orphaned workspace directory ${action.target}`;
|
|
113
|
+
case "would-delete-parked-device": return `Deleted the parked device ${action.target}`;
|
|
114
|
+
case "would-delete-temp-leftovers": return `Deleted the recognized leftovers in ${action.target}`;
|
|
115
|
+
case "would-delete-devices": return `Deleted the owned devices of ${name}`;
|
|
116
|
+
case "would-clear-build-dirs": return `Cleared the build directory ${action.target}`;
|
|
117
|
+
case "would-delete-dependencies": return `Deleted the installed dependencies ${action.target}`;
|
|
118
|
+
case "would-stop-gradle-daemons": return "Stopped idle Gradle and Kotlin daemons";
|
|
119
|
+
case "would-delete-gradle-version": return `Deleted the unpinned Gradle ${action.target} caches and distributions`;
|
|
120
|
+
case "would-stop-workspace": return `Stopped ${name} and deleted its owned devices`;
|
|
278
121
|
default: return `Unregistered the stale cache ${action.target}`;
|
|
279
122
|
}
|
|
280
123
|
}
|
|
@@ -285,14 +128,7 @@ async function runMaintenance(trigger) {
|
|
|
285
128
|
const startedAt = Date.now();
|
|
286
129
|
let claim;
|
|
287
130
|
try {
|
|
288
|
-
|
|
289
|
-
root: maintenanceRunClaims(),
|
|
290
|
-
mode: "exclusive",
|
|
291
|
-
label: "maintenance",
|
|
292
|
-
details: { trigger }
|
|
293
|
-
});
|
|
294
|
-
if (attempt.pending) releaseClaim(attempt.pending);
|
|
295
|
-
claim = attempt.acquired;
|
|
131
|
+
claim = claimPass(trigger);
|
|
296
132
|
} catch (error) {
|
|
297
133
|
crashLine(error);
|
|
298
134
|
return;
|
|
@@ -313,9 +149,29 @@ async function runMaintenance(trigger) {
|
|
|
313
149
|
};
|
|
314
150
|
const checks = due(state, settings, startedAt);
|
|
315
151
|
if (checks.length === 0) return;
|
|
316
|
-
|
|
152
|
+
let writeError = null;
|
|
153
|
+
const noteWriteError = (error) => {
|
|
154
|
+
writeError ??= error instanceof Error ? error.message : String(error);
|
|
155
|
+
};
|
|
156
|
+
const keepState = () => {
|
|
157
|
+
try {
|
|
158
|
+
writeState(state);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
noteWriteError(error);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
try {
|
|
164
|
+
logger = maintenanceLogger(settings, `p-${claim.claimId}`, trigger);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
noteWriteError(error);
|
|
167
|
+
}
|
|
317
168
|
const record = (event, level, msg, fields = {}) => {
|
|
318
|
-
|
|
169
|
+
let entry = null;
|
|
170
|
+
try {
|
|
171
|
+
entry = logger?.write(event, level, msg, fields) ?? null;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
noteWriteError(error);
|
|
174
|
+
}
|
|
319
175
|
if (entry && (event === "maintenance_action" || event === "maintenance_failure" || Array.isArray(fields.blocked) && fields.blocked.length > 0)) state.recent = [...state.recent, entry].slice(-20);
|
|
320
176
|
};
|
|
321
177
|
const failures = [];
|
|
@@ -332,17 +188,18 @@ async function runMaintenance(trigger) {
|
|
|
332
188
|
...state.deferredAt,
|
|
333
189
|
[check]: Date.now()
|
|
334
190
|
};
|
|
335
|
-
|
|
191
|
+
keepState();
|
|
336
192
|
continue;
|
|
337
193
|
}
|
|
338
194
|
state.lastAt[check] = Date.now();
|
|
339
195
|
ran.add(check);
|
|
340
196
|
delete state.deferredAt?.[check];
|
|
341
|
-
|
|
197
|
+
keepState();
|
|
342
198
|
try {
|
|
343
199
|
if (check === "worktree" || check === "sweep") continue;
|
|
344
200
|
if (check === "pressure") {
|
|
345
201
|
state.pressure = measurePressure(settings, state.pressure, state.lastAt[check]);
|
|
202
|
+
state.pressure.diskLevel = diskPressureLevel(lowestFree(state.pressure.disk), budget, settings);
|
|
346
203
|
const culprits = settings.memoryPressureLevel === "off" ? null : memoryCulpritsUnder(state.pressure.memory.level);
|
|
347
204
|
if (culprits) state.pressure.memory.culprits = culprits;
|
|
348
205
|
const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
|
|
@@ -361,14 +218,15 @@ async function runMaintenance(trigger) {
|
|
|
361
218
|
for (const culprit of state.pressure.memory.culprits ?? []) record("maintenance_check", "info", memoryCulpritAdvice([culprit]), { culprit });
|
|
362
219
|
} else {
|
|
363
220
|
measuredSizes = true;
|
|
364
|
-
|
|
221
|
+
const measureFailed = (target, workspace) => {
|
|
365
222
|
failures.push(`Could not measure ${target}`);
|
|
366
223
|
record("maintenance_failure", "error", `Could not measure ${target}`, {
|
|
367
224
|
target,
|
|
368
225
|
error: "du failed or timed out",
|
|
369
226
|
...workspace ? { workspace } : {}
|
|
370
227
|
});
|
|
371
|
-
}
|
|
228
|
+
};
|
|
229
|
+
state.sizes = [...await measureSizes(state.lastAt[check], measureFailed), ...deviceSweepIsScoped() ? [] : await measureOwnedDevices(state.lastAt[check], measureFailed)];
|
|
372
230
|
for (const size of state.sizes) record("maintenance_check", "debug", `${size.name}: ${formatBytes(size.bytes)}`, {
|
|
373
231
|
check: {
|
|
374
232
|
kind: `size:${size.category}`,
|
|
@@ -412,10 +270,11 @@ async function runMaintenance(trigger) {
|
|
|
412
270
|
settings,
|
|
413
271
|
budget,
|
|
414
272
|
protectedRoot: triggeringRoot(),
|
|
415
|
-
worktreeSweep: result.worktreeSweep
|
|
273
|
+
worktreeSweep: result.worktreeSweep,
|
|
274
|
+
pressureSweep: result.pressureSweep
|
|
416
275
|
};
|
|
417
276
|
const results = [];
|
|
418
|
-
const ordered = actions.toSorted((a, b) => (
|
|
277
|
+
const ordered = actions.toSorted((a, b) => executionRank(a) - executionRank(b));
|
|
419
278
|
for (const action of ordered) {
|
|
420
279
|
const began = Date.now();
|
|
421
280
|
let outcome;
|
|
@@ -424,6 +283,10 @@ async function runMaintenance(trigger) {
|
|
|
424
283
|
status: "kept",
|
|
425
284
|
bytes: 0,
|
|
426
285
|
detail: "free disk recovered before this action"
|
|
286
|
+
} : action.level !== void 0 && !levelStillShort(action, lowestFree(measureDisk()), budget, settings) ? {
|
|
287
|
+
status: "kept",
|
|
288
|
+
bytes: 0,
|
|
289
|
+
detail: `free disk is back above the level ${action.level} floor`
|
|
427
290
|
} : await executeAction(action, context);
|
|
428
291
|
} catch (error) {
|
|
429
292
|
outcome = {
|
|
@@ -474,8 +337,15 @@ async function runMaintenance(trigger) {
|
|
|
474
337
|
loggedSkips.add(skip.target);
|
|
475
338
|
record("maintenance_skip", "info", `Kept ${skip.target}: ${skip.reason}`, skip);
|
|
476
339
|
}
|
|
340
|
+
if (writeError) failures.push(`Could not write the maintenance state or log: ${writeError}`);
|
|
341
|
+
if (settings.mode !== "on" && state.pressure?.diskLevel === 3) failures.push(criticalLine(state.pressure.disk, budget, settings));
|
|
477
342
|
if (settings.mode === "on") {
|
|
478
343
|
const outcomes = await executePlan(result.actions);
|
|
344
|
+
if (state.pressure) {
|
|
345
|
+
state.pressure.disk = measureDisk();
|
|
346
|
+
state.pressure.diskLevel = diskPressureLevel(lowestFree(state.pressure.disk), budget, settings);
|
|
347
|
+
if (state.pressure.diskLevel === 3) failures.push(criticalLine(state.pressure.disk, budget, settings));
|
|
348
|
+
}
|
|
479
349
|
const blockedNow = [
|
|
480
350
|
...result.blocked,
|
|
481
351
|
...failures,
|
|
@@ -498,7 +368,7 @@ async function runMaintenance(trigger) {
|
|
|
498
368
|
blocked: blockedNow
|
|
499
369
|
};
|
|
500
370
|
const blockedChanged = !sameSet(new Set((previousBlocked ?? []).map(stableText)), new Set(state.lastPass.blocked.map(stableText)));
|
|
501
|
-
if (done.length || measuredSizes || blockedChanged) record("maintenance_pass", state.lastPass.blocked.length ? "warn" : "info", `Pass: ${done.length} actions, ${formatBytes(freedBytes)} freed${state.lastPass.blocked.length ? `; ${state.lastPass.blocked.join("; ")}` : ""}`, { ...state.lastPass });
|
|
371
|
+
if (done.length || measuredSizes || blockedChanged || (state.pressure?.diskLevel ?? 0) > 0) record("maintenance_pass", state.lastPass.blocked.length ? "warn" : "info", `Pass: ${done.length} actions, ${formatBytes(freedBytes)} freed${state.lastPass.blocked.length ? `; ${state.lastPass.blocked.join("; ")}` : ""}`, { ...state.lastPass });
|
|
502
372
|
} else {
|
|
503
373
|
const blocked = [...result.blocked, ...failures];
|
|
504
374
|
const planned = [...result.actions, ...retained];
|
|
@@ -541,9 +411,14 @@ async function runMaintenance(trigger) {
|
|
|
541
411
|
crashLine(error);
|
|
542
412
|
} finally {
|
|
543
413
|
logger?.close();
|
|
414
|
+
keepReserve();
|
|
544
415
|
releaseClaim(claim);
|
|
545
416
|
}
|
|
546
417
|
}
|
|
418
|
+
function criticalLine(disk, budget, settings) {
|
|
419
|
+
const floor = levelFloors(budget, settings)[3];
|
|
420
|
+
return `disk pressure level 3: ${disk.filter((volume) => volume.freeMb < floor).map((volume) => `${(volume.freeMb / 1024).toFixed(1)}G free on ${volume.volume}`).join(", ")} after this pass, under the ${(floor / 1024).toFixed(1)}G critical floor; builds refuse below budget.hardFloorDiskGb`;
|
|
421
|
+
}
|
|
547
422
|
function crashLine(error) {
|
|
548
423
|
try {
|
|
549
424
|
mkdirSync(maintenanceDir(), { recursive: true });
|