stim 1.27.0 → 1.29.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-BKN2Yuhg.mjs → acquire-artifact-C2DKfenN.mjs} +1 -1
- package/dist/{act-ROviTF_t.mjs → act-CrTcskiE.mjs} +502 -34
- package/dist/{activity-Cd-ysFes.mjs → activity-BR5oHSO5.mjs} +6 -5
- package/dist/{agent-device-usage-output-C5nCKWp9.mjs → agent-device-usage-output-W0x4SoC7.mjs} +4 -4
- package/dist/{android-DriNoAVy.mjs → android-BHKgeOuq.mjs} +5 -5
- package/dist/{android--HBgpvpW.mjs → android-BPmCmyAy.mjs} +5 -5
- package/dist/{android-Deb9X3_Y.mjs → android-CLU_MMnb.mjs} +1 -1
- package/dist/{android-cas-D5e6ecUg.mjs → android-cas-BH6K12__.mjs} +4 -4
- package/dist/{android-Cd6w7_qw.mjs → android-l616dRP1.mjs} +42 -39
- package/dist/{android-project-DUGMbq28.d.mts → android-project-CCEQyYJK.d.mts} +6 -2
- package/dist/api.d.mts +8 -5
- package/dist/api.mjs +27 -27
- package/dist/{apk-signed-tail-BHQHx3Rm.mjs → apk-signed-tail-B-wKoF_8.mjs} +2 -2
- package/dist/{artifact-0AGJYB9O.mjs → artifact-DHuFYfhD.mjs} +12 -12
- package/dist/{artifact-faemIZv5.mjs → artifact-Dm9ScLrh.mjs} +12 -12
- package/dist/{auto-placement-z-H5pJza.mjs → auto-placement-C8sJsyMN.mjs} +8 -8
- package/dist/{browser-web-slD8AvLp.mjs → browser-web-_tQTbQUs.mjs} +12 -12
- package/dist/{build-hS0QyFlQ.mjs → build-DtCU9Kim.mjs} +23 -23
- package/dist/{build-cache-gBJ-WKzA.mjs → build-cache-BGwTsIEa.mjs} +4 -4
- package/dist/{build-plan-CBqYbzYM.mjs → build-plan-CWyjMPKo.mjs} +6 -6
- package/dist/{cache-manifest-DEjqGGat.mjs → cache-manifest-evF_zJ9U.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-BWTze1Ls.mjs → ccache-DsDkdP72.mjs} +19 -18
- package/dist/{cli-ftXDLto1.mjs → cli-3fjOg-Oc.mjs} +19 -19
- package/dist/cli.mjs +1 -1
- package/dist/{client-xsdxrhWA.mjs → client-BTUH8TF1.mjs} +41 -8
- package/dist/collector-run.mjs +5 -5
- package/dist/{command-output-Dj-WT4BP.mjs → command-output-DjCsmzLZ.mjs} +1 -1
- package/dist/{config-Cn94Jc0g.mjs → config-AbUjIBOQ.mjs} +121 -19
- package/dist/{dependencies-BGokZ-Ng.mjs → dependencies-CHNqX6Pr.mjs} +38 -38
- package/dist/{dependency-state-C3OtgG94.mjs → dependency-state-CPKAKCZ8.mjs} +1 -1
- package/dist/{dev-client-BMca82xo.mjs → dev-client-CROrxj1x.mjs} +2 -2
- package/dist/{device-tM41-TUq.mjs → device-Bmm5qjM-.mjs} +14 -14
- package/dist/device-BvpasThQ.mjs +297 -0
- package/dist/{device-capacity-6LP7QsaA.mjs → device-capacity-B2ChA-bz.mjs} +86 -18
- package/dist/device-host-worker.mjs +15 -13
- package/dist/{device-ios-534c14fz.mjs → device-ios-CYzivd31.mjs} +9 -9
- package/dist/{device-lease-run-DwsGfjUN.mjs → device-lease-run-qRq_2W2V.mjs} +4 -4
- package/dist/{device-pool-BnQqvs6o.mjs → device-pool-CrmiE4_x.mjs} +3 -3
- package/dist/{device-BJm0irrq.mjs → device-provision-CK2XiEp1.mjs} +11 -302
- package/dist/{doctor-Dbx1ZpD2.mjs → doctor-BO_kaFWX.mjs} +1 -1
- package/dist/{doctor-DyqE9n1J.mjs → doctor-Cp4-HN1f.mjs} +20 -15
- package/dist/{doctor-F-3VUUyN.mjs → doctor-Dr3C1iXV.mjs} +19 -19
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-watchman-CxDbyrrt.mjs → doctor-watchman-CJr2aXXv.mjs} +4 -4
- package/dist/{eas-build-CjNSWmjo.mjs → eas-build-D-9HmGZS.mjs} +2 -2
- package/dist/{eas-fallback-9fqb46kW.mjs → eas-fallback-Cemt2GVL.mjs} +4 -4
- package/dist/{eas-session-ledger-DrP4OuuM.mjs → eas-session-ledger-B0KLZx5m.mjs} +36 -7
- package/dist/{error-diagnostics-snej9k4j.mjs → error-diagnostics-CV_1RoEH.mjs} +8 -8
- package/dist/{gc-CGZ1Yg88.mjs → gc-CKHqL4aS.mjs} +81 -18
- package/dist/{gc-BRwAY3qT.mjs → gc-DjXwQXHK.mjs} +2 -2
- package/dist/{guide-_rfEh_zM.mjs → guide-CeRlWVsS.mjs} +230 -62
- package/dist/{hosted-android-BMKzUNnY.mjs → hosted-android-DI_vvv7U.mjs} +5 -6
- package/dist/{hosted-client-D7Pk_Oo1.mjs → hosted-client-CgoxdU9j.mjs} +44 -17
- package/dist/{hosted-logs-B1gqQuva.mjs → hosted-logs-C-4INmkn.mjs} +17 -8
- package/dist/{hosted-logs-sync-Dg3qrZmV.mjs → hosted-logs-sync-Bf5s02fi.mjs} +5 -5
- package/dist/{hosted-macos-B9w4H8hc.mjs → hosted-macos-Doh85YUM.mjs} +5 -5
- package/dist/{hosted-native-CdgaiuyP.mjs → hosted-native-DvZENAL-.mjs} +11 -8
- package/dist/{idle-shutdown-Cbvo5KEh.mjs → idle-shutdown-BM37gMfU.mjs} +7 -7
- package/dist/{ios-Bk4mWbtS.mjs → ios-CNDH6fNF.mjs} +8 -8
- package/dist/{ios-E26qSpkb.mjs → ios-CoMCWfub.mjs} +4 -4
- package/dist/{ios-B5HlVMhQ.mjs → ios-UM_dManb.mjs} +31 -29
- package/dist/{ios-device-C_QkIf1Z.mjs → ios-device-L1-pota_.mjs} +1 -1
- package/dist/{ios-project-D8Jcy_br.mjs → ios-project-DJYptOCh.mjs} +7 -7
- package/dist/{ios-state-BZ03NFgF.mjs → ios-state-Ce_dystM.mjs} +1 -1
- package/dist/{js-swap-Dg2a945i.mjs → js-swap-BthE4kZC.mjs} +4 -4
- package/dist/{launch-CRyBeNsA.mjs → launch-D798aSm8.mjs} +19 -19
- package/dist/{lightened-BCsdAGj_.mjs → lightened-vSxkstg6.mjs} +4 -4
- package/dist/{logs-aJQb-RDg.mjs → logs-BND8MiBq.mjs} +9 -8
- package/dist/{logs-CC_-ZzEE.mjs → logs-CilPftm3.mjs} +5 -5
- package/dist/{macos-BGmTpnv9.mjs → macos-BOQrKYeJ.mjs} +1 -1
- package/dist/{macos-DlCBhMw5.mjs → macos-CxUi9xcE.mjs} +20 -20
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +13 -9
- package/dist/{metro-CvyD-xwe.mjs → metro-BMQHczcf.mjs} +2 -2
- package/dist/{metro-gateway-BnHdqMO_.mjs → metro-request-BtF7ox53.mjs} +25 -46
- package/dist/{named-ports-BCyMWA6b.mjs → named-ports-DcktE2Pw.mjs} +2 -2
- package/dist/{native-android-DlpxCyOP.mjs → native-android-BkhrCjdX.mjs} +16 -16
- package/dist/{native-gradle-artifact-inputs-C13qT7R_.mjs → native-gradle-artifact-inputs-Cw4P6Gyr.mjs} +3 -3
- package/dist/{native-runtime-DqaIBO5w.mjs → native-runtime-DyH2gkXK.mjs} +6 -6
- package/dist/{native-xcode-inputs-B1W8SrxB.mjs → native-xcode-inputs-DV8jr3kJ.mjs} +2 -2
- package/dist/{native-xcode-ios-QPP0Rm68.mjs → native-xcode-ios-DdpPG2iT.mjs} +15 -15
- package/dist/{ndjson-Dy2W4vRa.mjs → ndjson-CrjIsGzw.mjs} +2 -2
- package/dist/offload-worker.d.mts +1 -1
- package/dist/offload-worker.mjs +22 -22
- package/dist/{ownership-Bx-0cku-.mjs → ownership-Dtz9G5Gl.mjs} +2 -2
- package/dist/{phone-reverses-C9yAaKEv.mjs → phone-reverses-DZRad8HT.mjs} +4 -4
- package/dist/{placement-log-BXUbiZM6.mjs → placement-log-CoN6xrjY.mjs} +1 -1
- package/dist/{plan-placement-UxnQjv5Z.mjs → plan-placement-7sHuqR-r.mjs} +6 -6
- package/dist/{ports-uUrghqWN.mjs → ports-VQSAPZhl.mjs} +3 -3
- package/dist/{prebuild-BDpToDgR.mjs → prebuild-Bqp0LFGN.mjs} +9 -9
- package/dist/{project-DYj-HVx6.mjs → project-D1n0K4yg.mjs} +15 -15
- package/dist/{react-native-android-DDBccgJw.mjs → react-native-android-FQ-yX3Mv.mjs} +22 -22
- package/dist/{react-native-build-DaK2IFyP.mjs → react-native-build-D58bIqV9.mjs} +7 -7
- package/dist/{react-native-doctor-B-Mw6DcR.mjs → react-native-doctor-AkUH2aca.mjs} +5 -5
- package/dist/{react-native-ios-DjYwUF9U.mjs → react-native-ios-Dmsv8j7T.mjs} +14 -14
- package/dist/{recordings-C20iUZfp.mjs → recordings-CHMaF73C.mjs} +1 -1
- package/dist/{reload-fUdkH2_p.mjs → reload-BV0nD-k9.mjs} +14 -14
- package/dist/{reload-DJBeF_rC.mjs → reload-CDKEzzaf.mjs} +1 -1
- package/dist/{remote-y6n99WMW.mjs → remote-C8xyslUa.mjs} +9 -9
- package/dist/{result-CTqBw2Te.mjs → result-9fqcJ90W.mjs} +16 -16
- package/dist/{run-DaCeNKRm.mjs → run-BQAmrohh.mjs} +2 -2
- package/dist/{selection-Bs8phwhN.mjs → selection-D1ZDzHFX.mjs} +105 -62
- package/dist/{server-bare-BOh-iZEj.mjs → server-bare-CEQdB_F4.mjs} +37 -1
- package/dist/{server-command-8CuA51Cv.mjs → server-command-RlS-Kl4a.mjs} +5 -5
- package/dist/server-expo-BVV9qy31.mjs +2 -0
- package/dist/{server-expo-ABQs2XFA.mjs → server-expo-bB1VV2k-.mjs} +8 -5
- package/dist/{settings-CMHhQNwI.mjs → settings-BcVCcAT5.mjs} +2 -2
- package/dist/{settings-BDVI8Ivc.mjs → settings-D776ygML.mjs} +47 -3
- package/dist/{settings-Djl-mpjX.mjs → settings-D9LtQaUw.mjs} +2 -1
- package/dist/{settings-payload-cm60Zhib.mjs → settings-payload-_aatELz2.mjs} +4 -4
- package/dist/{settings-write-BdNRLlBn.mjs → settings-write-CkTVGQ4O.mjs} +5 -5
- package/dist/settings.schema.json +58 -9
- package/dist/{simslim-DCQwzoPy.mjs → simslim-CbpHERcv.mjs} +1 -1
- package/dist/{slot-launch-0l7RqSpr.mjs → slot-launch-Dbgfh8gc.mjs} +6 -6
- package/dist/{stage-F4cAfJGi.mjs → stage-BuHuRj1y.mjs} +1 -1
- package/dist/{start-DcqnF9p8.mjs → start-Cr-c3Xhq.mjs} +1 -1
- package/dist/{start-DrPwER_2.mjs → start-Dlv4XXTP.mjs} +11 -11
- package/dist/{state-CZxLyetD.mjs → state-C2AUjjhg.mjs} +1 -1
- package/dist/{state-BX1y5syV.mjs → state-D5ZxwCGJ.mjs} +2 -2
- package/dist/{stats-GxuCbles.mjs → stats-D5c-uIBp.mjs} +4 -4
- package/dist/{status-7ULDEJ1e.mjs → status-CK7ZoEhV.mjs} +2 -2
- package/dist/{status-BfnK9pUd.mjs → status-D6PBK6_-.mjs} +49 -26
- package/dist/{status-Bj7ZYvvc.mjs → status-DbQv--Yb.mjs} +1 -1
- package/dist/{status-watch-BfabQn03.mjs → status-watch-okrpea4i.mjs} +17 -6
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-CbWo21kb.mjs → stim-desktop-CYXLFpFS.mjs} +1 -1
- package/dist/{stop-x1Yu3He4.mjs → stop-CHtAiv79.mjs} +2 -2
- package/dist/{stop-D-EAr25B.mjs → stop-p9uSKuGE.mjs} +20 -19
- package/dist/{stop-CH79S3IZ.mjs → stop-uRQ-zYcl.mjs} +9 -5
- package/dist/supervisor-run.d.mts +1 -0
- package/dist/supervisor-run.mjs +243 -65
- package/dist/{support-Be0UeVZU.mjs → support-BMpQIug0.mjs} +11 -10
- package/dist/{support-CNg_YsOk.mjs → support-PFyTkrnr.mjs} +4 -4
- package/dist/{swiftpm-artifact-inputs-uPqYvGBv.mjs → swiftpm-artifact-inputs-Cddq6jN2.mjs} +1 -1
- package/dist/{swiftpm-macos-Ch4YjY_A.mjs → swiftpm-macos-BSj9iZlI.mjs} +8 -8
- package/dist/{toolchain-JYAOquPg.mjs → toolchain-B-mzR9Rh.mjs} +1 -1
- package/dist/{toolchain-CbCG6C5Z.mjs → toolchain-CLGnEUgT.mjs} +4 -4
- package/dist/{trigger-DMou-X7j.mjs → trigger-CfnOfpDd.mjs} +1 -1
- package/dist/trigger-DBZ-GBrl.mjs +2 -0
- package/dist/{warm-progress-C0RsbngN.mjs → warm-progress--KkkBBaq.mjs} +3 -3
- package/dist/web-BxSo493O.mjs +2 -0
- package/dist/web-run.mjs +5 -5
- package/dist/{web-Cq_AQ4DK.mjs → web-xlVssjQf.mjs} +8 -8
- package/dist/{workspace-state-BjqdjnJR.mjs → workspace-state-DGwkPXwq.mjs} +2 -2
- package/dist/{workspaces-DFbj07jp.mjs → workspaces-CvSYD_78.mjs} +106 -26
- package/dist/{worktree-COAJ3-OD.mjs → worktree-CaQBf6kh.mjs} +26 -47
- package/dist/worktree-DTOIohFe.mjs +2 -0
- package/package.json +7 -7
- package/shim/bundle-response.cjs +37 -0
- package/dist/server-expo-Ba_Y21vB.mjs +0 -2
- package/dist/trigger-qp2ji5wE.mjs +0 -2
- package/dist/web-Je6abcpz.mjs +0 -2
- package/dist/worktree-JGUd_53L.mjs +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { l as WorkspaceProcessCleanupError } from "./exec-aULwtNly.mjs";
|
|
2
|
-
import { I as waitForSharedBuild } from "./activity-
|
|
2
|
+
import { I as waitForSharedBuild } from "./activity-BR5oHSO5.mjs";
|
|
3
3
|
import { rmSync } from "node:fs";
|
|
4
4
|
//#region src/engine/artifact-lifecycle.ts
|
|
5
5
|
async function runArtifactLifecycle(phases) {
|
|
@@ -1,30 +1,33 @@
|
|
|
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-
|
|
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-
|
|
1
|
+
import { S as process_identity_exports, d as workspaceProcessLockError, l as WorkspaceProcessCleanupError, n as isTimeoutError, t as getExecutor, u as withWorkspaceProcessLock } from "./exec-aULwtNly.mjs";
|
|
2
|
+
import { E as workspaceDir, j as workspaceStateFile$1, k as workspaceLogsDir$1, r as readWorkspaceState$1, u as workspaceLastUsed, w as workspaceAgentDeviceDir } from "./workspace-state-DGwkPXwq.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-AbUjIBOQ.mjs";
|
|
4
|
+
import { o as formatLongDuration, u as plural } from "./command-output-DjCsmzLZ.mjs";
|
|
5
5
|
import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, r as childEnvironment } from "./operation-exec-Dp4FuIGR.mjs";
|
|
6
|
-
import { At as
|
|
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 {
|
|
11
|
-
import {
|
|
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, it as settingValueAt, jt as listWorktreesAsync, mt as LOCKED_REASON, qt as unpushedCommitsAsync, sn as removeTemporaryEntryAsync, wt as hasPopulatedSubmodulesAsync } from "./settings-D776ygML.mjs";
|
|
7
|
+
import { P as readRemoteSession, i as findProjectRoot$1 } from "./project-D1n0K4yg.mjs";
|
|
8
|
+
import { A as listAdbDevices, D as getAvdNameForSerial, F as listAvdsAsync, G as ownedAvdSerialResolverAsync, O as getAvdNameForSerialAsync, P as listAvds, V as ownedAvdDirectory, j as listAdbDevicesAsync, yt as readParked } from "./android-BHKgeOuq.mjs";
|
|
9
|
+
import { c as pidExists } from "./metro-BMQHczcf.mjs";
|
|
10
|
+
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-DsDkdP72.mjs";
|
|
11
|
+
import { o as readWebRecord, u as webFacts } from "./state-D5ZxwCGJ.mjs";
|
|
12
|
+
import { a as unregister, n as readManifest } from "./cache-manifest-evF_zJ9U.mjs";
|
|
13
|
+
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, x as resolveSupervisorTarget, y as workspaceInUse } from "./workspaces-CvSYD_78.mjs";
|
|
12
14
|
import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
|
|
13
|
-
import { N as listBuildLocks, _ as workspaceDeviceLastUseAt, b as leaseIsExpired, g as workspaceActivity, x as listLeaseFiles } from "./activity-
|
|
14
|
-
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-
|
|
15
|
+
import { N as listBuildLocks, _ as workspaceDeviceLastUseAt, b as leaseIsExpired, g as workspaceActivity, x as listLeaseFiles } from "./activity-BR5oHSO5.mjs";
|
|
16
|
+
import { d as listAllIosSims, f as listAllIosSimsAsync } from "./ios-CoMCWfub.mjs";
|
|
15
17
|
import { s as metroStoreRoot } from "./errors-DHm_U5gv.mjs";
|
|
16
|
-
import { t as resolveMaintenanceSettings } from "./settings-
|
|
17
|
-
import {
|
|
18
|
+
import { t as resolveMaintenanceSettings } from "./settings-D9LtQaUw.mjs";
|
|
19
|
+
import { o as runStop } from "./stop-p9uSKuGE.mjs";
|
|
20
|
+
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-CaQBf6kh.mjs";
|
|
18
21
|
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
|
|
20
|
-
import { a as restoreProblem, r as recordLightened, t as finishLightened } from "./lightened-
|
|
21
|
-
import { i as writeIdleShutdownEvent, n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-
|
|
22
|
+
import { a as lastFetchedAtAsync, c as mergeStateAsync, f as recordPullRequestLookup, i as fetchDefaultBranchAsync, o as localDefaultBranchAsync, r as FETCH_FRESH_MS } from "./warm-progress--KkkBBaq.mjs";
|
|
23
|
+
import { a as restoreProblem, r as recordLightened, t as finishLightened } from "./lightened-vSxkstg6.mjs";
|
|
24
|
+
import { i as writeIdleShutdownEvent, n as dueIdleDevices, r as shutDownIdleDevices } from "./idle-shutdown-BM37gMfU.mjs";
|
|
22
25
|
import { readClaimSet } from "@stim-cli/core/ownership-claim";
|
|
23
|
-
import { existsSync, lstatSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
26
|
+
import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
24
27
|
import { tmpdir } from "node:os";
|
|
25
28
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
26
|
-
import { buildCacheRoot, configDir, metroCacheRoot } from "@stim-cli/core";
|
|
27
|
-
import { LAST_BUILD_KEYS, MAINTENANCE_LOG_NAME, lastNativeUseFrom, loadConfig, readBuildHistory, readMaintenanceState, readPullRequestCache, settingDefinition, sharedCompilationCache } from "@stim-cli/core/state";
|
|
29
|
+
import { buildCacheRoot, configDir, metroCacheRoot, rotatedLogPath } from "@stim-cli/core";
|
|
30
|
+
import { LAST_BUILD_KEYS, MAINTENANCE_LOG_NAME, coerceSettingText, deviceViewersDir, lastNativeUseFrom, loadConfig, parseNdjsonText, readBuildHistory, readJsonObject, readMaintenanceState, readPullRequestCache, settingDefinition, settingValueError, sharedCompilationCache } from "@stim-cli/core/state";
|
|
28
31
|
import { isAbsolute as isAbsolute$1, join as join$1 } from "path";
|
|
29
32
|
import chalk from "chalk";
|
|
30
33
|
import { existsSync as existsSync$1, readdirSync as readdirSync$1, statSync as statSync$1 } from "fs";
|
|
@@ -126,7 +129,7 @@ function removalBlocker(facts, olderThan, now, noOwnCommitsIdleMs) {
|
|
|
126
129
|
if (facts.bare) return skip("bare-repository", "bare repository");
|
|
127
130
|
if (typeof facts.source === "object") return skip("source-checkout-unknown", `source checkout unknown: ${facts.source.refusal}`);
|
|
128
131
|
if (facts.source === "source") return skip("source-checkout", "source checkout");
|
|
129
|
-
if (facts.locked) return skip("locked",
|
|
132
|
+
if (facts.locked) return skip("locked", LOCKED_REASON);
|
|
130
133
|
if (facts.nested?.length) return skip("nested-worktree", `contains the worktree ${facts.nested.join(", ")}`);
|
|
131
134
|
if (facts.inUse.length) return skip("in-use", `in use: ${facts.inUse.join("; ")}`);
|
|
132
135
|
if (facts.porcelain === null) return skip("status-unreadable", "git status could not be read");
|
|
@@ -1320,6 +1323,11 @@ async function planSweep({ settings, sizes, protectedRoot, pinned, now, devices
|
|
|
1320
1323
|
}) : { workspaces: [] };
|
|
1321
1324
|
for (const entry of outputs.workspaces) {
|
|
1322
1325
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
1326
|
+
if (root !== null && keptByLock(entry) && entry.keptReason) skips.push({
|
|
1327
|
+
target: root,
|
|
1328
|
+
reason: entry.keptReason,
|
|
1329
|
+
workspace: root
|
|
1330
|
+
});
|
|
1323
1331
|
if (root === null || !entry.willClear || root === protectedRoot) continue;
|
|
1324
1332
|
if (pinned(root)) {
|
|
1325
1333
|
skips.push({
|
|
@@ -1481,6 +1489,432 @@ async function planWorktrees({ protectedRoot, pinned, now, level, graceMs, sizes
|
|
|
1481
1489
|
};
|
|
1482
1490
|
}
|
|
1483
1491
|
//#endregion
|
|
1492
|
+
//#region src/maintenance/idle-stop.ts
|
|
1493
|
+
const HOUR_MS = 36e5;
|
|
1494
|
+
const SETTING = "maintenance.idleStopHours";
|
|
1495
|
+
const METRO_REQUESTS = /* @__PURE__ */ new Set([
|
|
1496
|
+
"bundle_response_started",
|
|
1497
|
+
"bundle_response_progress",
|
|
1498
|
+
"bundle_response_finished",
|
|
1499
|
+
"bundle_response_failed",
|
|
1500
|
+
"bundle_build_started",
|
|
1501
|
+
"bundle_build_done",
|
|
1502
|
+
"bundle_build_failed",
|
|
1503
|
+
"manifest_request_started",
|
|
1504
|
+
"manifest_request_finished",
|
|
1505
|
+
"manifest_request_failed",
|
|
1506
|
+
"hmr_update"
|
|
1507
|
+
]);
|
|
1508
|
+
const STIM_SESSION = "stim-teardown-inventory";
|
|
1509
|
+
const AGENT_DEVICE_DRIVERS = /* @__PURE__ */ new Set(["agent-device-claim", "agent-device-lease"]);
|
|
1510
|
+
function decideIdleStop(evidence, { idleMs, now }) {
|
|
1511
|
+
if (!(idleMs > 0)) return {
|
|
1512
|
+
stop: false,
|
|
1513
|
+
reason: `${SETTING} is 0`
|
|
1514
|
+
};
|
|
1515
|
+
const last = evidence.activity.filter(({ at }) => Number.isFinite(at)).reduce((best, entry) => !best || entry.at > best.at ? entry : best, null);
|
|
1516
|
+
const idle = last ? now - last.at : NaN;
|
|
1517
|
+
if (last && idle < idleMs) return {
|
|
1518
|
+
stop: false,
|
|
1519
|
+
active: true,
|
|
1520
|
+
reason: `its last ${last.basis} was ${formatLongDuration(Math.max(0, idle))} ago, within ${SETTING}`
|
|
1521
|
+
};
|
|
1522
|
+
if (evidence.keep.length) return {
|
|
1523
|
+
stop: false,
|
|
1524
|
+
reason: evidence.keep.join("; ")
|
|
1525
|
+
};
|
|
1526
|
+
if (!last) return {
|
|
1527
|
+
stop: false,
|
|
1528
|
+
reason: "its last activity is unknown"
|
|
1529
|
+
};
|
|
1530
|
+
return {
|
|
1531
|
+
stop: true,
|
|
1532
|
+
idleMs: idle
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
async function idleStopHours(root, env, operation) {
|
|
1536
|
+
const setting = settingDefinition(SETTING);
|
|
1537
|
+
if (!setting?.env) return { invalid: `${SETTING} is not in the settings registry` };
|
|
1538
|
+
const raw = env[setting.env];
|
|
1539
|
+
const fromEnv = raw !== void 0 && raw !== "";
|
|
1540
|
+
let value;
|
|
1541
|
+
if (fromEnv) value = coerceSettingText(setting, raw);
|
|
1542
|
+
else try {
|
|
1543
|
+
const resolved = operation ? await resolveProjectSettingsAsync(root, {
|
|
1544
|
+
env,
|
|
1545
|
+
signal: operation.signal,
|
|
1546
|
+
declareFor: operation
|
|
1547
|
+
}) : resolveProjectSettings(root);
|
|
1548
|
+
value = settingValueAt(resolved.settings, SETTING);
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
rethrowCleanup(error, operation?.signal);
|
|
1551
|
+
return { invalid: `${SETTING} cannot be resolved: ${error instanceof Error ? error.message : String(error)}` };
|
|
1552
|
+
}
|
|
1553
|
+
if (value === void 0) return { hours: Number(setting.default) };
|
|
1554
|
+
const error = settingValueError(setting, value);
|
|
1555
|
+
return error || typeof value !== "number" ? { invalid: `${fromEnv ? setting.env : SETTING} is invalid: expected ${error ?? "a number"}` } : { hours: value };
|
|
1556
|
+
}
|
|
1557
|
+
function deviceKeepReason(device, platform) {
|
|
1558
|
+
const { activity } = device;
|
|
1559
|
+
const what = `its ${device.kind === "ios" ? "simulator" : "emulator"} ${device.name}`;
|
|
1560
|
+
if (activity.state === "driven" && !activity.basis.every((basis) => AGENT_DEVICE_DRIVERS.has(basis))) return `${what} is driven by ${activity.driver?.tool ?? "an unknown tool"}`;
|
|
1561
|
+
if (activity.basis.includes("agent-device-claim") && !activity.recent?.["agent-action"]) return `${what} has a live agent-device claim whose session activity cannot be found`;
|
|
1562
|
+
const probed = activity.state === "driven" ? activity.unknown ?? [] : activity.state === "unknown" ? activity.basis : [];
|
|
1563
|
+
const unknown = platform === "win32" ? probed.filter((basis) => basis !== "driver-process") : probed;
|
|
1564
|
+
if (unknown.length) return `${what} has unknown activity (${unknown.join(", ")})`;
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
function recentAt(activity, basis) {
|
|
1568
|
+
return Date.parse(activity.recent?.[basis] ?? "");
|
|
1569
|
+
}
|
|
1570
|
+
const missing = (error) => error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
1571
|
+
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
1572
|
+
function agentSessionsActedAt(root) {
|
|
1573
|
+
const dir = join(workspaceAgentDeviceDir(root), "sessions");
|
|
1574
|
+
let names;
|
|
1575
|
+
try {
|
|
1576
|
+
names = readdirSync(dir);
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
return missing(error) ? NaN : `its agent-device sessions cannot be read (${message(error)})`;
|
|
1579
|
+
}
|
|
1580
|
+
let latest = NaN;
|
|
1581
|
+
for (const name of names) {
|
|
1582
|
+
if (name === STIM_SESSION) continue;
|
|
1583
|
+
try {
|
|
1584
|
+
const at = statSync(join(dir, name, "events.ndjson")).mtimeMs;
|
|
1585
|
+
if (!(at <= latest)) latest = at;
|
|
1586
|
+
} catch (error) {
|
|
1587
|
+
if (!missing(error)) return `its agent-device session ${name} cannot be read (${message(error)})`;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return latest;
|
|
1591
|
+
}
|
|
1592
|
+
function metroRequestAt(root, since, serving) {
|
|
1593
|
+
const file = join(workspaceLogsDir$1(root), "metro.ndjson");
|
|
1594
|
+
const rotated = rotatedLogPath(file);
|
|
1595
|
+
const records = [];
|
|
1596
|
+
for (const path of [rotated, file]) try {
|
|
1597
|
+
records.push(...parseNdjsonText(readFileSync(path, "utf8")));
|
|
1598
|
+
} catch (error) {
|
|
1599
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") continue;
|
|
1600
|
+
return `its Metro log cannot be read (${error instanceof Error ? error.message : String(error)})`;
|
|
1601
|
+
}
|
|
1602
|
+
let latest = NaN;
|
|
1603
|
+
let earliest = Infinity;
|
|
1604
|
+
for (const record of records) {
|
|
1605
|
+
if (typeof record.ts !== "number") continue;
|
|
1606
|
+
earliest = Math.min(earliest, record.ts);
|
|
1607
|
+
if (typeof record.event === "string" && METRO_REQUESTS.has(record.event) && !(record.ts <= latest)) latest = record.ts;
|
|
1608
|
+
}
|
|
1609
|
+
if (!Number.isFinite(latest) && earliest > since && existsSync(rotated)) return `its rotated Metro log does not reach back ${SETTING}`;
|
|
1610
|
+
if (serving && earliest === Infinity) return "its dev server runs but its Metro log is missing or empty";
|
|
1611
|
+
return latest;
|
|
1612
|
+
}
|
|
1613
|
+
function unreadableViewers() {
|
|
1614
|
+
const dir = deviceViewersDir();
|
|
1615
|
+
let names;
|
|
1616
|
+
try {
|
|
1617
|
+
names = readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
return missing(error) ? null : `the stim-server viewer records cannot be read (${message(error)})`;
|
|
1620
|
+
}
|
|
1621
|
+
for (const name of names) {
|
|
1622
|
+
const record = readJsonObject(join(dir, name));
|
|
1623
|
+
if (!record) return `the stim-server viewer record ${name} cannot be read`;
|
|
1624
|
+
if ((0, process_identity_exports.inspectProcessIdentity)(record) === "unknown") return `the stim-server behind the viewer record ${name} cannot be verified`;
|
|
1625
|
+
}
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1628
|
+
async function keepReasons(root, devices, { now, platform, locked, operation }) {
|
|
1629
|
+
const checks = {
|
|
1630
|
+
devServer: false,
|
|
1631
|
+
nativeRun: !locked
|
|
1632
|
+
};
|
|
1633
|
+
const keep = operation ? await workspaceInUseAsync(root, checks, operation.signal, operation) : workspaceInUse(root, checks);
|
|
1634
|
+
if (workspaceBuildInProgress(root)) keep.push("a build is in progress");
|
|
1635
|
+
if (readRemoteSession(root)) keep.push("it has a remote device session");
|
|
1636
|
+
const holder = canonicalPath(root);
|
|
1637
|
+
for (const { lease, path } of listLeaseFiles()) if (!lease) keep.push(`the device lease ${path} cannot be read`);
|
|
1638
|
+
else if (!leaseIsExpired(lease, now) && canonicalPath(lease.holder) === holder) keep.push(`it holds the ${lease.platform} device lease on ${lease.deviceName ?? lease.id}`);
|
|
1639
|
+
const browser = webFacts(readWebRecord(root));
|
|
1640
|
+
if (browser && browser.status !== "stopped") keep.push(`its owned Chrome is ${browser.status}`);
|
|
1641
|
+
for (const device of devices) {
|
|
1642
|
+
const reason = deviceKeepReason(device, platform);
|
|
1643
|
+
if (reason) keep.push(reason);
|
|
1644
|
+
}
|
|
1645
|
+
const viewers = devices.length ? unreadableViewers() : null;
|
|
1646
|
+
if (viewers) keep.push(viewers);
|
|
1647
|
+
return keep;
|
|
1648
|
+
}
|
|
1649
|
+
async function idleStopEvidence(root, devices, { now, idleMs, platform = process.platform, locked = false, serving = false, operation }) {
|
|
1650
|
+
const state = readWorkspaceState$1(root);
|
|
1651
|
+
if (!state && existsSync(workspaceStateFile$1(root))) return {
|
|
1652
|
+
activity: [],
|
|
1653
|
+
keep: ["its state.json cannot be read"]
|
|
1654
|
+
};
|
|
1655
|
+
const sessions = agentSessionsActedAt(root);
|
|
1656
|
+
if (typeof sessions === "string") return {
|
|
1657
|
+
activity: [],
|
|
1658
|
+
keep: [sessions]
|
|
1659
|
+
};
|
|
1660
|
+
const build = state?.lastBuild;
|
|
1661
|
+
const builtAt = Date.parse(String(build?.startedAt ?? "")) + (typeof build?.durationMs === "number" ? build.durationMs : 0);
|
|
1662
|
+
const activity = [
|
|
1663
|
+
{
|
|
1664
|
+
basis: "stim command",
|
|
1665
|
+
at: Date.parse(String(state?.lastUsedAt ?? ""))
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
basis: "native run",
|
|
1669
|
+
at: builtAt
|
|
1670
|
+
},
|
|
1671
|
+
{
|
|
1672
|
+
basis: "agent-device command",
|
|
1673
|
+
at: typeof sessions === "number" ? sessions : NaN
|
|
1674
|
+
},
|
|
1675
|
+
...devices.flatMap(({ activity: device }) => [{
|
|
1676
|
+
basis: "agent-device command",
|
|
1677
|
+
at: recentAt(device, "agent-action")
|
|
1678
|
+
}, {
|
|
1679
|
+
basis: "live view",
|
|
1680
|
+
at: recentAt(device, "viewer")
|
|
1681
|
+
}])
|
|
1682
|
+
].filter(({ at }) => Number.isFinite(at));
|
|
1683
|
+
if (activity.some(({ at }) => now - at < idleMs)) return {
|
|
1684
|
+
activity,
|
|
1685
|
+
keep: []
|
|
1686
|
+
};
|
|
1687
|
+
const keep = await keepReasons(root, devices, {
|
|
1688
|
+
now,
|
|
1689
|
+
platform,
|
|
1690
|
+
locked,
|
|
1691
|
+
operation
|
|
1692
|
+
});
|
|
1693
|
+
if (keep.length) return {
|
|
1694
|
+
activity,
|
|
1695
|
+
keep
|
|
1696
|
+
};
|
|
1697
|
+
const metro = metroRequestAt(root, now - idleMs, serving);
|
|
1698
|
+
if (typeof metro === "string") return {
|
|
1699
|
+
activity,
|
|
1700
|
+
keep: [metro]
|
|
1701
|
+
};
|
|
1702
|
+
if (Number.isFinite(metro)) activity.push({
|
|
1703
|
+
basis: "Metro request",
|
|
1704
|
+
at: metro
|
|
1705
|
+
});
|
|
1706
|
+
return {
|
|
1707
|
+
activity,
|
|
1708
|
+
keep
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
function rethrowCleanup(error, signal) {
|
|
1712
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1713
|
+
signal?.throwIfAborted();
|
|
1714
|
+
}
|
|
1715
|
+
async function unseenEmulatorError(unseen, operation) {
|
|
1716
|
+
try {
|
|
1717
|
+
const signal = operation?.signal;
|
|
1718
|
+
const adb = operation ? await listAdbDevicesAsync({
|
|
1719
|
+
timeoutMs: 5e3,
|
|
1720
|
+
signal,
|
|
1721
|
+
operation
|
|
1722
|
+
}) : listAdbDevices({ timeoutMs: 5e3 });
|
|
1723
|
+
for (const { serial } of [...adb.emulators, ...adb.unhealthy.filter((entry) => entry.kind === "emulator")]) {
|
|
1724
|
+
const name = operation ? await getAvdNameForSerialAsync(serial, {
|
|
1725
|
+
timeoutMs: 5e3,
|
|
1726
|
+
signal,
|
|
1727
|
+
operation
|
|
1728
|
+
}) : getAvdNameForSerial(serial, { timeoutMs: 5e3 });
|
|
1729
|
+
if (name === null) return `its emulators cannot be identified to prove them idle (${serial} gave no AVD name)`;
|
|
1730
|
+
if (unseen.includes(name)) return `its emulator ${name} runs as ${serial}, but its activity could not be read`;
|
|
1731
|
+
}
|
|
1732
|
+
return null;
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
rethrowCleanup(error, operation?.signal);
|
|
1735
|
+
return `its emulators cannot be listed to prove them idle (${error instanceof Error ? error.message : String(error)})`;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
function survivingServer(recorded) {
|
|
1739
|
+
const pid = recorded?.serverPid;
|
|
1740
|
+
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return null;
|
|
1741
|
+
const token = recorded?.serverProcessToken;
|
|
1742
|
+
return (typeof token === "string" ? ["same", "unknown"].includes((0, process_identity_exports.inspectProcessIdentity)({
|
|
1743
|
+
pid,
|
|
1744
|
+
processToken: token
|
|
1745
|
+
})) : pidExists(pid)) ? `its dev server (pid ${pid}) may still run after its supervisor exited; stim stop ends it` : null;
|
|
1746
|
+
}
|
|
1747
|
+
async function candidate(path, env, devices, operation) {
|
|
1748
|
+
const signal = operation?.signal;
|
|
1749
|
+
const project = loadConfig$1()?.projects?.[path];
|
|
1750
|
+
if (!project) return null;
|
|
1751
|
+
const supervisor = resolveSupervisorTarget({
|
|
1752
|
+
state: readWorkspaceState$1(path)?.supervisor,
|
|
1753
|
+
record: project.supervisor,
|
|
1754
|
+
reservedPort: project.metroPort
|
|
1755
|
+
});
|
|
1756
|
+
const slots = projectDeviceSlots(project);
|
|
1757
|
+
const ownsIos = slots.some(({ platforms }) => platforms.ios?.owned === true);
|
|
1758
|
+
const owns = ownsIos || slots.some(({ platforms }) => platforms.android?.owned === true);
|
|
1759
|
+
if (!owns && (supervisor.status === "none" || supervisor.status === "stale")) return null;
|
|
1760
|
+
const setting = await idleStopHours(path, env, operation);
|
|
1761
|
+
if ("invalid" in setting) return { skip: setting.invalid };
|
|
1762
|
+
if (setting.hours === 0) return null;
|
|
1763
|
+
let booted = [];
|
|
1764
|
+
if (owns) try {
|
|
1765
|
+
booted = (await devices(ownsIos)).filter((device) => device.project === path);
|
|
1766
|
+
} catch (error) {
|
|
1767
|
+
rethrowCleanup(error, signal);
|
|
1768
|
+
return supervisor.status === "none" || supervisor.status === "stale" ? null : { skip: "its owned devices cannot be listed to prove them idle" };
|
|
1769
|
+
}
|
|
1770
|
+
if (supervisor.status === "unverified") return { skip: `its dev server supervisor cannot be verified: ${supervisor.reason ?? "unknown identity"}` };
|
|
1771
|
+
if (supervisor.status === "ours" && readWorkspaceState$1(path)?.supervisor?.mode === "command-child") return { skip: "its dev server runs metro.command, whose bundle and HMR requests Stim cannot see" };
|
|
1772
|
+
if (supervisor.status === "ours" && readWorkspaceState$1(path)?.supervisor?.hmrUpdates !== true) return { skip: "its dev server does not report HMR updates to Stim: an Expo SDK before 54, or a server an older Stim started, which stim stop and stim start restart" };
|
|
1773
|
+
const avdNames = slots.flatMap(({ platforms }) => platforms.android?.owned && platforms.android.avdName ? [platforms.android.avdName] : []);
|
|
1774
|
+
if (supervisor.status !== "ours" && booted.length === 0) return null;
|
|
1775
|
+
const orphan = supervisor.status === "stale" ? survivingServer(readWorkspaceState$1(path)?.supervisor) : null;
|
|
1776
|
+
if (orphan) return { skip: orphan };
|
|
1777
|
+
const seen = new Set(booted.flatMap((device) => device.kind === "android" ? [device.id] : []));
|
|
1778
|
+
const unseen = avdNames.filter((name) => !seen.has(name));
|
|
1779
|
+
const emulators = unseen.length ? await unseenEmulatorError(unseen, operation) : null;
|
|
1780
|
+
if (emulators) return { skip: emulators };
|
|
1781
|
+
return {
|
|
1782
|
+
path,
|
|
1783
|
+
hours: setting.hours,
|
|
1784
|
+
serving: supervisor.status === "ours",
|
|
1785
|
+
devices: booted
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Plans stopping each workspace, other than `protectedRoot`, whose dev server runs or whose owned simulator or
|
|
1790
|
+
* emulator is booted, once it has had no real activity for its maintenance.idleStopHours.
|
|
1791
|
+
*/
|
|
1792
|
+
async function planIdleStop({ protectedRoot, now, devices, env = process.env, platform = process.platform, operation }) {
|
|
1793
|
+
const plan = {
|
|
1794
|
+
actions: [],
|
|
1795
|
+
blocked: [],
|
|
1796
|
+
skips: []
|
|
1797
|
+
};
|
|
1798
|
+
if (deviceSweepIsScoped(env)) return plan;
|
|
1799
|
+
for (const path of Object.keys(loadConfig$1()?.projects ?? {})) {
|
|
1800
|
+
const root = canonicalPath(path);
|
|
1801
|
+
if (root === protectedRoot) continue;
|
|
1802
|
+
operation?.signal.throwIfAborted();
|
|
1803
|
+
const found = await candidate(path, env, devices, operation);
|
|
1804
|
+
if (!found) continue;
|
|
1805
|
+
if ("skip" in found) {
|
|
1806
|
+
plan.skips.push({
|
|
1807
|
+
target: root,
|
|
1808
|
+
reason: found.skip,
|
|
1809
|
+
workspace: root
|
|
1810
|
+
});
|
|
1811
|
+
continue;
|
|
1812
|
+
}
|
|
1813
|
+
const idleMs = found.hours * HOUR_MS;
|
|
1814
|
+
const decision = decideIdleStop(await idleStopEvidence(path, found.devices, {
|
|
1815
|
+
now,
|
|
1816
|
+
idleMs,
|
|
1817
|
+
platform,
|
|
1818
|
+
serving: found.serving,
|
|
1819
|
+
operation
|
|
1820
|
+
}), {
|
|
1821
|
+
idleMs,
|
|
1822
|
+
now
|
|
1823
|
+
});
|
|
1824
|
+
if (!decision.stop) {
|
|
1825
|
+
if (!decision.active) plan.skips.push({
|
|
1826
|
+
target: root,
|
|
1827
|
+
reason: decision.reason,
|
|
1828
|
+
workspace: root
|
|
1829
|
+
});
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
plan.actions.push({
|
|
1833
|
+
kind: "would-stop-workspace",
|
|
1834
|
+
check: "idle",
|
|
1835
|
+
target: root,
|
|
1836
|
+
workspace: root,
|
|
1837
|
+
bytes: 0,
|
|
1838
|
+
reason: `no real activity for ${formatLongDuration(decision.idleMs)}, over ${SETTING} ${found.hours}`
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
return plan;
|
|
1842
|
+
}
|
|
1843
|
+
const kept$1 = (detail) => ({
|
|
1844
|
+
status: "kept",
|
|
1845
|
+
bytes: 0,
|
|
1846
|
+
detail
|
|
1847
|
+
});
|
|
1848
|
+
/**
|
|
1849
|
+
* Stops a planned idle workspace the way `stim stop` does, under its native-run and metro-start locks, after
|
|
1850
|
+
* deciding again that it is still idle. Physical-device leases stay.
|
|
1851
|
+
*/
|
|
1852
|
+
async function stopIdleWorkspace(action, { protectedRoot, devices, operation, env = operation?.env ?? process.env, by = "automatic maintenance" }) {
|
|
1853
|
+
const root = action.workspace ?? action.target;
|
|
1854
|
+
if (root === protectedRoot) return kept$1("the command that started this pass runs in it");
|
|
1855
|
+
if (deviceSweepIsScoped(env)) return kept$1("STIM_HOME scopes this config, and devices are machine-wide");
|
|
1856
|
+
const path = Object.keys(loadConfig$1()?.projects ?? {}).find((entry) => canonicalPath(entry) === root) ?? root;
|
|
1857
|
+
const stillIdle = async () => {
|
|
1858
|
+
const now = Date.now();
|
|
1859
|
+
const found = await candidate(path, env, devices(), operation);
|
|
1860
|
+
if (!found) return "nothing of it runs any more";
|
|
1861
|
+
if ("skip" in found) return found.skip;
|
|
1862
|
+
const idleMs = found.hours * HOUR_MS;
|
|
1863
|
+
const decision = decideIdleStop(await idleStopEvidence(path, found.devices, {
|
|
1864
|
+
now,
|
|
1865
|
+
idleMs,
|
|
1866
|
+
locked: true,
|
|
1867
|
+
serving: found.serving,
|
|
1868
|
+
operation
|
|
1869
|
+
}), {
|
|
1870
|
+
idleMs,
|
|
1871
|
+
now
|
|
1872
|
+
});
|
|
1873
|
+
return decision.stop ? null : decision.reason;
|
|
1874
|
+
};
|
|
1875
|
+
const signal = operation?.signal;
|
|
1876
|
+
const run = await withIdleWorkspace(path, async () => {
|
|
1877
|
+
try {
|
|
1878
|
+
return await withWorkspaceProcessLock(workspaceDir(path), "metro-start", async () => {
|
|
1879
|
+
const active = await stillIdle();
|
|
1880
|
+
if (active) return kept$1(active);
|
|
1881
|
+
const stopped = await runStop({
|
|
1882
|
+
root: path,
|
|
1883
|
+
operation,
|
|
1884
|
+
report: () => {},
|
|
1885
|
+
requester: { by: `${by} (${action.reason})` },
|
|
1886
|
+
releaseLeases: () => []
|
|
1887
|
+
});
|
|
1888
|
+
return stopped.ok ? {
|
|
1889
|
+
status: "done",
|
|
1890
|
+
bytes: 0,
|
|
1891
|
+
detail: stopped.summary
|
|
1892
|
+
} : {
|
|
1893
|
+
status: "failed",
|
|
1894
|
+
bytes: 0,
|
|
1895
|
+
detail: stopped.summary
|
|
1896
|
+
};
|
|
1897
|
+
}, {
|
|
1898
|
+
external: true,
|
|
1899
|
+
waitMs: 0,
|
|
1900
|
+
ownerPurpose: "idle stop",
|
|
1901
|
+
signal,
|
|
1902
|
+
declareSpawnsFor: operation
|
|
1903
|
+
});
|
|
1904
|
+
} catch (error) {
|
|
1905
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
1906
|
+
signal?.throwIfAborted();
|
|
1907
|
+
if (workspaceProcessLockError(error)) return kept$1("a stim start holds its metro-start lock");
|
|
1908
|
+
throw error;
|
|
1909
|
+
}
|
|
1910
|
+
}, {
|
|
1911
|
+
purpose: "automatic maintenance",
|
|
1912
|
+
devServer: false,
|
|
1913
|
+
operation
|
|
1914
|
+
});
|
|
1915
|
+
return run.ran ? run.value : kept$1(`in use: ${run.reasons.join("; ")}`);
|
|
1916
|
+
}
|
|
1917
|
+
//#endregion
|
|
1484
1918
|
//#region src/workspace/running-from.ts
|
|
1485
1919
|
const LIST_TIMEOUT_MS = 1e4;
|
|
1486
1920
|
function parsePs(text) {
|
|
@@ -1629,6 +2063,7 @@ function artifactWorktree(root, entries, source = sourceCheckoutOf(entries)) {
|
|
|
1629
2063
|
return {
|
|
1630
2064
|
path: entry.path,
|
|
1631
2065
|
linked: entry.path !== source.path,
|
|
2066
|
+
locked: Boolean(entry.locked),
|
|
1632
2067
|
keys
|
|
1633
2068
|
};
|
|
1634
2069
|
}
|
|
@@ -1725,6 +2160,7 @@ function buildNativeUseReason(keys, now) {
|
|
|
1725
2160
|
function artifactGuard(candidate, kind, pinned, locked, running) {
|
|
1726
2161
|
const { worktree, path, keys } = candidate;
|
|
1727
2162
|
if (keys.some(pinned)) return "pinned by maintenance.keep";
|
|
2163
|
+
if (candidate.locked) return LOCKED_REASON;
|
|
1728
2164
|
if (!pathExists(path)) return "it is already gone";
|
|
1729
2165
|
let real;
|
|
1730
2166
|
try {
|
|
@@ -1770,7 +2206,8 @@ async function collectArtifactsAsync(kind, options, signal, operation) {
|
|
|
1770
2206
|
const candidate = {
|
|
1771
2207
|
worktree: worktree.path,
|
|
1772
2208
|
path,
|
|
1773
|
-
keys: worktree.keys
|
|
2209
|
+
keys: worktree.keys,
|
|
2210
|
+
locked: worktree.locked
|
|
1774
2211
|
};
|
|
1775
2212
|
let reason = protectedHere ? "the command that started this pass runs inside its worktree" : artifactGuard(candidate, kind, options.pinned, void 0, running);
|
|
1776
2213
|
if (!reason) {
|
|
@@ -1828,7 +2265,8 @@ function collectArtifacts(kind, options) {
|
|
|
1828
2265
|
const candidate = {
|
|
1829
2266
|
worktree: worktree.path,
|
|
1830
2267
|
path,
|
|
1831
|
-
keys: worktree.keys
|
|
2268
|
+
keys: worktree.keys,
|
|
2269
|
+
locked: worktree.locked
|
|
1832
2270
|
};
|
|
1833
2271
|
const reason = protectedHere ? "the command that started this pass runs inside its worktree" : keptReason(candidate, kind, {
|
|
1834
2272
|
...options,
|
|
@@ -1867,7 +2305,8 @@ async function clearArtifact(action, kind, options) {
|
|
|
1867
2305
|
const candidate = {
|
|
1868
2306
|
worktree: worktree.path,
|
|
1869
2307
|
path: action.target,
|
|
1870
|
-
keys: worktree.keys
|
|
2308
|
+
keys: worktree.keys,
|
|
2309
|
+
locked: worktree.locked
|
|
1871
2310
|
};
|
|
1872
2311
|
const running = kind === "dependencies" ? await readRunningProcessesAsync() : null;
|
|
1873
2312
|
const early = keptReason(candidate, kind, {
|
|
@@ -1889,6 +2328,8 @@ async function clearArtifact(action, kind, options) {
|
|
|
1889
2328
|
const before = lowestFree(measureDisk());
|
|
1890
2329
|
const [key] = candidate.keys;
|
|
1891
2330
|
const remove = async () => {
|
|
2331
|
+
const lock = candidate.locked ? "locked" : await worktreeLockAsync(candidate.worktree);
|
|
2332
|
+
if (lock) return lockReason(lock);
|
|
1892
2333
|
const reason = keptReason(candidate, kind, {
|
|
1893
2334
|
...options,
|
|
1894
2335
|
now: Date.now(),
|
|
@@ -2285,6 +2726,11 @@ async function planLevel2({ settings, sizes, protectedRoot, pinned, now, operati
|
|
|
2285
2726
|
lighten: true
|
|
2286
2727
|
})).workspaces.flatMap((entry) => {
|
|
2287
2728
|
const root = entry.projectRoot === null ? null : canonicalPath(entry.projectRoot);
|
|
2729
|
+
if (root !== null && keptByLock(entry) && entry.keptReason) skips.push({
|
|
2730
|
+
target: root,
|
|
2731
|
+
reason: entry.keptReason,
|
|
2732
|
+
workspace: root
|
|
2733
|
+
});
|
|
2288
2734
|
if (root === null || !entry.willClear || root === protectedRoot || pinned(root)) return [];
|
|
2289
2735
|
const used = workspaceLastUsed(root);
|
|
2290
2736
|
return Number.isFinite(used) ? [{
|
|
@@ -2501,7 +2947,7 @@ async function planPressureLevels(level, context) {
|
|
|
2501
2947
|
function triggeringRoot(operation) {
|
|
2502
2948
|
return canonicalPath(findProjectRoot$1(operation?.cwd ?? process.cwd()) ?? join(configDir(), "maintenance", "no-project"));
|
|
2503
2949
|
}
|
|
2504
|
-
async function plannedMaintenance(pressure, recordedSizes, settings, { devices = true, sweep = false, worktrees = false, idle = false, refresh = true, operation } = {}) {
|
|
2950
|
+
async function plannedMaintenance(pressure, recordedSizes, settings, { devices = true, sweep = false, worktrees = false, idle = false, refresh = true, background = false, operation } = {}) {
|
|
2505
2951
|
const env = operation?.env ?? process.env;
|
|
2506
2952
|
const resolved = resolveBudget({ env });
|
|
2507
2953
|
if (resolved.error) throw new Error(resolved.error);
|
|
@@ -2577,7 +3023,7 @@ async function plannedMaintenance(pressure, recordedSizes, settings, { devices =
|
|
|
2577
3023
|
recentlyUsed: (workspace) => recentUse(workspace, settings)
|
|
2578
3024
|
});
|
|
2579
3025
|
const merge = (extra) => {
|
|
2580
|
-
for (const action of extra.actions) if (!result.actions.some((entry) => entry.kind === action.kind && entry.target === action.target && (entry.level === action.level || action.kind === "would-delete-devices"))) result.actions.push(action);
|
|
3026
|
+
for (const action of extra.actions) if (!result.actions.some((entry) => entry.kind === action.kind && entry.target === action.target && (entry.level === action.level || action.kind === "would-delete-devices") && (action.check !== "idle" || entry.check === "idle"))) result.actions.push(action);
|
|
2581
3027
|
result.blocked.push(...extra.blocked);
|
|
2582
3028
|
result.skips.push(...extra.skips);
|
|
2583
3029
|
};
|
|
@@ -2604,11 +3050,27 @@ async function plannedMaintenance(pressure, recordedSizes, settings, { devices =
|
|
|
2604
3050
|
merge(planned);
|
|
2605
3051
|
result.worktreeSweep = planned.sweep;
|
|
2606
3052
|
}
|
|
2607
|
-
if (idle && devices)
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
3053
|
+
if (idle && devices) {
|
|
3054
|
+
merge(planIdleShutdown({
|
|
3055
|
+
protectedRoot: root,
|
|
3056
|
+
now: Date.now(),
|
|
3057
|
+
env
|
|
3058
|
+
}));
|
|
3059
|
+
const now = Date.now();
|
|
3060
|
+
try {
|
|
3061
|
+
merge(await planIdleStop({
|
|
3062
|
+
protectedRoot: background ? "" : root,
|
|
3063
|
+
now,
|
|
3064
|
+
env,
|
|
3065
|
+
operation,
|
|
3066
|
+
devices: operation ? cachedDeviceActivityAsync(now, env, operation.signal, operation) : cachedDeviceActivity(now)
|
|
3067
|
+
}));
|
|
3068
|
+
} catch (error) {
|
|
3069
|
+
if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
|
|
3070
|
+
operation?.signal.throwIfAborted();
|
|
3071
|
+
result.blocked.push(`idle stop could not be planned: ${error instanceof Error ? error.message : String(error)}`);
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
2612
3074
|
if (pressure) {
|
|
2613
3075
|
const pressured = await planPressureLevels(diskPressureLevel(lowestFree(pressure.disk), budget, settings), {
|
|
2614
3076
|
settings,
|
|
@@ -2804,7 +3266,8 @@ async function clearOutputs(action, context) {
|
|
|
2804
3266
|
olderThan,
|
|
2805
3267
|
now,
|
|
2806
3268
|
measure: false,
|
|
2807
|
-
lighten
|
|
3269
|
+
lighten,
|
|
3270
|
+
only: root
|
|
2808
3271
|
});
|
|
2809
3272
|
const entry = report.workspaces.find((candidate) => candidate.projectRoot && canonicalPath(candidate.projectRoot) === root);
|
|
2810
3273
|
if (!entry) return kept("it has no build outputs any more");
|
|
@@ -3096,7 +3559,12 @@ async function executeAction(action, context) {
|
|
|
3096
3559
|
case "would-delete-parked-device": return deleteParkedDevice(action);
|
|
3097
3560
|
case "would-delete-devices": return deleteDevices(action, context);
|
|
3098
3561
|
case "would-shutdown-device": return action.check === "disk" ? kept("automatic maintenance does not stop devices or dev servers for disk") : shutDownIdleDevice(action);
|
|
3099
|
-
case "would-stop-workspace":
|
|
3562
|
+
case "would-stop-workspace":
|
|
3563
|
+
if (action.level === 3) return stopWorkspace(action, context);
|
|
3564
|
+
return action.check === "idle" ? stopIdleWorkspace(action, {
|
|
3565
|
+
protectedRoot: context.background ? "" : context.protectedRoot,
|
|
3566
|
+
devices: () => cachedDeviceActivity(Date.now())
|
|
3567
|
+
}) : kept("automatic maintenance stops dev servers only at disk pressure level 3 or after maintenance.idleStopHours");
|
|
3100
3568
|
case "would-clear-build-dirs":
|
|
3101
3569
|
case "would-delete-dependencies": return clearArtifacts(action, context);
|
|
3102
3570
|
case "would-stop-gradle-daemons": return stopGradleDaemonsAction(action);
|
|
@@ -3110,4 +3578,4 @@ function diskRecovered(budget) {
|
|
|
3110
3578
|
return measureDisk().every((disk) => disk.freeMb >= floor);
|
|
3111
3579
|
}
|
|
3112
3580
|
//#endregion
|
|
3113
|
-
export {
|
|
3581
|
+
export { candidateRootsAsync as C, worktreeRemovalReason as D, worktreePullRequestNote as E, maintenancePinned as S, removeWorktrees as T, finishedWorkspaces as _, previewMaintenance as a, cachedDeviceActivity as b, deleteTempLeftovers as c, appRoots as d, artifactWorktrees as f, stopIdleWorkspace as g, planIdleStop 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, measureOwnedDevices as v, collectWorktreeSweep as w, cachedDeviceActivityAsync as x, ownedDeviceUsage as y };
|