stim 1.20.2 → 1.21.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 +88 -8
- package/dist/acquire-artifact-CD4lbiWE.mjs +153 -0
- package/dist/act-DHAw2A2S.mjs +2667 -0
- package/dist/activity-BzVfHSrY.mjs +1376 -0
- package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-zh1vhbLp.mjs} +21 -65
- package/dist/{android-HqP1_vB_.mjs → android-BEJ8Jpl7.mjs} +2 -2
- package/dist/{android-DCKZrNvV.mjs → android-BLgbNqox.mjs} +128 -78
- package/dist/{android-Dlzxshgp.mjs → android-CV_GCELZ.mjs} +5 -5
- package/dist/{android-Mz_Inn3w.mjs → android-DUYkNF4u.mjs} +184 -102
- package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-Ct5b1xCK.mjs} +7 -6
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/android-project-BCAAmMwz.mjs +12 -0
- package/dist/api.d.mts +740 -8
- package/dist/api.mjs +585 -1
- package/dist/{artifact-HSwkIWEQ.mjs → artifact-B8T3S5gi.mjs} +223 -201
- package/dist/{artifact-D3czlUvT.mjs → artifact-DAuZ-FNU.mjs} +158 -148
- package/dist/{browser-web-CA-F1GQo.mjs → browser-web-QQzVjz3O.mjs} +26 -24
- package/dist/budget-Bs6SxxzO.mjs +9154 -0
- package/dist/{build-DYDbfkk5.mjs → build-CoPzQRNw.mjs} +144 -96
- package/dist/build-cache-DmyR9Zzc.mjs +602 -0
- package/dist/build-plan-CaFskB7_.mjs +188 -0
- package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DkkqguoK.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-zdKiYQ3E.mjs → ccache-BJRZ9pG3.mjs} +10 -9
- package/dist/{cdp-Dq_ypAlJ.mjs → cdp-CWmIUMbw.mjs} +18 -5
- package/dist/{chrome-BnzZMqsR.mjs → chrome-B6tfCta1.mjs} +7 -4
- package/dist/{cli-CLP3diBm.mjs → cli-0DYf8QhQ.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/client-B7QVOlCr.d.mts +253 -0
- package/dist/client-UXD70ZbM.mjs +1406 -0
- package/dist/collector-run.d.mts +4 -40
- package/dist/collector-run.mjs +9 -8
- package/dist/{command-output-BTy8hZ0F.mjs → command-output-B1UrjZHL.mjs} +1 -1
- package/dist/config-CYcBF478.mjs +949 -0
- package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-CqeBlrEn.mjs} +3 -3
- package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-BbKQW83h.mjs} +20 -5
- package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-DFRyG1_o.mjs} +1 -1
- package/dist/{dev-client-DAWVIGBu.mjs → dev-client-UOeESKm6.mjs} +2 -2
- package/dist/device-DCxH7_By.mjs +1068 -0
- package/dist/{device-BECOiufl.mjs → device-ExJq8Ei7.mjs} +35 -35
- package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-CMlqEcvw.mjs} +43 -13
- package/dist/device-host-worker.mjs +65 -61
- package/dist/{device-ios-COSi6oS1.mjs → device-ios-DRUeKaFV.mjs} +48 -45
- package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-C8raGFoP.mjs} +14 -26
- package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-DMRpVX9a.mjs} +5 -5
- package/dist/doctor-BLHCYxzi.mjs +2 -0
- package/dist/{doctor-kfMBnUw6.mjs → doctor-DTvaDOda.mjs} +281 -317
- package/dist/{doctor-CB8oZKCk.mjs → doctor-Dhqebm0q.mjs} +183 -91
- package/dist/doctor-fingerprint.mjs +19 -0
- package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-Cv1F10Kj.mjs} +40 -21
- package/dist/{eas-build-JyfqyHfC.mjs → eas-build-BomfRnFT.mjs} +53 -20
- package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-DJwZpy0c.mjs} +26 -208
- package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-op6A54yi.mjs} +229 -11
- package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-Bf0rZvG9.mjs} +172 -82
- package/dist/exec-H20xSg2T.d.mts +65 -0
- package/dist/exec-_UbtCQcG.mjs +750 -0
- package/dist/gc-C-WwL0yi.mjs +3 -0
- package/dist/{gc-qWOMdnER.mjs → gc-_-dCXdyL.mjs} +584 -796
- package/dist/git-C3iTsJaZ.mjs +73 -0
- package/dist/{guide-G9cAbVAc.mjs → guide-Yqwt2bd6.mjs} +941 -269
- package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-Bw-honsd.mjs} +8 -6
- package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DB_gBPfY.mjs} +34 -19
- package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CUvOf4Vr.mjs} +1 -1
- package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-DL_P5AdN.mjs} +77 -43
- package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-QI141yKk.mjs} +21 -17
- package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-Ksyjgzq-.mjs} +30 -21
- package/dist/idle-BVeRGroT.d.mts +24 -0
- package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DaKmZi0z.mjs} +11 -10
- package/dist/{ios-BwVCF7oA.mjs → ios-CQ68hG9s.mjs} +8 -8
- package/dist/{ios-RkW4pnQf.mjs → ios-CpByZy12.mjs} +140 -80
- package/dist/{ios-device-B5veSDDQ.mjs → ios-device-CXGP1bsD.mjs} +1 -1
- package/dist/{ios-device-D7pi2Sca.mjs → ios-device-CwFMehUS.mjs} +51 -26
- package/dist/{ios-project-K9hY_Jab.mjs → ios-project-WuwwBdvW.mjs} +13 -13
- package/dist/{ios-nOLJGVdy.mjs → ios-qNJt4dFm.mjs} +1 -1
- package/dist/ios-signing-DTTIChGs.mjs +489 -0
- package/dist/{ios-state-CBLe1xYw.mjs → ios-state-DvFX-K_l.mjs} +1 -1
- package/dist/{ios-Ce7bc7br.mjs → ios-ubFsBzwq.mjs} +129 -86
- package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Cc1dttps.mjs} +53 -26
- package/dist/{launch-F4sOqAhB.mjs → launch-CD1yVc7U.mjs} +91 -90
- package/dist/{launch-C3qJ6Agb.mjs → launch-Zq2mOSDy.mjs} +82 -541
- package/dist/logs-BS00Anxf.mjs +352 -0
- package/dist/logs-CMm05HxN.mjs +255 -0
- package/dist/{macos-D7uDvO-z.mjs → macos-B65--pPd.mjs} +1 -1
- package/dist/{macos-Ch5VJmcS.mjs → macos-C-0qJ6zq.mjs} +225 -212
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +122 -247
- package/dist/{metro-DnCEjCxs.mjs → metro-DEXpIhHC.mjs} +67 -12
- package/dist/{metro-gateway-CX9Xlkq2.mjs → metro-gateway-BMJNlj3E.mjs} +20 -12
- package/dist/{named-ports-4WopRPg-.mjs → named-ports-BWTzt6mu.mjs} +8 -63
- package/dist/native-android-JACyjTZs.mjs +844 -0
- package/dist/{native-gradle-inputs-BsLRrl7u.mjs → native-gradle-inputs-Bep9JcSF.mjs} +128 -140
- package/dist/native-inputs-TRTTTRxt.mjs +91 -0
- package/dist/native-run-DY_RLx3C.mjs +277 -0
- package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-Dg1Q7tfF.mjs} +9 -8
- package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-CB2iQeWq.mjs} +27 -18
- package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-CXX39F7o.mjs} +96 -47
- package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
- package/dist/offload-worker.d.mts +1 -46
- package/dist/offload-worker.mjs +197 -66
- package/dist/{ownership-DCtw_2IA.mjs → ownership-DEmM5vhh.mjs} +3 -3
- package/dist/{page-DRHy329N.mjs → page-CPaHeYqj.mjs} +7 -4
- package/dist/paths-BsJMoPP2.mjs +12 -0
- package/dist/paths-DQtTgsBf.mjs +42 -0
- package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BqGbTa61.mjs} +5 -5
- package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-Bwj-IjY1.mjs} +6 -6
- package/dist/{ports-DdSUicVo.mjs → ports-D-MmCTdv.mjs} +3 -3
- package/dist/prebuild-uD_ipCxF.mjs +449 -0
- package/dist/{project-_phNIJfs.mjs → project-BZNjmW_8.mjs} +65 -37
- package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-Lfetn8Kr.mjs} +2 -2
- package/dist/pull-request-zjCSAryH.d.mts +120 -0
- package/dist/pull-requests.d.mts +1 -119
- package/dist/pull-requests.mjs +1 -1
- package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-DuzH0cn3.mjs} +74 -48
- package/dist/{gradle-DSrXb6lG.mjs → react-native-build-rhk4smwQ.mjs} +292 -15
- package/dist/react-native-doctor-CQpuIMso.mjs +234 -0
- package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-Bhq1rJeV.mjs} +46 -28
- package/dist/{recordings-D0d5aQt0.mjs → recordings-DYteQSu4.mjs} +12 -9
- package/dist/{reload-C8JhxjSh.mjs → reload-CmTRFJaX.mjs} +93 -47
- package/dist/reload-DzjSl5P_.mjs +2 -0
- package/dist/{remote-BiR6aYjy.mjs → remote-ByYkXdGD.mjs} +15 -10
- package/dist/result-DNiS-tTP.mjs +434 -0
- package/dist/{run-BtPgpKks.mjs → run-D23HmJMs.mjs} +4 -5
- package/dist/selection-CSl9i5qU.mjs +619 -0
- package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CxTrvDg8.mjs} +3 -4
- package/dist/{server-command-CTtCkmcQ.mjs → server-command-CtzloH3v.mjs} +14 -7
- package/dist/server-expo-C-90EhcG.mjs +2 -0
- package/dist/{server-expo-DsguMGUF.mjs → server-expo-DT_F_uVI.mjs} +50 -9
- package/dist/{settings-B717odTD.mjs → settings-CsJDEXgK.mjs} +234 -24
- package/dist/{settings-vk3mJGSm.d.mts → settings-DkdmlelE.d.mts} +6 -4
- package/dist/settings-T1gtc3bf.mjs +114 -0
- package/dist/settings-write-HyVZ8eQ8.mjs +359 -0
- package/dist/settings.schema.json +163 -16
- package/dist/{simslim-CCr3rE-A.mjs → simslim-Cgk17SXV.mjs} +14 -12
- package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-DF8VfT64.mjs} +15 -20
- package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
- package/dist/stage-BIS0ydsV.mjs +183 -0
- package/dist/{start-BWqzODpb.mjs → start-7lpH7hmN.mjs} +63 -44
- package/dist/{start-TXeMmmO2.mjs → start-RChynRDp.mjs} +1 -1
- package/dist/{state-D1Icyjlu.mjs → state-C4ZtUisW.mjs} +40 -13
- package/dist/{state-CG_OFoaA.mjs → state-XMziexv2.mjs} +3 -2
- package/dist/{stats-BoY5sEPU.mjs → stats-53T7OTb9.mjs} +7 -13
- package/dist/stats-report-BFfMpWWF.mjs +16 -0
- package/dist/{status-WgFbkRzj.mjs → status-BL7jVyAB.mjs} +535 -447
- package/dist/status-CSi6tlRq.mjs +2 -0
- package/dist/{status-BTA7kKiQ.mjs → status-DqEUSSxs.mjs} +6 -4
- package/dist/{status-watch-C23ILtf9.mjs → status-watch-GDCfqpTE.mjs} +187 -22
- package/dist/status-worker.d.mts +1 -0
- package/dist/status-worker.mjs +19 -0
- package/dist/stim-desktop-C12we7lz.mjs +112 -0
- package/dist/{stop-DR6VoDIk.mjs → stop-Bk_1qiV6.mjs} +2 -2
- package/dist/{stop-BNmBMi1F.mjs → stop-CPzlM1L-.mjs} +138 -98
- package/dist/{stop-DPEhunlw.mjs → stop-D7h6jAXQ.mjs} +11 -10
- package/dist/supervisor-run.d.mts +8 -17
- package/dist/supervisor-run.mjs +63 -27
- package/dist/{support-DMTqj3Hm.mjs → support-67vraa1Q.mjs} +18 -11
- package/dist/{support-CwjbFs9H.mjs → support-Dlu37g6H.mjs} +12 -12
- package/dist/{swiftpm-macos-DRNVJWlb.mjs → swiftpm-macos-p8WZbxKU.mjs} +35 -24
- package/dist/toolchain-DhKwp9iI.mjs +2 -0
- package/dist/toolchain-Hp9sCpK4.mjs +873 -0
- package/dist/{trigger-CigAYjeL.mjs → trigger-BAahxUPq.mjs} +20 -5
- package/dist/trigger-Bf3uDcpv.mjs +2 -0
- package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-BHX5r0Ei.mjs} +250 -156
- package/dist/{web-BDBMxDpx.mjs → web-CJmIj6AI.mjs} +18 -13
- package/dist/web-DknQETPs.mjs +2 -0
- package/dist/web-run.mjs +11 -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-process-lock-1_1OoVW5.mjs +57 -0
- package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-Cjuigeeu.mjs} +62 -58
- package/dist/{workspaces-C36s2jb9.mjs → workspaces-BccMFmGQ.mjs} +1188 -1079
- package/dist/worktree-CK2MpJW5.mjs +2 -0
- package/dist/{worktree-CgvJYJ-Q.mjs → worktree-DQ6Zi2Mv.mjs} +304 -53
- package/dist/xcode-Zlx3qjEs.mjs +896 -0
- package/package.json +7 -5
- 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/miss-reason-mKzZ4VvN.mjs +0 -238
- package/dist/native-android-D5qc3-_v.mjs +0 -226
- 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/spawn-claims-DVS5RkMS.mjs +0 -72
- package/dist/stage-KNTQopqv.mjs +0 -157
- package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
- 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-CYcBF478.mjs";
|
|
2
|
+
import { Tt as deviceSweepIsScoped, u as resolveBudget } from "./budget-Bs6SxxzO.mjs";
|
|
3
|
+
import { I as memoryCulpritAdvice, N as memoryCulpritsUnder } from "./ios-CpByZy12.mjs";
|
|
4
|
+
import { h as maintenanceLogger } from "./client-UXD70ZbM.mjs";
|
|
8
5
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
6
|
+
import { A as lowestFree, C as measurePressure, D as diskPressureLevel, E as sizeScanDeferred, O as levelFloors, S as measureDisk, T as measureSizes, k as levelStillShort } from "./worktree-DQ6Zi2Mv.mjs";
|
|
7
|
+
import { i as plannedMaintenance, m as measureOwnedDevices, n as diskRecovered, o as triggeringRoot, r as executeAction } from "./act-DHAw2A2S.mjs";
|
|
8
|
+
import { t as relaunchWithLogFile } from "./detached-entry-DFRyG1_o.mjs";
|
|
9
9
|
import { r as due, t as capChildLog } from "./attempt-DW-mQqM7.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import { appendFileSync,
|
|
12
|
-
import { basename, join, resolve
|
|
13
|
-
import {
|
|
10
|
+
import { randomBytes } from "node:crypto";
|
|
11
|
+
import { appendFileSync, mkdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { basename, join, resolve } from "node:path";
|
|
13
|
+
import { withDirLock } from "@stim-cli/core";
|
|
14
|
+
import { maintenanceChildLogFile, maintenanceDir, maintenanceRunClaims, maintenanceStateFile, readMaintenanceState } from "@stim-cli/core/state";
|
|
14
15
|
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { LOG_ROTATE_BYTES, buildCacheRoot, metroCacheRoot, rotatedLogPath, withDirLock } from "@stim-cli/core";
|
|
16
16
|
import { releaseClaim, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
17
|
-
//#region src/maintenance/act.ts
|
|
18
|
-
const kept = (detail) => ({
|
|
19
|
-
status: "kept",
|
|
20
|
-
bytes: 0,
|
|
21
|
-
detail
|
|
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
|
|
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 });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as readWorkspaceState } from "./workspace-state-
|
|
1
|
+
import { p as process_identity_exports, t as getExecutor } from "./exec-_UbtCQcG.mjs";
|
|
2
|
+
import { F as isOnMountedVolume, I as listMountedVolumes, _ as loadConfig, n as allMetroPorts, r as claimMetroPort, x as releaseMetroPort } from "./config-CYcBF478.mjs";
|
|
3
|
+
import { r as readWorkspaceState } from "./workspace-state-Cjuigeeu.mjs";
|
|
4
4
|
import { sep } from "path";
|
|
5
5
|
import { existsSync, readlinkSync, realpathSync } from "fs";
|
|
6
6
|
import { readFile } from "node:fs/promises";
|
|
@@ -192,25 +192,34 @@ function createPortProbe() {
|
|
|
192
192
|
throw new PortInspectionError(`Cannot tell whether TCP port ${port} is free: the TCP listener table failed (${listening.message.replace(/\s+/g, " ").trim()}), lsof could not list listeners, and a loopback connect failed.`);
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
|
-
function isMetroRunning(port) {
|
|
195
|
+
function isMetroRunning(port, signal) {
|
|
196
196
|
return new Promise((resolve) => {
|
|
197
197
|
const req = request({
|
|
198
198
|
hostname: "localhost",
|
|
199
199
|
port,
|
|
200
200
|
path: "/status",
|
|
201
|
-
timeout: 2e3
|
|
201
|
+
timeout: 2e3,
|
|
202
|
+
signal
|
|
202
203
|
}, (res) => {
|
|
203
204
|
let data = "";
|
|
205
|
+
let bytes = 0;
|
|
204
206
|
res.on("data", (chunk) => {
|
|
207
|
+
bytes += Buffer.byteLength(chunk);
|
|
208
|
+
if (bytes > 65536) return finish(false);
|
|
205
209
|
data += chunk;
|
|
206
210
|
});
|
|
207
|
-
res.on("end", () =>
|
|
211
|
+
res.on("end", () => finish(data.includes("packager-status:running")));
|
|
212
|
+
res.on("error", () => finish(false));
|
|
213
|
+
res.on("aborted", () => finish(false));
|
|
208
214
|
});
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
const deadline = setTimeout(() => finish(false), 2e3);
|
|
216
|
+
const finish = (running) => {
|
|
217
|
+
clearTimeout(deadline);
|
|
211
218
|
req.destroy();
|
|
212
|
-
resolve(
|
|
213
|
-
}
|
|
219
|
+
resolve(running);
|
|
220
|
+
};
|
|
221
|
+
req.on("error", () => finish(false));
|
|
222
|
+
req.on("timeout", () => finish(false));
|
|
214
223
|
req.end();
|
|
215
224
|
});
|
|
216
225
|
}
|
|
@@ -305,6 +314,23 @@ function listeningPids(port, platform = process.platform) {
|
|
|
305
314
|
if (pids.length > 0 || platform !== "win32") return pids;
|
|
306
315
|
return parseNetstatPids(getExecutor().runQuiet("netstat -ano", { timeoutMs: 1e4 }), port);
|
|
307
316
|
}
|
|
317
|
+
/** Reads listener pids without blocking on lsof or netstat. */
|
|
318
|
+
async function listeningPidsAsync(port, platform = process.platform) {
|
|
319
|
+
const pids = parseLsofPids(await getExecutor().runFileQuietAsync("lsof", [
|
|
320
|
+
"-nP",
|
|
321
|
+
`-iTCP:${port}`,
|
|
322
|
+
"-sTCP:LISTEN",
|
|
323
|
+
"-t"
|
|
324
|
+
], {
|
|
325
|
+
timeoutMs: 1e4,
|
|
326
|
+
killSignal: "SIGKILL"
|
|
327
|
+
}));
|
|
328
|
+
if (pids.length > 0 || platform !== "win32") return pids;
|
|
329
|
+
return parseNetstatPids(await getExecutor().runFileQuietAsync("netstat", ["-ano"], {
|
|
330
|
+
timeoutMs: 1e4,
|
|
331
|
+
killSignal: "SIGKILL"
|
|
332
|
+
}), port);
|
|
333
|
+
}
|
|
308
334
|
function parseLsofCwd(out) {
|
|
309
335
|
if (!out) return null;
|
|
310
336
|
const lines = String(out).split("\n");
|
|
@@ -314,7 +340,10 @@ function parseLsofCwd(out) {
|
|
|
314
340
|
return nLine ? nLine.slice(1) : null;
|
|
315
341
|
}
|
|
316
342
|
function lsofOutput(args) {
|
|
317
|
-
return getExecutor().runFileAsync("lsof", args, {
|
|
343
|
+
return getExecutor().runFileAsync("lsof", args, {
|
|
344
|
+
timeoutMs: 1e4,
|
|
345
|
+
killSignal: "SIGKILL"
|
|
346
|
+
}).catch((error) => typeof error?.stdout === "string" ? error.stdout : null);
|
|
318
347
|
}
|
|
319
348
|
/**
|
|
320
349
|
* `listeningPids` for several ports with one lsof call. A port lsof could not be asked about is
|
|
@@ -470,5 +499,31 @@ function killMetroTree(leader, processToken) {
|
|
|
470
499
|
return false;
|
|
471
500
|
}
|
|
472
501
|
}
|
|
502
|
+
/** Signals a process tree without blocking on Windows taskkill. */
|
|
503
|
+
async function signalProcessTreeAsync(pid, signal = "SIGTERM", options = {}) {
|
|
504
|
+
if (!Number.isSafeInteger(pid) || pid <= 1) throw new Error(`Refusing to signal pid ${pid}.`);
|
|
505
|
+
if ((options.platform ?? process.platform) !== "win32") return signalProcessTree(pid, signal, options);
|
|
506
|
+
return await getExecutor().runFileQuietAsync("taskkill", [
|
|
507
|
+
"/PID",
|
|
508
|
+
String(pid),
|
|
509
|
+
"/T",
|
|
510
|
+
"/F"
|
|
511
|
+
], {
|
|
512
|
+
timeoutMs: 3e4,
|
|
513
|
+
killSignal: "SIGKILL"
|
|
514
|
+
}) !== null;
|
|
515
|
+
}
|
|
516
|
+
/** Stops the verified Metro process tree without blocking on Windows taskkill. */
|
|
517
|
+
async function killMetroTreeAsync(leader, processToken) {
|
|
518
|
+
if (!leader || leader === process.pid || (0, process_identity_exports.inspectProcessIdentity)({
|
|
519
|
+
pid: leader,
|
|
520
|
+
processToken
|
|
521
|
+
}) !== "same") return false;
|
|
522
|
+
try {
|
|
523
|
+
return await signalProcessTreeAsync(leader, "SIGTERM", { group: true });
|
|
524
|
+
} catch {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
473
528
|
//#endregion
|
|
474
|
-
export {
|
|
529
|
+
export { reserveMetroPort as _, listeningPids as a, parseNetstatPids as c, processCwds as d, resolveProjectMetro as f, isMetroRunning as g, createPortProbe as h, killMetroTreeAsync as i, pidExists as l, signalProcessTreeAsync as m, isInsideProject as n, listeningPidsAsync as o, signalProcessTree as p, killMetroTree as r, listeningPidsByPort as s, NOT_OURS_FOREIGN_CWD as t, processCwd as u, PORT_INSPECTION_REMEDY as v, PortInspectionError as y };
|