stim 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acquire-artifact-DVsvSwf7.mjs → acquire-artifact-CKByBnTD.mjs} +2 -2
- package/dist/{act-C-BqJEpu.mjs → act-8iswyfRa.mjs} +319 -126
- package/dist/{activity-Lnb_EoRY.mjs → activity-DRMg4_mD.mjs} +6 -6
- package/dist/{agent-device-usage-output-DbXy5tg8.mjs → agent-device-usage-output-tE90fDdo.mjs} +5 -5
- package/dist/{android-CiNQw3kq.mjs → android-CHmSU4B4.mjs} +101 -45
- package/dist/{android-DTAcRwBC.mjs → android-CsPs-7Mg.mjs} +23 -18
- package/dist/{android-B5P81yI-.mjs → android-D577ApKG.mjs} +37 -15
- package/dist/{android-CSbLRD53.mjs → android-YWCbmkVK.mjs} +5 -5
- package/dist/{android-cas-BTVhZ0Qs.mjs → android-cas-_aDifWW0.mjs} +4 -4
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api.d.mts +14 -4
- package/dist/api.mjs +39 -29
- package/dist/{apk-signed-tail-B46U9hXc.mjs → apk-signed-tail-CQbwM0qO.mjs} +2 -2
- package/dist/{artifact-CsAP6AGK.mjs → artifact-DYtHjxsn.mjs} +19 -24
- package/dist/{artifact-BxREhAaV.mjs → artifact-bFkfD3vf.mjs} +18 -23
- package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
- package/dist/auto-placement-BVqs8AJi.mjs +350 -0
- package/dist/{browser-web-rYPyqhTf.mjs → browser-web-BUaLcafY.mjs} +16 -16
- package/dist/{build-DPhApsjV.mjs → build-cQURy_KW.mjs} +35 -31
- package/dist/{build-cache-DrXNCy3T.mjs → build-cache-CZULpXVl.mjs} +43 -21
- package/dist/{build-plan-DrMMdayj.mjs → build-plan-CxoYfxsc.mjs} +7 -6
- package/dist/{cache-manifest-BEZ9Bpl1.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{budget-k2mZGvvk.mjs → ccache-Bm_A1xX9.mjs} +562 -1604
- package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
- package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
- package/dist/{cli-BBKFGOFl.mjs → cli-CpbaLDa7.mjs} +24 -23
- package/dist/cli.mjs +1 -1
- package/dist/{client-D9CaRks-.mjs → client-YxCer6ab.mjs} +84 -65
- package/dist/collector-run.d.mts +10 -9
- package/dist/collector-run.mjs +42 -27
- package/dist/{command-output-BF5AR2dL.mjs → command-output-C8R1KIvi.mjs} +1 -1
- package/dist/{config-BktkY_zC.mjs → config-Cn94Jc0g.mjs} +23 -4
- package/dist/{dependencies-Dw6wfQdv.mjs → dependencies-DKeMzwXY.mjs} +108 -60
- package/dist/{dependency-state-DFB41vfr.mjs → dependency-state-CojA2o0t.mjs} +14 -7
- package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
- package/dist/{dev-client-DXR_tPVY.mjs → dev-client-D-BW5uiq.mjs} +2 -2
- package/dist/{device-BK-zwyd_.mjs → device-CgXfbcz5.mjs} +25 -24
- package/dist/{device-capacity-DCSvUF0l.mjs → device-capacity-Cd8lMSn3.mjs} +175 -22
- package/dist/{device-BcYeHSFu.mjs → device-eeK95Lir.mjs} +16 -16
- package/dist/device-host-worker.mjs +22 -20
- package/dist/{device-ios-BLGfXQeK.mjs → device-ios-Cc9ulihb.mjs} +251 -23
- package/dist/{device-lease-run-BmvIl7bI.mjs → device-lease-run-Mtzp4THX.mjs} +5 -5
- package/dist/{device-pool-Dluix4H3.mjs → device-pool-eRz6DtCg.mjs} +3 -3
- package/dist/{doctor-Bhg1ii70.mjs → doctor-Bz_ouYAW.mjs} +28 -16
- package/dist/{doctor-Cp-BhzTS.mjs → doctor-C2QyhejJ.mjs} +1 -1
- package/dist/{doctor-fingerprint-D3a04Mhu.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +1 -1
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-watchman-BStK05nt.mjs → doctor-watchman-BTW82PDC.mjs} +5 -5
- package/dist/{doctor-OnwP94ne.mjs → doctor-xf7ht-5n.mjs} +76 -32
- package/dist/{eas-build-Dsj93iM9.mjs → eas-build-Dm6q68QY.mjs} +4 -4
- package/dist/eas-fallback-DajNpxf-.mjs +87 -0
- package/dist/{eas-session-ledger-B5vygTiD.mjs → eas-session-ledger-CBFo_Uo1.mjs} +37 -8
- package/dist/{error-diagnostics-BOOm9Db7.mjs → error-diagnostics-D1QfyJzQ.mjs} +51 -25
- package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
- package/dist/{gc-ldgr-hXU.mjs → gc-DM5oMm-J.mjs} +161 -45
- package/dist/{gc-C_79zvz4.mjs → gc-PLFwb0k4.mjs} +2 -2
- package/dist/{guide-D7K0X6KG.mjs → guide-C4I46XAk.mjs} +674 -213
- package/dist/{hosted-android-Bk54ej6n.mjs → hosted-android-DlaKLbW0.mjs} +6 -7
- package/dist/{hosted-client-fHO8yqzc.mjs → hosted-client-DDRm9hPJ.mjs} +51 -20
- package/dist/{hosted-logs-BfbmDM4M.mjs → hosted-logs-bSebOKbz.mjs} +8 -8
- package/dist/{hosted-logs-sync-B0pvmOk-.mjs → hosted-logs-sync-B0c53W_c.mjs} +5 -5
- package/dist/{hosted-macos-CPl0OZ9h.mjs → hosted-macos-B7-8Pv4H.mjs} +6 -6
- package/dist/{hosted-native-CpDB3-PO.mjs → hosted-native-CDe33CSr.mjs} +22 -18
- package/dist/{idle-shutdown-FfxL1KdG.mjs → idle-shutdown-CQ0QwU9J.mjs} +7 -8
- package/dist/{ios-WxpDJ5T1.mjs → ios-B1DYuOjh.mjs} +27 -11
- package/dist/{ios-B7-lToDu.mjs → ios-B1HvafEG.mjs} +8 -8
- package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
- package/dist/{ios-device-CsyryvpT.mjs → ios-device-B4elVFKi.mjs} +3 -3
- package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
- package/dist/{ios-project-Ty5pHl9O.mjs → ios-project-CR4mZ7CH.mjs} +22 -9
- package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
- package/dist/{ios-state-Cw7-WQf2.mjs → ios-state-BPHqMDdZ.mjs} +1 -1
- package/dist/{ios-ftxdQbJS.mjs → ios-tg4tp3q1.mjs} +94 -37
- package/dist/{js-swap-BMhXYVDS.mjs → js-swap-CVpSW1fn.mjs} +8 -7
- package/dist/{launch-DOp8RjDz.mjs → launch-DoySmhjz.mjs} +42 -38
- package/dist/lightened-DFAJgfIk.mjs +171 -0
- package/dist/{logs-s1dRIG1E.mjs → logs-BGsW7iPe.mjs} +46 -21
- package/dist/{logs-dQDki6Tt.mjs → logs-DI5ILkYB.mjs} +7 -7
- package/dist/{macos-DBBPNnIA.mjs → macos-Bo9st9Di.mjs} +73 -38
- package/dist/{macos-B0VEV3Gf.mjs → macos-C12RMJQF.mjs} +1 -1
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +7 -7
- package/dist/{metro-CjC10t6E.mjs → metro-BnhXV2Mj.mjs} +4 -4
- package/dist/{metro-gateway-B6_PgD0L.mjs → metro-request-DXyKjVDF.mjs} +26 -47
- package/dist/{named-ports-BG0j1X4g.mjs → named-ports-Phoi2POD.mjs} +3 -3
- package/dist/{native-android-CL2NGiik.mjs → native-android-vxgtLD7w.mjs} +17 -18
- package/dist/{native-gradle-artifact-inputs-btSUulme.mjs → native-gradle-artifact-inputs-BN96IVw8.mjs} +5 -5
- package/dist/{native-runtime-Dq3RBcON.mjs → native-runtime-DG4Rodzj.mjs} +9 -8
- package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
- package/dist/{native-xcode-inputs-BW7H8JGu.mjs → native-xcode-inputs-BKarCoKg.mjs} +3 -3
- package/dist/{native-xcode-ios-CBXJAxfC.mjs → native-xcode-ios-8A-efGa5.mjs} +17 -17
- package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
- package/dist/offload-worker.mjs +23 -24
- package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
- package/dist/{ownership-BjYvMNX_.mjs → ownership-DJCq48IJ.mjs} +3 -3
- package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
- package/dist/{phone-reverses-lmj6kcPm.mjs → phone-reverses-BzTa8g1F.mjs} +18 -4
- package/dist/{placement-log-DIFPQAXp.mjs → placement-log-Cvhta5ib.mjs} +3 -3
- package/dist/{plan-placement-IiiSQhtz.mjs → plan-placement-WkZdccuN.mjs} +36 -10
- package/dist/{ports-C2_w1Z0Z.mjs → ports-UV4mJgyC.mjs} +3 -3
- package/dist/{prebuild-gmouvmJZ.mjs → prebuild-k8d_tqOq.mjs} +16 -17
- package/dist/{project-BUu6Is4k.mjs → project-Sui52ywT.mjs} +17 -17
- package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
- package/dist/pull-requests.mjs +1 -1
- package/dist/{react-native-android-Cgg99REN.mjs → react-native-android-DANlGGQf.mjs} +32 -26
- package/dist/{react-native-build-oNwqF5Wb.mjs → react-native-build-jUHnIfZ9.mjs} +9 -9
- package/dist/{react-native-doctor-BhA3KUte.mjs → react-native-doctor-DCWRjS7K.mjs} +6 -6
- package/dist/{react-native-ios-B-nf4rjN.mjs → react-native-ios-BwMsFMXi.mjs} +23 -17
- package/dist/{recordings-BldzVKq0.mjs → recordings-iy0mkm7b.mjs} +1 -1
- package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
- package/dist/{reload-C9OduiNc.mjs → reload-Bj7QyuDy.mjs} +1 -1
- package/dist/{reload-CCR7KC_l.mjs → reload-c_uEyc_X.mjs} +16 -16
- package/dist/{remote-C8S7FlPF.mjs → remote-DFlpAqdV.mjs} +23 -10
- package/dist/{result-7F5hEwQJ.mjs → result-BIcXREyC.mjs} +32 -21
- package/dist/{run-BqB0v3pt.mjs → run-y2HwyNvg.mjs} +3 -3
- package/dist/{selection-BNPBZ6T5.mjs → selection-CXgM_VK_.mjs} +37 -29
- package/dist/{server-bare-A75rDIdD.mjs → server-bare-2N4vSRZG.mjs} +2 -2
- package/dist/{server-command-CssKFOD7.mjs → server-command-qneHPcRI.mjs} +6 -6
- package/dist/{server-expo-eQfOdydb.mjs → server-expo-Ccm9zB0o.mjs} +4 -4
- package/dist/server-expo-WulkyAwT.mjs +2 -0
- package/dist/{settings-CosW5X-S.mjs → settings-CY5JZlNN.mjs} +375 -62
- package/dist/{settings-OaGQF-ri.mjs → settings-Cfd_Q6ys.mjs} +24 -3
- package/dist/settings-payload-DwQiEMCn.mjs +257 -0
- package/dist/settings-write-CJpjkeAd.mjs +185 -0
- package/dist/settings.schema.json +51 -33
- package/dist/{simslim-Bax1qcxu.mjs → simslim-DCQwzoPy.mjs} +2 -2
- package/dist/{slot-launch-CYCEhfBY.mjs → slot-launch-BpmanOnk.mjs} +6 -6
- package/dist/{stage-jKQ7CP_B.mjs → stage-CmugrSG5.mjs} +2 -2
- package/dist/{start-C_wefNKB.mjs → start-CHH3zgIU.mjs} +1 -1
- package/dist/{start-_BdJ32cZ.mjs → start-DYLk6GXn.mjs} +27 -22
- package/dist/{state-C1i2nMOP.mjs → state-B2QJbDwz.mjs} +4 -4
- package/dist/{state-C4OdpOTF.mjs → state-BXC1Lfxw.mjs} +2 -2
- package/dist/{stats-tEpEEH-u.mjs → stats-DxKqhcGp.mjs} +5 -5
- package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
- package/dist/{status-CRXz-Gtj.mjs → status-7ULDEJ1e.mjs} +1 -1
- package/dist/{status-DQrqodLj.mjs → status-BHCkOZga.mjs} +51 -28
- package/dist/{status-B9M7x4CZ.mjs → status-D_Ljc89p.mjs} +1 -1
- package/dist/{status-watch-B5wDIH_o.mjs → status-watch-BmsPqYSU.mjs} +18 -7
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-6Dqp-gjX.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
- package/dist/{stop-DRqQVqDJ.mjs → stop-D-dGE9gh.mjs} +21 -20
- package/dist/{stop-ySNQHXMG.mjs → stop-DQvE-P76.mjs} +10 -6
- package/dist/{stop-CmdNhGlC.mjs → stop-b2pouxAO.mjs} +2 -2
- package/dist/supervisor-run.mjs +237 -63
- package/dist/{support-BGSCBoib.mjs → support-04IhBUTT.mjs} +6 -6
- package/dist/{support-CVOCp0Ft.mjs → support-BtlJKjyQ.mjs} +12 -11
- package/dist/{swiftpm-artifact-inputs-CfUzt_0Z.mjs → swiftpm-artifact-inputs-Cj2UpmPN.mjs} +4 -4
- package/dist/{swiftpm-macos-x6HPpl_2.mjs → swiftpm-macos-BhF2stxY.mjs} +11 -12
- package/dist/{toolchain-J4J8MrAr.mjs → toolchain-mLA_km-b.mjs} +321 -15
- package/dist/{toolchain-DoavrvIA.mjs → toolchain-qktiV8xc.mjs} +1 -1
- package/dist/{trigger-KVaWWNyn.mjs → trigger-DMou-X7j.mjs} +2 -2
- package/dist/trigger-qp2ji5wE.mjs +2 -0
- package/dist/{warm-progress-DvhTX_eu.mjs → warm-progress-B0Vpuvpl.mjs} +731 -727
- package/dist/{web-Bihbf7-u.mjs → web-BYmK0TjL.mjs} +9 -9
- package/dist/web-CrVLVQZY.mjs +2 -0
- package/dist/web-run.mjs +9 -9
- package/dist/windows-report.mjs +1 -1
- package/dist/{workspace-state-pUg3_RRA.mjs → workspace-state-kIZrdlSg.mjs} +3 -3
- package/dist/{workspaces-g2lhdBXF.mjs → workspaces-CmOcceDN.mjs} +1879 -74
- package/dist/{worktree-BKuklFh_.mjs → worktree-2dk5edza.mjs} +933 -534
- package/dist/worktree-nliAoHxB.mjs +2 -0
- package/package.json +7 -7
- package/dist/ccache-Bx5TbxwG.mjs +0 -143
- package/dist/eas-fallback-FwkeqqGi.mjs +0 -381
- package/dist/hosted-ios-D55QhYaD.mjs +0 -15
- package/dist/native-run-BfIDFKLH.mjs +0 -275
- package/dist/server-expo-wvcj5tiZ.mjs +0 -2
- package/dist/settings-write-QjYfSrjF.mjs +0 -360
- package/dist/trigger-DzJu208Q.mjs +0 -2
- package/dist/web-BFLueSh-.mjs +0 -2
- package/dist/worktree-Bm4cb-nU.mjs +0 -2
|
@@ -1,39 +1,77 @@
|
|
|
1
|
-
import { D as ownership_claim_exports, E as debugLog, S as process_identity_exports, b as operationState, c as throwIfCancelled, d as workspaceProcessLockError, l as WorkspaceProcessCleanupError, n as isTimeoutError, o as cancellableSleep, s as cancelledError, t as getExecutor, u as withWorkspaceProcessLock, y as isTermination } from "./exec-
|
|
2
|
-
import { D as workspaceId$1, E as workspaceDir, d as writeWorkspaceState, j as workspaceStateFile$1, k as workspaceLogsDir$1, l as withWorkspaceStateLockAsync,
|
|
3
|
-
import {
|
|
1
|
+
import { D as ownership_claim_exports, E as debugLog, S as process_identity_exports, b as operationState, c as throwIfCancelled, d as workspaceProcessLockError, l as WorkspaceProcessCleanupError, n as isTimeoutError, o as cancellableSleep, s as cancelledError, t as getExecutor, u as withWorkspaceProcessLock, y as isTermination } from "./exec-aULwtNly.mjs";
|
|
2
|
+
import { D as workspaceId$1, E as workspaceDir, M as withDirLock$1, b as sharedCcache$1, d as writeWorkspaceState, j as workspaceStateFile$1, k as workspaceLogsDir$1, l as withWorkspaceStateLockAsync, r as readWorkspaceState$1, t as clearWorkspaceStateKey, y as sharedBuildCache } from "./workspace-state-kIZrdlSg.mjs";
|
|
3
|
+
import { F as isOnMountedVolume, G as projectDeviceSlots, H as deviceSlotPlatforms, L as measuredDirectorySizeAsync, M as directorySize, N as directorySizeAsync, O as withConfigLockAsync$1, P as formatBytes, R as volumeRootFor, _ as loadConfig$1, a as clearDevice, d as getConfigDir, o as clearSupervisor, p as getProject } from "./config-Cn94Jc0g.mjs";
|
|
4
4
|
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
5
|
-
import { a as formatElapsed, l as phaseLine, o as formatLongDuration, s as isAppLaunchError, u as plural } from "./command-output-
|
|
6
|
-
import { a as killOnAbort, n as runOperationFileQuiet, r as childEnvironment, t as runOperationFile } from "./operation-exec-
|
|
7
|
-
import {
|
|
8
|
-
import { C as resolvePackageJson, M as readMetroTunnel, N as readPidFile, P as readRemoteSession, i as findProjectRoot$1, j as clearWorkspaceSupervisor, k as clearRemoteSession, s as ownedDeviceLabel, v as detectIsExpo } from "./project-
|
|
9
|
-
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, I as listInstalledSystemImages, J as parseAvdSystemImage, V as ownedAvdDirectory,
|
|
10
|
-
import { a as listeningPidsAsync, c as pidExists, d as resolveProjectMetro, h as isMetroRunning, r as killMetroTreeAsync, u as processCwds } from "./metro-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { i as registeredCaches } from "./cache-manifest-
|
|
5
|
+
import { a as formatElapsed, l as phaseLine, o as formatLongDuration, s as isAppLaunchError, u as plural } from "./command-output-C8R1KIvi.mjs";
|
|
6
|
+
import { a as killOnAbort, n as runOperationFileQuiet, r as childEnvironment, t as runOperationFile } from "./operation-exec-Dp4FuIGR.mjs";
|
|
7
|
+
import { Z as resolveProjectSettingsAsync, d as androidLayoutSetting, ft as planMetroReach, m as defaultAndroidLayout } from "./settings-CY5JZlNN.mjs";
|
|
8
|
+
import { C as resolvePackageJson, M as readMetroTunnel, N as readPidFile, P as readRemoteSession, i as findProjectRoot$1, j as clearWorkspaceSupervisor, k as clearRemoteSession, s as ownedDeviceLabel, v as detectIsExpo } from "./project-Sui52ywT.mjs";
|
|
9
|
+
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, I as listInstalledSystemImages, J as parseAvdSystemImage, V as ownedAvdDirectory, d as androidToolPath, dt as isStimOwnedSim, m as avdIniPaths, mt as dropParked, o as androidHome, q as parseAvdDeviceProfile, ut as isStimOwnedAvd, v as avdStorageRoots, yt as readParked } from "./android-CsPs-7Mg.mjs";
|
|
10
|
+
import { a as listeningPidsAsync, c as pidExists, d as resolveProjectMetro, h as isMetroRunning, r as killMetroTreeAsync, u as processCwds } from "./metro-BnhXV2Mj.mjs";
|
|
11
|
+
import { c as readNdjsonGenerations$1, i as createNdjsonWriter, r as createNdjsonTail } from "./ndjson-Dy2W4vRa.mjs";
|
|
12
|
+
import { T as formatSpace, a as removeEasSessionClaim, d as parseWatchRoots, f as parseWatchmanClients, i as recordEasSessionClaim, l as parseSubscriberNames, n as easMachineStateRoot$1, o as removeEasSessionClaimAsync, p as parseWatchmanPid, r as readEasSessionLedger$1, s as compareStimVersions, t as assertEasMachineRootWritable, u as parseTriggerCount, w as environmentState, y as capacity } from "./eas-session-ledger-CBFo_Uo1.mjs";
|
|
13
|
+
import { i as registeredCaches, r as register } from "./cache-manifest-DEjqGGat.mjs";
|
|
14
|
+
import { At as mapLimited, B as workspaceBuildInProgress, Dt as createGcResults, Et as GC_OUTPUT, F as collectOwnedDeviceActivityAsync, L as idleShutdownCandidates, Mt as sizeConcurrency, N as collectIdleDevicesAsync, _t as teardownParkedIosSim, bt as measureDu, dt as eraseParkedIosSim, gt as teardownParkedAvd, ht as teardownOwnedIosSim, i as clearWorkspaceOutputs, l as keptByLock, o as collectWorkspaceOutputs, pt as teardownOwnedAvd, ut as eraseParkedAvd, v as withIdleWorkspace, vt as probePublicHttp, wt as listBuildSlots, x as resolveSupervisorTarget, xt as writeUsageCache, yt as canonical$1, z as shutDownIdleDevices } from "./workspaces-CmOcceDN.mjs";
|
|
14
15
|
import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { A as uninstallIosApp, O as sanitizeDeviceLabel, U as deviceHoldsApk, W as deviceHoldsBundle, b as parseSimctlList, f as listAllIosSimsAsync, g as listUserApps, p as listIosDeviceTypesAsync, u as iosSimulatorFailureAdvice, y as parseRuntimeVersion } from "./ios-WxpDJ5T1.mjs";
|
|
16
|
+
import { lt as claimForEmptying, ot as runCancellationSignal, rt as nativeRunWaitNotice } from "./toolchain-mLA_km-b.mjs";
|
|
17
|
+
import { N as listBuildLocks, b as leaseIsExpired, g as workspaceActivity, o as envDir, p as readHostProcessTableAsync, x as listLeaseFiles } from "./activity-DRMg4_mD.mjs";
|
|
18
|
+
import { l as expoConfigContents } from "./build-cache-CZULpXVl.mjs";
|
|
19
|
+
import { G as deviceHoldsBundle, O as sanitizeDeviceLabel, W as deviceHoldsApk, b as parseSimctlList, f as listAllIosSimsAsync, g as listUserApps, j as uninstallIosApp, p as listIosDeviceTypesAsync, u as iosSimulatorFailureAdvice, y as parseRuntimeVersion } from "./ios-B1DYuOjh.mjs";
|
|
20
20
|
import { n as supervisorError } from "./errors-DHm_U5gv.mjs";
|
|
21
|
-
import { c as findBinUpward, n as expoBinFromPackage, r as expoBinPath, s as expoTelemetryEnv } from "./server-expo-
|
|
22
|
-
import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-
|
|
21
|
+
import { c as findBinUpward, n as expoBinFromPackage, r as expoBinPath, s as expoTelemetryEnv } from "./server-expo-Ccm9zB0o.mjs";
|
|
22
|
+
import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-CiBA-er9.mjs";
|
|
23
23
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
24
24
|
import { createRequire } from "node:module";
|
|
25
|
-
import { randomUUID } from "node:crypto";
|
|
25
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
26
26
|
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, statfsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
27
27
|
import { homedir, platform, totalmem } from "node:os";
|
|
28
28
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
29
29
|
import { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, ambientContext, cacheDirRefusal, compiledHelper, configDir, ensurePrivateDir, rotatedLogPath, withAmbientContext, withDirLock } from "@stim-cli/core";
|
|
30
|
-
import {
|
|
30
|
+
import { DEV_SERVER_STOP_REQUEST_KEY, MACHINE_OWNER_KINDS, MAINTENANCE_LOG_NAME, budgetSweepFile, budgetSweepLock, buildWorkerRoot, gcLogFile, isJsonObject, loadConfig, machineCacheUsageFile, maintenanceNdjsonFile, readDevServerStop, readDevServerStopRequest, readJsonObject, readMachineCacheUsage, runId, settingDefinition, settingValueError, workspaceLogsDir } from "@stim-cli/core/state";
|
|
31
31
|
import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
|
|
32
32
|
import { fileURLToPath } from "node:url";
|
|
33
33
|
import chalk from "chalk";
|
|
34
34
|
import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
|
|
35
35
|
import { access, lstat, readFile, readdir, rm, stat, statfs } from "node:fs/promises";
|
|
36
36
|
import { homedir as homedir$1, tmpdir as tmpdir$1 } from "os";
|
|
37
|
+
//#region src/budget-sweep.ts
|
|
38
|
+
const EMPTY_SWEEP_WINDOW_MS = 3e5;
|
|
39
|
+
function sweepMarker(caches, olderThanDays) {
|
|
40
|
+
const hash = createHash("sha256").update(String(olderThanDays));
|
|
41
|
+
for (const line of caches.map((cache) => `${cache.name}\0${cache.dir}`).toSorted()) hash.update("\n").update(line);
|
|
42
|
+
return hash.digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function canSkipEmptySweep(recorded, now) {
|
|
45
|
+
if (!recorded || recorded.marker !== now.marker) return false;
|
|
46
|
+
const age = now.at - recorded.at;
|
|
47
|
+
return age >= 0 && age < 3e5 && recorded.freeMb - now.freeMb <= 1024;
|
|
48
|
+
}
|
|
49
|
+
function readEmptySweep() {
|
|
50
|
+
const value = readJsonObject(budgetSweepFile());
|
|
51
|
+
if (!value) return null;
|
|
52
|
+
const { at, freeMb, marker } = value;
|
|
53
|
+
return typeof at === "number" && Number.isFinite(at) && typeof freeMb === "number" && Number.isFinite(freeMb) && typeof marker === "string" ? {
|
|
54
|
+
at,
|
|
55
|
+
freeMb,
|
|
56
|
+
marker
|
|
57
|
+
} : null;
|
|
58
|
+
}
|
|
59
|
+
function writeEmptySweep(sweep) {
|
|
60
|
+
const file = budgetSweepFile();
|
|
61
|
+
try {
|
|
62
|
+
mkdirSync(dirname(file), {
|
|
63
|
+
recursive: true,
|
|
64
|
+
mode: 448
|
|
65
|
+
});
|
|
66
|
+
withDirLock$1(budgetSweepLock(), () => {
|
|
67
|
+
if (!sweep) return rmSync(file, { force: true });
|
|
68
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
69
|
+
writeFileSync(tmp, JSON.stringify(sweep), { mode: 384 });
|
|
70
|
+
renameSync(tmp, file);
|
|
71
|
+
});
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
37
75
|
//#region src/cache/caches.ts
|
|
38
76
|
function xcodeDerivedDataRoot(env) {
|
|
39
77
|
return join$1(env.HOME || env.USERPROFILE || homedir$1(), "Library", "Developer", "Xcode", "DerivedData");
|
|
@@ -204,17 +242,15 @@ function canonicalCacheDir(dir) {
|
|
|
204
242
|
}
|
|
205
243
|
const CACHE_SIZE_TIMEOUT_MS = 6e4;
|
|
206
244
|
async function sizeCaches(caches, operation) {
|
|
207
|
-
|
|
208
|
-
for (const cache of caches) {
|
|
245
|
+
return mapLimited(caches, sizeConcurrency(operation), async (cache) => {
|
|
209
246
|
operation?.signal.throwIfAborted();
|
|
210
247
|
const bytes = cache.bytes ?? await measuredDirectorySizeAsync(cache.dir, {
|
|
211
248
|
timeoutMs: CACHE_SIZE_TIMEOUT_MS,
|
|
212
249
|
operation,
|
|
213
250
|
signal: operation?.signal
|
|
214
251
|
});
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
return sized;
|
|
252
|
+
return Object.assign({}, cache, bytes === null ? { sizeError: "Size unavailable: measurement failed or exceeded 60 seconds." } : { bytes });
|
|
253
|
+
});
|
|
218
254
|
}
|
|
219
255
|
function pruneCache(cache, { olderThanDays, now = Date.now(), protect, evictBytes, byMtime = false } = {}) {
|
|
220
256
|
const cutoff = now - olderThanDays * 24 * 60 * 60 * 1e3;
|
|
@@ -296,18 +332,22 @@ async function pruneCacheAsync(cache, { olderThanDays, now = Date.now(), signal,
|
|
|
296
332
|
};
|
|
297
333
|
const cutoff = now - olderThanDays * 24 * 60 * 60 * 1e3;
|
|
298
334
|
let entries = cache.files ?? [cache.dir];
|
|
335
|
+
let unlisted = 0;
|
|
299
336
|
for (let depth = 0; !cache.files && depth < (cache.entriesDepth ?? 1); depth++) {
|
|
300
337
|
const next = [];
|
|
301
338
|
for (const parent of entries) {
|
|
302
339
|
signal?.throwIfAborted();
|
|
303
|
-
const names = await readdir(parent).catch(() =>
|
|
340
|
+
const names = await readdir(parent).catch((error) => {
|
|
341
|
+
if (error.code !== "ENOENT" && error.code !== "ENOTDIR") unlisted++;
|
|
342
|
+
return [];
|
|
343
|
+
});
|
|
304
344
|
next.push(...names.map((name) => join$1(parent, name)));
|
|
305
345
|
}
|
|
306
346
|
entries = next;
|
|
307
347
|
}
|
|
308
348
|
let removed = 0;
|
|
309
349
|
let bytes = 0;
|
|
310
|
-
let failed =
|
|
350
|
+
let failed = unlisted;
|
|
311
351
|
for (const entry of entries) {
|
|
312
352
|
signal?.throwIfAborted();
|
|
313
353
|
try {
|
|
@@ -2983,9 +3023,32 @@ async function launchedIosAppAfterNoHandle(error, udid, bundleId, exec) {
|
|
|
2983
3023
|
}
|
|
2984
3024
|
async function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, devMenuParams = false, consolePaths }, { exec = null } = {}) {
|
|
2985
3025
|
const e = exec || getExecutor();
|
|
2986
|
-
const running = await iosAppProcess(udid, bundleId, { exec: e });
|
|
2987
|
-
const stateUnknown = running.state === "unknown";
|
|
2988
3026
|
const launchRestarts = metroPort === null || !devClientScheme || Boolean(consolePaths);
|
|
3027
|
+
const writeJsLocation = async (port) => {
|
|
3028
|
+
try {
|
|
3029
|
+
await e.runFileAsync("xcrun", [
|
|
3030
|
+
"simctl",
|
|
3031
|
+
"spawn",
|
|
3032
|
+
udid,
|
|
3033
|
+
"defaults",
|
|
3034
|
+
"write",
|
|
3035
|
+
bundleId,
|
|
3036
|
+
"RCT_jsLocation",
|
|
3037
|
+
jsLocationValue(port)
|
|
3038
|
+
], { timeoutMs: 6e4 });
|
|
3039
|
+
return null;
|
|
3040
|
+
} catch (err) {
|
|
3041
|
+
return {
|
|
3042
|
+
failed: true,
|
|
3043
|
+
code: LAUNCH_ERROR,
|
|
3044
|
+
reason: `Could not point ${bundleId} at Metro port ${port} (defaults write RCT_jsLocation): ${await describeIosSimulatorFailure(err, e)}`
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
const runningProbe = iosAppProcess(udid, bundleId, { exec: e });
|
|
3049
|
+
const earlyWrite = metroPort !== null && launchRestarts ? writeJsLocation(metroPort) : null;
|
|
3050
|
+
const running = await runningProbe;
|
|
3051
|
+
const stateUnknown = running.state === "unknown";
|
|
2989
3052
|
const launchArgs = [
|
|
2990
3053
|
"simctl",
|
|
2991
3054
|
"launch",
|
|
@@ -3014,24 +3077,8 @@ async function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null,
|
|
|
3014
3077
|
restart.restartedPid = running.pid;
|
|
3015
3078
|
}
|
|
3016
3079
|
if (metroPort !== null) {
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
"simctl",
|
|
3020
|
-
"spawn",
|
|
3021
|
-
udid,
|
|
3022
|
-
"defaults",
|
|
3023
|
-
"write",
|
|
3024
|
-
bundleId,
|
|
3025
|
-
"RCT_jsLocation",
|
|
3026
|
-
jsLocationValue(metroPort)
|
|
3027
|
-
], { timeoutMs: 6e4 });
|
|
3028
|
-
} catch (err) {
|
|
3029
|
-
return {
|
|
3030
|
-
failed: true,
|
|
3031
|
-
code: LAUNCH_ERROR,
|
|
3032
|
-
reason: `Could not point ${bundleId} at Metro port ${metroPort} (defaults write RCT_jsLocation): ${await describeIosSimulatorFailure(err, e)}`
|
|
3033
|
-
};
|
|
3034
|
-
}
|
|
3080
|
+
const writeFailure = await (earlyWrite ?? writeJsLocation(metroPort));
|
|
3081
|
+
if (writeFailure) return writeFailure;
|
|
3035
3082
|
if (devClientScheme) {
|
|
3036
3083
|
const url = devClientUrl(devClientScheme, metroPort, "localhost", { devMenuParams });
|
|
3037
3084
|
const viaInitialUrl = Boolean(consolePaths) || stateUnknown;
|
|
@@ -3738,6 +3785,43 @@ function jsRunningFields(jsRunningAt) {
|
|
|
3738
3785
|
function expoBundleLine(msg) {
|
|
3739
3786
|
return /\bBundl(?:ing|ed)\b/.test(msg);
|
|
3740
3787
|
}
|
|
3788
|
+
function createCrashProbe({ firstAt, everyMs, now, run }) {
|
|
3789
|
+
let nextAt = firstAt;
|
|
3790
|
+
let pending = null;
|
|
3791
|
+
let outcome = null;
|
|
3792
|
+
const consume = () => {
|
|
3793
|
+
const done = outcome;
|
|
3794
|
+
if (!done) return null;
|
|
3795
|
+
pending = null;
|
|
3796
|
+
outcome = null;
|
|
3797
|
+
if ("error" in done) throw done.error;
|
|
3798
|
+
return done.result;
|
|
3799
|
+
};
|
|
3800
|
+
return {
|
|
3801
|
+
get pending() {
|
|
3802
|
+
return pending;
|
|
3803
|
+
},
|
|
3804
|
+
poll() {
|
|
3805
|
+
const found = consume();
|
|
3806
|
+
if (found) return found;
|
|
3807
|
+
if (!pending && now() >= nextAt) {
|
|
3808
|
+
nextAt = now() + everyMs;
|
|
3809
|
+
pending = (async () => {
|
|
3810
|
+
try {
|
|
3811
|
+
outcome = { result: await run() };
|
|
3812
|
+
} catch (error) {
|
|
3813
|
+
outcome = { error };
|
|
3814
|
+
}
|
|
3815
|
+
})();
|
|
3816
|
+
}
|
|
3817
|
+
return null;
|
|
3818
|
+
},
|
|
3819
|
+
async settle() {
|
|
3820
|
+
await pending;
|
|
3821
|
+
return consume();
|
|
3822
|
+
}
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3741
3825
|
async function nativeLaunchFailure({ readCrashes, since, platform, processAlive, mode, waitedMs }) {
|
|
3742
3826
|
if (!readCrashes) return null;
|
|
3743
3827
|
const crashes = (await readCrashes()).filter((record) => record.event === "native_crash" && after(record, since) && recordCouldBelongToPlatform(record, platform));
|
|
@@ -3763,15 +3847,18 @@ function manifestDeadline(records, { startedAt, timeoutMs }) {
|
|
|
3763
3847
|
if (open.size > 0) return cap;
|
|
3764
3848
|
return servedAt === null ? base : Math.min(cap, Math.max(base, servedAt + MANIFEST_GRACE_MS));
|
|
3765
3849
|
}
|
|
3766
|
-
async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, onActivity, deviceLogsThrough, now = Date.now, sleep = (ms) =>
|
|
3850
|
+
async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, onActivity, deviceLogsThrough, now = Date.now, signal, sleep = (ms) => cancellableSleep(ms, {
|
|
3851
|
+
signal,
|
|
3852
|
+
what: "launch readiness check"
|
|
3853
|
+
}) } = {}) {
|
|
3767
3854
|
const delivered = (record) => deliveryOwner(record, {
|
|
3768
3855
|
slot,
|
|
3769
3856
|
appPid,
|
|
3770
3857
|
platformShared
|
|
3771
3858
|
}) === "this";
|
|
3772
|
-
const read = readRecords || (
|
|
3773
|
-
const readDevice = readDeviceRecords || (
|
|
3774
|
-
const readClient = readClientRecords || (
|
|
3859
|
+
const read = readRecords || tailNdjson(logsDir, "metro.ndjson");
|
|
3860
|
+
const readDevice = readDeviceRecords || tailNdjson(logsDir, "device.ndjson");
|
|
3861
|
+
const readClient = readClientRecords || tailNdjson(logsDir, "client.ndjson");
|
|
3775
3862
|
const deviceNow = () => {
|
|
3776
3863
|
const at = now();
|
|
3777
3864
|
return deviceLogsThrough ? Math.max(Math.min(at, deviceLogsThrough() ?? -Infinity), at - DEVICE_LOG_LAG_LIMIT_MS) : at;
|
|
@@ -3786,7 +3873,19 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
|
|
|
3786
3873
|
let deliveryId = null;
|
|
3787
3874
|
let runtimeLoadingAt = null;
|
|
3788
3875
|
let runtimeStartedAt = null;
|
|
3789
|
-
|
|
3876
|
+
const crashProbe = createCrashProbe({
|
|
3877
|
+
firstAt: startedAt + 1e3,
|
|
3878
|
+
everyMs: 2e3,
|
|
3879
|
+
now,
|
|
3880
|
+
run: () => nativeLaunchFailure({
|
|
3881
|
+
readCrashes: readNativeCrashes,
|
|
3882
|
+
since,
|
|
3883
|
+
platform,
|
|
3884
|
+
processAlive,
|
|
3885
|
+
mode,
|
|
3886
|
+
waitedMs: 0
|
|
3887
|
+
})
|
|
3888
|
+
});
|
|
3790
3889
|
let bundlingAt = null;
|
|
3791
3890
|
let reported = null;
|
|
3792
3891
|
const report = (name, at) => {
|
|
@@ -3794,131 +3893,149 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
|
|
|
3794
3893
|
reported = name;
|
|
3795
3894
|
onActivity?.(name, at);
|
|
3796
3895
|
};
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
if (now() >= nextCrashCheck) {
|
|
3807
|
-
nextCrashCheck = now() + 2e3;
|
|
3808
|
-
const crash = await nativeLaunchFailure({
|
|
3809
|
-
readCrashes: readNativeCrashes,
|
|
3810
|
-
since,
|
|
3811
|
-
platform,
|
|
3812
|
-
processAlive,
|
|
3813
|
-
mode,
|
|
3814
|
-
waitedMs: now() - startedAt
|
|
3896
|
+
const loop = async () => {
|
|
3897
|
+
while (true) {
|
|
3898
|
+
const metroRecords = read().filter((record) => after(record, since));
|
|
3899
|
+
const bundleRecords = metroRecords.filter((record) => (!requireBundleResponse || String(record.event).startsWith("bundle_response_")) && delivered(record));
|
|
3900
|
+
const deviceRecords = readDevice().filter((record) => after(record, since) && (slot === void 0 || (record.slot ?? "default") === slot));
|
|
3901
|
+
const clientRecords = readClient().filter((record) => after(record, since) && !platformShared);
|
|
3902
|
+
bundleDeadline = manifestDeadline(metroRecords.filter((record) => String(record.event).startsWith("manifest_request_") && (!platform || record.platform === platform)), {
|
|
3903
|
+
startedAt,
|
|
3904
|
+
timeoutMs: baseTimeoutMs
|
|
3815
3905
|
});
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3906
|
+
const crash = crashProbe.poll();
|
|
3907
|
+
if (crash) return {
|
|
3908
|
+
...crash,
|
|
3909
|
+
waitedMs: now() - startedAt
|
|
3910
|
+
};
|
|
3911
|
+
if (deliveryId === null) {
|
|
3912
|
+
const request = bundleRecords.find((record) => record.event === "bundle_response_started" && typeof record.requestId === "string" && isBundleProof(record, since, platform));
|
|
3913
|
+
if (request) {
|
|
3914
|
+
deliveryId = request.requestId;
|
|
3915
|
+
bundlingAt = request;
|
|
3916
|
+
proof = null;
|
|
3917
|
+
stabilityDeadline = null;
|
|
3918
|
+
}
|
|
3825
3919
|
}
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3920
|
+
for (const record of bundleRecords) {
|
|
3921
|
+
if (isBundleProof(record, since, platform)) activity = record;
|
|
3922
|
+
const completed = deliveryId === null ? isBundleReadyProof(record, since, platform) : record.event === "bundle_response_finished" && record.requestId === deliveryId && isBundleProof(record, since, platform);
|
|
3923
|
+
if (!proof && completed) {
|
|
3924
|
+
proof = record;
|
|
3925
|
+
stabilityDeadline = Number(record.ts) + Math.max(0, stabilityMs);
|
|
3926
|
+
}
|
|
3833
3927
|
}
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
if (loading) runtimeLoadingAt = Number(loading.ts);
|
|
3839
|
-
}
|
|
3840
|
-
if (runtimeLoadingAt !== null && runtimeStartedAt === null) {
|
|
3841
|
-
const executing = signals.find((record) => record.src === "device" && record.platform === "android" && Number(record.ts) >= runtimeLoadingAt && (/^ReactNativeJS\(\d+\)$/.test(String(record.proc)) || appReadinessSignal(record, platform) !== null));
|
|
3842
|
-
if (executing) runtimeStartedAt = Number(executing.ts);
|
|
3843
|
-
}
|
|
3844
|
-
const runtimeWaiting = runtimeLoadingAt !== null && runtimeStartedAt === null;
|
|
3845
|
-
const completedAt = proof ? Math.max(Number(proof.ts), runtimeStartedAt ?? 0) : null;
|
|
3846
|
-
if (completedAt !== null) stabilityDeadline = completedAt + Math.max(0, stabilityMs);
|
|
3847
|
-
const jsRunningAt = jsRunningSince(signals, completedAt, runtimeWaiting, platform);
|
|
3848
|
-
const windowEnd = settledWindowEnd(stabilityDeadline, jsRunningAt);
|
|
3849
|
-
const readinessDeadline = completedAt !== null ? completedAt + APP_READINESS_TIMEOUT_MS : bundleDeadline;
|
|
3850
|
-
if (pendingAt === null) {
|
|
3851
|
-
const pending = signals.find((record) => appReadinessSignal(record, platform) === "pending" && (runtimeWaiting || stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3852
|
-
if (pending) {
|
|
3853
|
-
pendingAt = Number(pending.ts);
|
|
3854
|
-
onReadinessPending?.();
|
|
3928
|
+
const signals = deviceRecords.filter((record) => Number(record.ts) <= now()).toSorted((a, b) => Number(a.ts) - Number(b.ts));
|
|
3929
|
+
if (platform === "android" && runtimeLoadingAt === null) {
|
|
3930
|
+
const loading = signals.find((record) => record.src === "device" && record.platform === "android" && /^(?:unknown:)?BridgelessReact\(\d+\)$/.test(String(record.proc)) && /^ReactHost\{\d+\}\.getOrCreateReactInstanceTask\(\): Loading JS Bundle$/.test(String(record.msg)) && (stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3931
|
+
if (loading) runtimeLoadingAt = Number(loading.ts);
|
|
3855
3932
|
}
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
const
|
|
3862
|
-
|
|
3863
|
-
const
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3933
|
+
if (runtimeLoadingAt !== null && runtimeStartedAt === null) {
|
|
3934
|
+
const executing = signals.find((record) => record.src === "device" && record.platform === "android" && Number(record.ts) >= runtimeLoadingAt && (/^ReactNativeJS\(\d+\)$/.test(String(record.proc)) || appReadinessSignal(record, platform) !== null));
|
|
3935
|
+
if (executing) runtimeStartedAt = Number(executing.ts);
|
|
3936
|
+
}
|
|
3937
|
+
const runtimeWaiting = runtimeLoadingAt !== null && runtimeStartedAt === null;
|
|
3938
|
+
const completedAt = proof ? Math.max(Number(proof.ts), runtimeStartedAt ?? 0) : null;
|
|
3939
|
+
if (completedAt !== null) stabilityDeadline = completedAt + Math.max(0, stabilityMs);
|
|
3940
|
+
const jsRunningAt = jsRunningSince(signals, completedAt, runtimeWaiting, platform);
|
|
3941
|
+
const windowEnd = settledWindowEnd(stabilityDeadline, jsRunningAt);
|
|
3942
|
+
const readinessDeadline = completedAt !== null ? completedAt + APP_READINESS_TIMEOUT_MS : bundleDeadline;
|
|
3943
|
+
if (pendingAt === null) {
|
|
3944
|
+
const pending = signals.find((record) => appReadinessSignal(record, platform) === "pending" && (runtimeWaiting || stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3945
|
+
if (pending) {
|
|
3946
|
+
pendingAt = Number(pending.ts);
|
|
3947
|
+
onReadinessPending?.();
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
report(...launchActivity(pendingAt, proof, bundlingAt));
|
|
3951
|
+
const ready = pendingAt !== null && signals.some((record) => Number(record.ts) >= pendingAt && Number(record.ts) <= readinessDeadline && appReadinessSignal(record, platform) === "ready");
|
|
3952
|
+
const bundleErrors = bundleRecords.filter((record) => isFatalLaunchError(record, platform) || deliveryId !== null && record.event === "bundle_response_failed" && record.requestId === deliveryId && isBundleProof(record, since, platform));
|
|
3953
|
+
if (bundleErrors.length) {
|
|
3954
|
+
const alive = processAlive ? await processAlive() : null;
|
|
3955
|
+
const fatalRecord = bundleErrors[bundleErrors.length - 1];
|
|
3956
|
+
const fatalAt = Number(fatalRecord?.ts ?? since ?? 0);
|
|
3957
|
+
return {
|
|
3958
|
+
verified: false,
|
|
3959
|
+
fatal: true,
|
|
3960
|
+
errors: metroRecords.filter((record) => after(record, fatalAt) && recordCouldBelongToPlatform(record, platform) && isLaunchError(record, platform)),
|
|
3961
|
+
processAlive: alive,
|
|
3962
|
+
record: fatalRecord,
|
|
3963
|
+
mode,
|
|
3964
|
+
waitedMs: now() - startedAt,
|
|
3965
|
+
...pendingAt !== null ? { readiness: "error" } : {}
|
|
3966
|
+
};
|
|
3967
|
+
}
|
|
3968
|
+
if (proof && windowEnd !== null && (pendingAt !== null || deviceNow() >= windowEnd)) {
|
|
3969
|
+
const errorSince = pendingAt === null ? Number(proof.ts ?? since ?? 0) : Number(since ?? 0);
|
|
3970
|
+
const errors = [
|
|
3971
|
+
...metroRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform)),
|
|
3972
|
+
...deviceRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform)),
|
|
3973
|
+
...clientRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform))
|
|
3974
|
+
].filter((record) => isLaunchError(record, platform));
|
|
3975
|
+
const alive = processAlive ? await processAlive() : null;
|
|
3976
|
+
const waitedMs = now() - startedAt;
|
|
3977
|
+
if (alive === false) return {
|
|
3978
|
+
verified: false,
|
|
3979
|
+
fatal: true,
|
|
3980
|
+
errors,
|
|
3981
|
+
processAlive: alive,
|
|
3982
|
+
record: proof,
|
|
3983
|
+
mode,
|
|
3984
|
+
waitedMs,
|
|
3985
|
+
...pendingAt !== null ? { readiness: "error" } : {}
|
|
3986
|
+
};
|
|
3987
|
+
const actionableErrors = errors.filter((record) => !isIosConnectionRefusal(record, platform));
|
|
3988
|
+
const appErrors = actionableErrors.some(isAppLaunchError);
|
|
3989
|
+
if (!runtimeWaiting && pendingAt === null || appErrors || ready || deviceNow() >= readinessDeadline) return {
|
|
3990
|
+
verified: true,
|
|
3991
|
+
record: proof,
|
|
3992
|
+
errors: actionableErrors,
|
|
3993
|
+
processAlive: alive,
|
|
3994
|
+
mode,
|
|
3995
|
+
waitedMs,
|
|
3996
|
+
...pendingAt !== null ? { readiness: appErrors ? "error" : ready ? "ready" : "timed-out" } : {},
|
|
3997
|
+
...jsRunningFields(jsRunningAt)
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
if ((!proof || runtimeWaiting) && now() >= bundleDeadline) return await bundleTimeoutOutcome({
|
|
4001
|
+
requested: findBundleRequest(deviceRecords, since, metroPort, platform) ?? activity,
|
|
4002
|
+
unattributed: metroRecords.find((record) => record.event === "bundle_response_finished" && deliveryOwner(record, {
|
|
4003
|
+
slot,
|
|
4004
|
+
appPid,
|
|
4005
|
+
platformShared
|
|
4006
|
+
}) === "unknown" && isBundleProof(record, since, platform)) ?? null,
|
|
4007
|
+
processAlive,
|
|
4008
|
+
deviceRecords,
|
|
4009
|
+
platform,
|
|
3901
4010
|
mode,
|
|
3902
|
-
waitedMs
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
4011
|
+
waitedMs: now() - startedAt
|
|
4012
|
+
});
|
|
4013
|
+
const nap = sleep(Math.min(pollMs, Math.max(0, (runtimeWaiting ? bundleDeadline : proof && pendingAt !== null ? readinessDeadline : windowEnd ?? bundleDeadline) - deviceNow())));
|
|
4014
|
+
await (crashProbe.pending ? Promise.race([nap, crashProbe.pending]) : nap);
|
|
3906
4015
|
}
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
processAlive,
|
|
3915
|
-
deviceRecords,
|
|
3916
|
-
platform,
|
|
3917
|
-
mode,
|
|
3918
|
-
waitedMs: now() - startedAt
|
|
3919
|
-
});
|
|
3920
|
-
await sleep(Math.min(pollMs, Math.max(0, (runtimeWaiting ? bundleDeadline : proof && pendingAt !== null ? readinessDeadline : windowEnd ?? bundleDeadline) - deviceNow())));
|
|
4016
|
+
};
|
|
4017
|
+
let result;
|
|
4018
|
+
try {
|
|
4019
|
+
result = await loop();
|
|
4020
|
+
} catch (error) {
|
|
4021
|
+
await crashProbe.settle().catch(() => {});
|
|
4022
|
+
throw error;
|
|
3921
4023
|
}
|
|
4024
|
+
const probed = crashProbe.pending !== null;
|
|
4025
|
+
const late = await crashProbe.settle();
|
|
4026
|
+
if (late) return {
|
|
4027
|
+
...late,
|
|
4028
|
+
waitedMs: now() - startedAt
|
|
4029
|
+
};
|
|
4030
|
+
if (probed && result.verified && await processAlive?.() === false) return {
|
|
4031
|
+
...result,
|
|
4032
|
+
verified: false,
|
|
4033
|
+
fatal: true,
|
|
4034
|
+
processAlive: false,
|
|
4035
|
+
waitedMs: now() - startedAt,
|
|
4036
|
+
...result.readiness ? { readiness: "error" } : {}
|
|
4037
|
+
};
|
|
4038
|
+
return result;
|
|
3922
4039
|
}
|
|
3923
4040
|
function launchActivity(pendingAt, proof, bundling) {
|
|
3924
4041
|
if (pendingAt !== null) return ["waiting-ready", pendingAt];
|
|
@@ -4012,6 +4129,9 @@ function readCollectorRecords(logsDir) {
|
|
|
4012
4129
|
function readNdjson(logsDir, name) {
|
|
4013
4130
|
return logsDir ? readNdjsonGenerations$1(join(logsDir, name)) : [];
|
|
4014
4131
|
}
|
|
4132
|
+
function tailNdjson(logsDir, name) {
|
|
4133
|
+
return logsDir ? createNdjsonTail(join(logsDir, name)) : () => [];
|
|
4134
|
+
}
|
|
4015
4135
|
function unattributedLaunchLines({ platform, metroPort, slot = "default", siblings }) {
|
|
4016
4136
|
const others = siblings.length === 1 ? `Slot ${siblings[0]} also runs` : `Slots ${siblings.join(", ")} also run`;
|
|
4017
4137
|
return [
|
|
@@ -6214,11 +6334,11 @@ function directories(dir, notices) {
|
|
|
6214
6334
|
}
|
|
6215
6335
|
function scopedOutside(gradleHome, env) {
|
|
6216
6336
|
if (!deviceSweepIsScoped(env)) return false;
|
|
6217
|
-
const rel = relative(canonical(getConfigDir()), gradleHome);
|
|
6337
|
+
const rel = relative(canonical$1(getConfigDir()), gradleHome);
|
|
6218
6338
|
return rel === "" || rel.startsWith("..") || isAbsolute(rel);
|
|
6219
6339
|
}
|
|
6220
6340
|
function gradleUserHome(env, cwd) {
|
|
6221
|
-
return canonical(envDir("GRADLE_USER_HOME", env, cwd) ?? join(env?.HOME || env?.USERPROFILE || homedir(), ".gradle"));
|
|
6341
|
+
return canonical$1(envDir("GRADLE_USER_HOME", env, cwd) ?? join(env?.HOME || env?.USERPROFILE || homedir(), ".gradle"));
|
|
6222
6342
|
}
|
|
6223
6343
|
/** Each Gradle version's `caches/<version>` and `wrapper/dists/gradle-<version>-*` directories under `gradleHome`. */
|
|
6224
6344
|
function gradleVersionDirs(gradleHome, notices) {
|
|
@@ -7127,7 +7247,7 @@ async function emptyCache(cache, signal, operation) {
|
|
|
7127
7247
|
}
|
|
7128
7248
|
function reportFailures(cache, failed, { log, record, fail }) {
|
|
7129
7249
|
if (!failed) return false;
|
|
7130
|
-
const message = `${failed} entr${failed === 1 ? "y" : "ies"} in ${cache.dir} could not be removed`;
|
|
7250
|
+
const message = `${failed} entr${failed === 1 ? "y" : "ies"} in ${cache.dir} could not be read or removed`;
|
|
7131
7251
|
log(chalk.red(`${cache.name}: ${message}`));
|
|
7132
7252
|
record("cache", "failed", cache.name, {
|
|
7133
7253
|
id: cache.dir,
|
|
@@ -7141,6 +7261,7 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7141
7261
|
let cacheBytes = 0;
|
|
7142
7262
|
let failures = 0;
|
|
7143
7263
|
const trimmed = [];
|
|
7264
|
+
let unchanged = 0;
|
|
7144
7265
|
for (const c of caches) {
|
|
7145
7266
|
signal?.throwIfAborted();
|
|
7146
7267
|
if (c.machineGlobal) {
|
|
@@ -7170,9 +7291,10 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7170
7291
|
bytes: r.bytes
|
|
7171
7292
|
});
|
|
7172
7293
|
log(chalk.green(`Trimmed ${c.name}: ${r.removed} entr${r.removed === 1 ? "y" : "ies"} (${formatBytes(r.bytes)})`));
|
|
7173
|
-
} else if (!r.failed)
|
|
7294
|
+
} else if (!r.failed) unchanged++;
|
|
7174
7295
|
if (reportFailures(c, r.failed, output)) failures++;
|
|
7175
7296
|
}
|
|
7297
|
+
if (unchanged) log(chalk.dim(`${unchanged} cache${unchanged === 1 ? "" : "s"}: nothing older than ${olderThan}d`));
|
|
7176
7298
|
if (cacheBytes) log(chalk.dim(`Trimmed ${formatBytes(cacheBytes)} of shared cache. The next build that wanted those entries pays to rebuild them.`));
|
|
7177
7299
|
return {
|
|
7178
7300
|
trimmed,
|
|
@@ -7182,6 +7304,7 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7182
7304
|
async function emptyCaches(caches, output = GC_OUTPUT, signal, operation) {
|
|
7183
7305
|
const { log, record } = output;
|
|
7184
7306
|
let cacheBytes = 0;
|
|
7307
|
+
let failures = 0;
|
|
7185
7308
|
for (const c of caches) {
|
|
7186
7309
|
signal?.throwIfAborted();
|
|
7187
7310
|
if (!c.willEmpty) {
|
|
@@ -7207,1431 +7330,86 @@ async function emptyCaches(caches, output = GC_OUTPUT, signal, operation) {
|
|
|
7207
7330
|
});
|
|
7208
7331
|
log(chalk.green(`Emptied ${c.name}: ${r.removed} entr${r.removed === 1 ? "y" : "ies"} (${formatBytes(r.bytes)})`));
|
|
7209
7332
|
} else if (!r.failed) log(chalk.dim(`${c.name}: already empty`));
|
|
7210
|
-
reportFailures(c, r.failed, output)
|
|
7333
|
+
if (reportFailures(c, r.failed, output)) failures++;
|
|
7211
7334
|
}
|
|
7212
7335
|
if (cacheBytes) log(chalk.dim(`Emptied ${formatBytes(cacheBytes)} of shared cache. Every build that wanted any of it now pays to rebuild it.`));
|
|
7336
|
+
return failures;
|
|
7213
7337
|
}
|
|
7214
7338
|
//#endregion
|
|
7215
|
-
//#region src/
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
}
|
|
7224
|
-
function updateStats(record, run, now) {
|
|
7225
|
-
const at = new Date(now).toISOString();
|
|
7226
|
-
const durationMs = wholeMs(run.durationMs);
|
|
7227
|
-
const phases = {
|
|
7228
|
-
coldBuildMs: wholeMs(run.coldBuildMs),
|
|
7229
|
-
podsMs: wholeMs(run.podsMs)
|
|
7230
|
-
};
|
|
7231
|
-
const projects = { ...record.projects };
|
|
7232
|
-
const scope = { ...projects[run.projectKey] };
|
|
7233
|
-
const machine = { ...record.machine };
|
|
7234
|
-
const before = scope[run.platform] ?? null;
|
|
7235
|
-
const credit = creditMs(before, run, durationMs);
|
|
7236
|
-
scope[run.platform] = applyRun(before, run, {
|
|
7237
|
-
at,
|
|
7238
|
-
durationMs,
|
|
7239
|
-
credit,
|
|
7240
|
-
phases
|
|
7241
|
-
});
|
|
7242
|
-
projects[run.projectKey] = scope;
|
|
7243
|
-
machine[run.platform] = applyRun(machine[run.platform] ?? null, run, {
|
|
7244
|
-
at,
|
|
7245
|
-
durationMs,
|
|
7246
|
-
credit,
|
|
7247
|
-
phases
|
|
7248
|
-
});
|
|
7249
|
-
const history = { ...record.history };
|
|
7250
|
-
if (run.phases && !run.failed && !run.waitedForBuild && !run.offloadedTo) {
|
|
7251
|
-
const outcome = isHit(run.cacheHit) ? "hit" : "cold";
|
|
7252
|
-
const project = { ...history[run.projectKey] };
|
|
7253
|
-
const lists = { ...project[run.platform] };
|
|
7254
|
-
const sample = {
|
|
7255
|
-
at,
|
|
7256
|
-
durationMs,
|
|
7257
|
-
phases: wholePhases(run.phases),
|
|
7258
|
-
...run.deviceSetup === void 0 ? {} : { deviceSetup: run.deviceSetup }
|
|
7259
|
-
};
|
|
7260
|
-
lists[outcome] = trimSamples([...lists[outcome] ?? [], sample]);
|
|
7261
|
-
project[run.platform] = lists;
|
|
7262
|
-
history[run.projectKey] = project;
|
|
7263
|
-
}
|
|
7264
|
-
let placements = record.placements;
|
|
7265
|
-
let buildMachines = record.buildMachines;
|
|
7266
|
-
if (run.placement) {
|
|
7267
|
-
const placement = buildPlacement(run, before, at);
|
|
7268
|
-
placements = trimPlacements([...placements ?? [], placement], now);
|
|
7269
|
-
if (placement.machine && placement.decision !== "here") buildMachines = {
|
|
7270
|
-
...buildMachines,
|
|
7271
|
-
[placement.machine]: applyPlacement(buildMachines?.[placement.machine], placement)
|
|
7272
|
-
};
|
|
7273
|
-
}
|
|
7274
|
-
const capacityRefusals = trimCapacityRefusals(record.capacityRefusals ?? [], now);
|
|
7275
|
-
const capacityWaits = trimCapacityWaits(record.capacityWaits ?? [], now);
|
|
7276
|
-
return {
|
|
7277
|
-
version: STATS_VERSION,
|
|
7278
|
-
machine,
|
|
7279
|
-
projects,
|
|
7280
|
-
...Object.keys(history).length ? { history } : {},
|
|
7281
|
-
...placements?.length ? { placements } : {},
|
|
7282
|
-
...capacityRefusals.length ? { capacityRefusals } : {},
|
|
7283
|
-
...capacityWaits.length ? { capacityWaits } : {},
|
|
7284
|
-
...buildMachines && Object.keys(buildMachines).length ? { buildMachines } : {}
|
|
7285
|
-
};
|
|
7286
|
-
}
|
|
7287
|
-
function buildPlacement(run, before, at) {
|
|
7288
|
-
const placement = run.placement;
|
|
7289
|
-
const buildMs = wholeMs(placement.decision === "offloaded" ? placement.buildMs : run.coldBuildMs);
|
|
7290
|
-
const localEstimateMs = wholeMs(before?.lastColdBuildMs);
|
|
7291
|
-
const slotWaitMs = wholeMs(placement.slotWaitMs);
|
|
7292
|
-
const deviceSlotWaitMs = wholeMs(placement.deviceSlotWaitMs);
|
|
7293
|
-
return {
|
|
7294
|
-
at,
|
|
7295
|
-
project: run.projectKey,
|
|
7296
|
-
platform: run.platform,
|
|
7297
|
-
decision: placement.decision,
|
|
7298
|
-
reason: placement.reason,
|
|
7299
|
-
...placement.machine ? { machine: placement.machine } : {},
|
|
7300
|
-
...buildMs > 0 ? { buildMs } : {},
|
|
7301
|
-
...slotWaitMs > 0 ? { slotWaitMs } : {},
|
|
7302
|
-
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {},
|
|
7303
|
-
...localEstimateMs > 0 ? { localEstimateMs } : {},
|
|
7304
|
-
...run.failed ? { failed: true } : {}
|
|
7305
|
-
};
|
|
7306
|
-
}
|
|
7307
|
-
function applyPlacement(totals, placement) {
|
|
7308
|
-
const next = totals ? { ...totals } : {
|
|
7309
|
-
offloaded: 0,
|
|
7310
|
-
offloadedMs: 0,
|
|
7311
|
-
savedMs: 0,
|
|
7312
|
-
fallbacks: 0
|
|
7313
|
-
};
|
|
7314
|
-
if (placement.decision === "fell-back") {
|
|
7315
|
-
next.fallbacks += 1;
|
|
7316
|
-
next.lastFallbackAt = placement.at;
|
|
7317
|
-
return next;
|
|
7318
|
-
}
|
|
7319
|
-
next.offloaded += 1;
|
|
7320
|
-
next.offloadedMs += placement.buildMs ?? 0;
|
|
7321
|
-
if (placement.localEstimateMs && placement.buildMs) next.savedMs += placement.localEstimateMs - placement.buildMs;
|
|
7322
|
-
next.lastOffloadAt = placement.at;
|
|
7323
|
-
return next;
|
|
7324
|
-
}
|
|
7325
|
-
function trimPlacements(placements, now) {
|
|
7326
|
-
return placements.filter((each) => now - Date.parse(each.at) <= PLACEMENT_MAX_AGE_MS).slice(-100);
|
|
7327
|
-
}
|
|
7328
|
-
function recordRunStats(run, now) {
|
|
7329
|
-
return withConfigLock$1(() => {
|
|
7330
|
-
const path = statsFile();
|
|
7331
|
-
const loaded = loadForUpdate(path, now);
|
|
7332
|
-
if (loaded.newerVersion !== null) return {
|
|
7333
|
-
recorded: false,
|
|
7334
|
-
note: `Run statistics at ${path} are version ${loaded.newerVersion}, which this Stim does not understand, so this run was not recorded.`
|
|
7335
|
-
};
|
|
7336
|
-
writeStats(path, updateStats(loaded.record, run, now));
|
|
7337
|
-
return {
|
|
7338
|
-
recorded: true,
|
|
7339
|
-
note: loaded.note
|
|
7340
|
-
};
|
|
7339
|
+
//#region src/maintenance/log.ts
|
|
7340
|
+
function openRetainedLog(file, settings) {
|
|
7341
|
+
ensurePrivateDir(dirname(file));
|
|
7342
|
+
const rotated = rotatedLogPath(file);
|
|
7343
|
+
withDirLock(`${file}.lock`, () => {
|
|
7344
|
+
try {
|
|
7345
|
+
if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
|
|
7346
|
+
} catch {}
|
|
7341
7347
|
});
|
|
7348
|
+
return createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
|
|
7342
7349
|
}
|
|
7343
|
-
function
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
const path = statsFile();
|
|
7347
|
-
const loaded = loadForUpdate(path, now, false);
|
|
7348
|
-
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
7349
|
-
const capacityRefusals = trimCapacityRefusals([...loaded.record.capacityRefusals ?? [], {
|
|
7350
|
-
...event,
|
|
7351
|
-
at: new Date(now).toISOString(),
|
|
7352
|
-
kind: "device"
|
|
7353
|
-
}], now);
|
|
7354
|
-
writeStats(path, {
|
|
7355
|
-
...loaded.record,
|
|
7356
|
-
capacityRefusals
|
|
7357
|
-
});
|
|
7358
|
-
});
|
|
7359
|
-
} catch {}
|
|
7360
|
-
}
|
|
7361
|
-
function recordCapacityWait(event, now) {
|
|
7362
|
-
try {
|
|
7363
|
-
withConfigLock$1(() => {
|
|
7364
|
-
const path = statsFile();
|
|
7365
|
-
const loaded = loadForUpdate(path, now, false);
|
|
7366
|
-
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
7367
|
-
const capacityWaits = trimCapacityWaits([...loaded.record.capacityWaits ?? [], {
|
|
7368
|
-
platform: event.platform,
|
|
7369
|
-
max: event.max,
|
|
7370
|
-
workspace: event.workspace,
|
|
7371
|
-
ms: wholeMs(event.ms),
|
|
7372
|
-
...event.reclaimed && Number.isInteger(event.reclaimed) && event.reclaimed > 0 ? { reclaimed: event.reclaimed } : {},
|
|
7373
|
-
at: new Date(now).toISOString(),
|
|
7374
|
-
kind: "device-wait"
|
|
7375
|
-
}], now);
|
|
7376
|
-
writeStats(path, {
|
|
7377
|
-
...loaded.record,
|
|
7378
|
-
capacityWaits
|
|
7379
|
-
});
|
|
7380
|
-
});
|
|
7381
|
-
} catch {}
|
|
7382
|
-
}
|
|
7383
|
-
function createRunRecorder({ platform, write, now, note, phases, deviceSetup }) {
|
|
7384
|
-
let projectKey = null;
|
|
7385
|
-
let cacheKey = null;
|
|
7386
|
-
let coldBuildMs = 0;
|
|
7387
|
-
let podsMs = 0;
|
|
7388
|
-
let placement = null;
|
|
7389
|
-
let deviceSlotWaitMs = 0;
|
|
7390
|
-
let recorded = false;
|
|
7350
|
+
function maintenanceLogger(settings, pass, trigger) {
|
|
7351
|
+
const file = maintenanceNdjsonFile();
|
|
7352
|
+
const writer = openRetainedLog(file, settings);
|
|
7391
7353
|
return {
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
try {
|
|
7418
|
-
const outcome = write({
|
|
7419
|
-
platform,
|
|
7420
|
-
projectKey,
|
|
7421
|
-
failed,
|
|
7422
|
-
cacheHit,
|
|
7423
|
-
waitedForBuild: Boolean(waited),
|
|
7424
|
-
durationMs,
|
|
7425
|
-
...offloadedTo ? { offloadedTo } : {},
|
|
7426
|
-
...coldBuildMs > 0 ? { coldBuildMs } : {},
|
|
7427
|
-
...podsMs > 0 ? { podsMs } : {},
|
|
7428
|
-
...Object.keys(ran).length ? { phases: ran } : {},
|
|
7429
|
-
...failed || deviceSetup?.() === void 0 ? {} : { deviceSetup: deviceSetup() },
|
|
7430
|
-
...placement ? { placement: {
|
|
7431
|
-
...placement,
|
|
7432
|
-
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {}
|
|
7433
|
-
} } : {}
|
|
7434
|
-
}, now());
|
|
7435
|
-
if (outcome?.note) note(outcome.note);
|
|
7436
|
-
} catch (error) {
|
|
7437
|
-
note(`Run statistics could not be recorded: ${error?.message || error}`);
|
|
7354
|
+
write(event, level, msg, fields = {}) {
|
|
7355
|
+
if (level === "debug" && !settings.logChecks) return null;
|
|
7356
|
+
const record = {
|
|
7357
|
+
...fields,
|
|
7358
|
+
ts: Date.now(),
|
|
7359
|
+
src: "maintenance",
|
|
7360
|
+
level,
|
|
7361
|
+
msg,
|
|
7362
|
+
event,
|
|
7363
|
+
pass,
|
|
7364
|
+
trigger,
|
|
7365
|
+
mode: settings.mode === "on" ? "on" : "report"
|
|
7366
|
+
};
|
|
7367
|
+
if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
|
|
7368
|
+
if (typeof fields.workspace === "string" && [
|
|
7369
|
+
"maintenance_action",
|
|
7370
|
+
"maintenance_failure",
|
|
7371
|
+
"maintenance_skip"
|
|
7372
|
+
].includes(event)) {
|
|
7373
|
+
const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
|
|
7374
|
+
try {
|
|
7375
|
+
if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
|
|
7376
|
+
} finally {
|
|
7377
|
+
workspace.close();
|
|
7378
|
+
}
|
|
7438
7379
|
}
|
|
7439
|
-
|
|
7380
|
+
return record;
|
|
7381
|
+
},
|
|
7382
|
+
close: () => writer.close()
|
|
7440
7383
|
};
|
|
7441
7384
|
}
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
}
|
|
7453
|
-
const parsed = decodeStats(text);
|
|
7454
|
-
if (!parsed.record && parsed.newerVersion === null) {
|
|
7455
|
-
if (!recoverCorrupt) return {
|
|
7456
|
-
record: null,
|
|
7457
|
-
note: null,
|
|
7458
|
-
newerVersion: null
|
|
7459
|
-
};
|
|
7460
|
-
const aside = `${path}.corrupt-${now}`;
|
|
7461
|
-
renameSync(path, aside);
|
|
7462
|
-
return {
|
|
7463
|
-
record: emptyStats(),
|
|
7464
|
-
note: `Run statistics at ${path} could not be read, so they were moved to ${aside} and a new file was started.`,
|
|
7465
|
-
newerVersion: null
|
|
7466
|
-
};
|
|
7467
|
-
}
|
|
7468
|
-
if (parsed.newerVersion !== null) return {
|
|
7469
|
-
record: emptyStats(),
|
|
7470
|
-
note: null,
|
|
7471
|
-
newerVersion: parsed.newerVersion
|
|
7472
|
-
};
|
|
7385
|
+
//#endregion
|
|
7386
|
+
//#region src/commands/gc/log.ts
|
|
7387
|
+
const VERBS = {
|
|
7388
|
+
done: "Cleared",
|
|
7389
|
+
kept: "Kept",
|
|
7390
|
+
failed: "Failed to clear"
|
|
7391
|
+
};
|
|
7392
|
+
function gcLogRecord(run, result, ts) {
|
|
7393
|
+
const path = [result.id, result.label].find((value) => value !== null && isAbsolute(value)) ?? null;
|
|
7394
|
+
const size = result.bytes ? ` (${formatBytes(result.bytes)})` : "";
|
|
7395
|
+
const why = result.detail ? `: ${result.detail}` : "";
|
|
7473
7396
|
return {
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
const next = bucket ? { ...bucket } : {
|
|
7491
|
-
runs: 0,
|
|
7492
|
-
failed: 0,
|
|
7493
|
-
hits: 0,
|
|
7494
|
-
misses: 0,
|
|
7495
|
-
coldRuns: 0,
|
|
7496
|
-
coldRunMs: 0,
|
|
7497
|
-
hitRuns: 0,
|
|
7498
|
-
hitRunMs: 0,
|
|
7499
|
-
timeSavedMs: 0,
|
|
7500
|
-
firstRunAt: at,
|
|
7501
|
-
lastRunAt: at
|
|
7502
|
-
};
|
|
7503
|
-
next.runs += 1;
|
|
7504
|
-
next.lastRunAt = at;
|
|
7505
|
-
if (phases.coldBuildMs > 0) next.lastColdBuildMs = phases.coldBuildMs;
|
|
7506
|
-
if (phases.podsMs > 0) next.lastPodsMs = phases.podsMs;
|
|
7507
|
-
if (run.failed) {
|
|
7508
|
-
next.failed += 1;
|
|
7509
|
-
return next;
|
|
7510
|
-
}
|
|
7511
|
-
if (isHit(run.cacheHit)) {
|
|
7512
|
-
next.hits += 1;
|
|
7513
|
-
if (!run.waitedForBuild) {
|
|
7514
|
-
next.hitRuns += 1;
|
|
7515
|
-
next.hitRunMs += durationMs;
|
|
7516
|
-
next.timeSavedMs += credit;
|
|
7517
|
-
}
|
|
7518
|
-
return next;
|
|
7519
|
-
}
|
|
7520
|
-
next.misses += 1;
|
|
7521
|
-
if (run.offloadedTo) {
|
|
7522
|
-
next.offloadedRuns = (next.offloadedRuns ?? 0) + 1;
|
|
7523
|
-
next.offloadedRunMs = (next.offloadedRunMs ?? 0) + durationMs;
|
|
7524
|
-
next.lastOffloadHost = run.offloadedTo;
|
|
7525
|
-
return next;
|
|
7526
|
-
}
|
|
7527
|
-
next.coldRuns += 1;
|
|
7528
|
-
next.coldRunMs += durationMs;
|
|
7529
|
-
return next;
|
|
7530
|
-
}
|
|
7531
|
-
function creditMs(bucket, run, durationMs) {
|
|
7532
|
-
if (run.failed || !isHit(run.cacheHit) || run.waitedForBuild) return 0;
|
|
7533
|
-
if (!bucket || bucket.coldRuns <= 0) return 0;
|
|
7534
|
-
return Math.max(0, Math.round(bucket.coldRunMs / bucket.coldRuns) - durationMs);
|
|
7535
|
-
}
|
|
7536
|
-
function isHit(cacheHit) {
|
|
7537
|
-
return cacheHit === "local" || cacheHit === "remote";
|
|
7538
|
-
}
|
|
7539
|
-
function wholeMs(value) {
|
|
7540
|
-
const ms = Number(value);
|
|
7541
|
-
return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : 0;
|
|
7542
|
-
}
|
|
7543
|
-
//#endregion
|
|
7544
|
-
//#region src/engine/build-detail.ts
|
|
7545
|
-
const LINE_MAX = 160;
|
|
7546
|
-
const TARGET_GRAPH = /^note: Target dependency graph \((\d+) targets?\)/;
|
|
7547
|
-
const XCODE_ACTION = /^([A-Z][A-Za-z]+)\s(.*)\s\(in target '([^']+)' from project '([^']+)'\)$/;
|
|
7548
|
-
const XCODE_CONFIGURE = /^(ComputeTargetDependencyGraph|CreateBuildDescription|CreateBuildRequest|Resolve Package Graph|Prepare packages)$/;
|
|
7549
|
-
const GRADLE_TASK = /^> Task (:\S+)/;
|
|
7550
|
-
/**
|
|
7551
|
-
* xcodebuild actions that end a target's work: a clean build touches each product last, and an incremental build
|
|
7552
|
-
* that touches nothing still signs framework products last. Targets that end any other way are not counted.
|
|
7553
|
-
*/
|
|
7554
|
-
const XCODE_TARGET_DONE = /^(Touch|RegisterExecutionPolicyException|CodeSign)$/;
|
|
7555
|
-
const GRADLE_CONFIGURE = /^> Configure project /;
|
|
7556
|
-
/**
|
|
7557
|
-
* SwiftPM prints `[done / total] name` once it plans the build (with U+2009 thin spaces around the slash in Swift 6.4
|
|
7558
|
-
* output), `[done/total] Compiling ...` in older toolchains; Swift 6.4 names the target being worked on, and
|
|
7559
|
-
* `<product>-product` is the link of a product.
|
|
7560
|
-
*/
|
|
7561
|
-
const SWIFTPM_PROGRESS = /^\[(\d+)\s*\/\s*(\d+)\](?:\s+(.*))?$/;
|
|
7562
|
-
const SWIFTPM_CONFIGURE = /^(Fetching|Fetched|Computing version|Computed|Creating working copy|Working copy of)\b|^\[(Pre-planning|Planning|Using on-disk description)/;
|
|
7563
|
-
const XCODE_STEPS = [
|
|
7564
|
-
[/^(CpResource|CopyPNGFile|CopyStringsFile|CompileAssetCatalog\w*|CompileStoryboard|CompileXIB|LinkStoryboards|ProcessInfoPlistFile)$/, "resources"],
|
|
7565
|
-
[/^(Compile\w*|Swift\w*|ScanDependencies|Precompile\w*)$/, "compile"],
|
|
7566
|
-
[/^(Ld|Libtool|CreateUniversalBinary|GenerateDSYMFile)$/, "link"],
|
|
7567
|
-
[/^PhaseScriptExecution$/, "script"],
|
|
7568
|
-
[/^CodeSign$/, "sign"]
|
|
7569
|
-
];
|
|
7570
|
-
const GRADLE_STEPS = [
|
|
7571
|
-
[/[Dd]ex/, "dex"],
|
|
7572
|
-
[/^(createBundle\w*JsAndAssets|generateCodegen\w*)$/, "script"],
|
|
7573
|
-
[/(Resources?|Assets|Manifest|ResValues|RFile|JavaRes)$/, "resources"],
|
|
7574
|
-
[/^(compile|kapt|ksp|javaPreCompile|buildCMake|configureCMake|externalNativeBuild)/, "compile"],
|
|
7575
|
-
[/^(package|assemble|install|zipalign|validateSigning|merge\w*NativeLibs|strip\w*Symbols)/, "package"]
|
|
7576
|
-
];
|
|
7577
|
-
function stepOf(name, table) {
|
|
7578
|
-
return table.find(([pattern]) => pattern.test(name))?.[1] ?? null;
|
|
7579
|
-
}
|
|
7580
|
-
function clip(text) {
|
|
7581
|
-
return text.length > LINE_MAX ? `${text.slice(0, 157)}...` : text;
|
|
7582
|
-
}
|
|
7583
|
-
function unescape(token) {
|
|
7584
|
-
return token.replace(/\\(.)/g, "$1");
|
|
7585
|
-
}
|
|
7586
|
-
function baseName(path) {
|
|
7587
|
-
return path.split("/").findLast(Boolean) ?? path;
|
|
7588
|
-
}
|
|
7589
|
-
/**
|
|
7590
|
-
* An xcodebuild action line in short form: the action, the file it works on and its target, as in
|
|
7591
|
-
* `CompileC sqlite3.c (sqlite3)`. The file is the last absolute path in the arguments, which xcodebuild prints
|
|
7592
|
-
* as the source for compile, copy and plist steps and as the product for link and sign steps; a script phase
|
|
7593
|
-
* shows its name instead.
|
|
7594
|
-
*/
|
|
7595
|
-
function shortXcodeAction(action, args, target) {
|
|
7596
|
-
const tokens = args.match(/(?:\\.|\S)+/g) ?? [];
|
|
7597
|
-
const subject = action === "PhaseScriptExecution" ? unescape(tokens[0] ?? "") : baseName(unescape(tokens.findLast((token) => token.startsWith("/")) ?? ""));
|
|
7598
|
-
return clip(`${action}${subject ? ` ${subject}` : ""} (${target})`);
|
|
7599
|
-
}
|
|
7600
|
-
function swiftpmStep(text) {
|
|
7601
|
-
return /^Linking\b|-product$/.test(text) ? "link" : "compile";
|
|
7602
|
-
}
|
|
7603
|
-
/** What one line of xcodebuild, Gradle or SwiftPM output says about the build's progress, or null for any other line. */
|
|
7604
|
-
function parseBuildToolLine(msg) {
|
|
7605
|
-
const counted = SWIFTPM_PROGRESS.exec(msg);
|
|
7606
|
-
if (counted) {
|
|
7607
|
-
const text = counted[3]?.trim() ?? "";
|
|
7608
|
-
return {
|
|
7609
|
-
kind: "count",
|
|
7610
|
-
done: Number(counted[1]),
|
|
7611
|
-
total: Number(counted[2]),
|
|
7612
|
-
step: swiftpmStep(text),
|
|
7613
|
-
line: text ? clip(text) : null
|
|
7614
|
-
};
|
|
7615
|
-
}
|
|
7616
|
-
if (SWIFTPM_CONFIGURE.test(msg)) return { kind: "configure" };
|
|
7617
|
-
const graph = TARGET_GRAPH.exec(msg);
|
|
7618
|
-
if (graph) return {
|
|
7619
|
-
kind: "total",
|
|
7620
|
-
unit: "targets",
|
|
7621
|
-
total: Number(graph[1])
|
|
7622
|
-
};
|
|
7623
|
-
if (XCODE_CONFIGURE.test(msg) || GRADLE_CONFIGURE.test(msg)) return { kind: "configure" };
|
|
7624
|
-
const action = XCODE_ACTION.exec(msg);
|
|
7625
|
-
if (action) {
|
|
7626
|
-
const [, name, args, target, project] = action;
|
|
7627
|
-
const step = stepOf(name, XCODE_STEPS);
|
|
7628
|
-
return {
|
|
7629
|
-
kind: "unit",
|
|
7630
|
-
unit: "targets",
|
|
7631
|
-
id: `${project}/${target}`,
|
|
7632
|
-
step,
|
|
7633
|
-
line: step ? shortXcodeAction(name, args, target) : null,
|
|
7634
|
-
finished: XCODE_TARGET_DONE.test(name)
|
|
7635
|
-
};
|
|
7636
|
-
}
|
|
7637
|
-
const task = GRADLE_TASK.exec(msg);
|
|
7638
|
-
if (task) {
|
|
7639
|
-
const path = task[1];
|
|
7640
|
-
return {
|
|
7641
|
-
kind: "unit",
|
|
7642
|
-
unit: "tasks",
|
|
7643
|
-
id: path,
|
|
7644
|
-
step: stepOf(path.slice(path.lastIndexOf(":") + 1), GRADLE_STEPS),
|
|
7645
|
-
line: clip(`> Task ${path}`),
|
|
7646
|
-
finished: false
|
|
7647
|
-
};
|
|
7648
|
-
}
|
|
7649
|
-
return null;
|
|
7650
|
-
}
|
|
7651
|
-
/**
|
|
7652
|
-
* Accumulates a build's tool output into its detail: xcodebuild counts the distinct targets it finished against the
|
|
7653
|
-
* total its dependency graph note gives; Gradle counts the task lines it printed and has no total; SwiftPM reports
|
|
7654
|
-
* its own `[done / total]` counts, which the parser passes through.
|
|
7655
|
-
*/
|
|
7656
|
-
function createBuildDetailParser() {
|
|
7657
|
-
let seen = false;
|
|
7658
|
-
let step = null;
|
|
7659
|
-
let unit = null;
|
|
7660
|
-
let total = null;
|
|
7661
|
-
let line = null;
|
|
7662
|
-
let tasks = 0;
|
|
7663
|
-
let counted = null;
|
|
7664
|
-
const targets = /* @__PURE__ */ new Set();
|
|
7665
|
-
return {
|
|
7666
|
-
push(msg) {
|
|
7667
|
-
const parsed = parseBuildToolLine(msg);
|
|
7668
|
-
if (!parsed) return false;
|
|
7669
|
-
seen = true;
|
|
7670
|
-
if (parsed.kind === "total") {
|
|
7671
|
-
unit = "targets";
|
|
7672
|
-
total = parsed.total;
|
|
7673
|
-
return true;
|
|
7674
|
-
}
|
|
7675
|
-
if (parsed.kind === "configure") {
|
|
7676
|
-
step = "configure";
|
|
7677
|
-
return true;
|
|
7678
|
-
}
|
|
7679
|
-
if (parsed.kind === "count") {
|
|
7680
|
-
unit = "steps";
|
|
7681
|
-
counted = {
|
|
7682
|
-
done: parsed.done,
|
|
7683
|
-
total: parsed.total
|
|
7684
|
-
};
|
|
7685
|
-
step = parsed.step;
|
|
7686
|
-
if (parsed.line) line = parsed.line;
|
|
7687
|
-
return true;
|
|
7688
|
-
}
|
|
7689
|
-
unit = parsed.unit;
|
|
7690
|
-
if (parsed.unit === "tasks") tasks += 1;
|
|
7691
|
-
else if (parsed.finished) targets.add(parsed.id);
|
|
7692
|
-
if (parsed.step) step = parsed.step;
|
|
7693
|
-
if (parsed.line) line = parsed.line;
|
|
7694
|
-
return true;
|
|
7695
|
-
},
|
|
7696
|
-
detail(updatedAt) {
|
|
7697
|
-
if (!seen) return null;
|
|
7698
|
-
if (unit === "steps" && counted) return {
|
|
7699
|
-
step,
|
|
7700
|
-
unit,
|
|
7701
|
-
done: Math.min(counted.done, counted.total),
|
|
7702
|
-
total: counted.total,
|
|
7703
|
-
line,
|
|
7704
|
-
updatedAt
|
|
7705
|
-
};
|
|
7706
|
-
const done = unit === "tasks" ? tasks : unit === "targets" ? targets.size : null;
|
|
7707
|
-
return {
|
|
7708
|
-
step,
|
|
7709
|
-
unit,
|
|
7710
|
-
done: done !== null && total !== null ? Math.min(done, total) : done,
|
|
7711
|
-
total: unit === "tasks" ? null : total,
|
|
7712
|
-
line,
|
|
7713
|
-
updatedAt
|
|
7714
|
-
};
|
|
7715
|
-
}
|
|
7716
|
-
};
|
|
7717
|
-
}
|
|
7718
|
-
//#endregion
|
|
7719
|
-
//#region src/engine/build-progress.ts
|
|
7720
|
-
const ACTIVE_BUILD_KEY = "activeBuild";
|
|
7721
|
-
const NO_BUILD_PROGRESS = {
|
|
7722
|
-
step: () => {},
|
|
7723
|
-
activity: () => {},
|
|
7724
|
-
estimate: () => {},
|
|
7725
|
-
miss: () => {},
|
|
7726
|
-
hit: () => {},
|
|
7727
|
-
deviceSetup: () => {},
|
|
7728
|
-
deviceSetupKnown: () => void 0,
|
|
7729
|
-
place: () => {},
|
|
7730
|
-
waitingOn: () => {},
|
|
7731
|
-
waitingFor: () => {},
|
|
7732
|
-
output: () => {},
|
|
7733
|
-
durations: () => ({}),
|
|
7734
|
-
phase: () => null,
|
|
7735
|
-
steps: () => null,
|
|
7736
|
-
clear: () => {}
|
|
7737
|
-
};
|
|
7738
|
-
/** `writer`, with each record it writes also passed to `progress.output`. */
|
|
7739
|
-
function tapBuildLog(writer, progress) {
|
|
7740
|
-
if (progress === NO_BUILD_PROGRESS) return writer;
|
|
7741
|
-
return {
|
|
7742
|
-
get file() {
|
|
7743
|
-
return writer.file;
|
|
7744
|
-
},
|
|
7745
|
-
write(record) {
|
|
7746
|
-
progress.output(record);
|
|
7747
|
-
return writer.write(record);
|
|
7748
|
-
},
|
|
7749
|
-
close: () => writer.close(),
|
|
7750
|
-
get written() {
|
|
7751
|
-
return writer.written;
|
|
7752
|
-
},
|
|
7753
|
-
get dropped() {
|
|
7754
|
-
return writer.dropped;
|
|
7755
|
-
},
|
|
7756
|
-
get lastError() {
|
|
7757
|
-
return writer.lastError;
|
|
7758
|
-
}
|
|
7759
|
-
};
|
|
7760
|
-
}
|
|
7761
|
-
function runFailureRecord({ code, message, phase }) {
|
|
7762
|
-
return {
|
|
7763
|
-
src: "build",
|
|
7764
|
-
level: "error",
|
|
7765
|
-
event: "run_failed",
|
|
7766
|
-
...code ? { code } : {},
|
|
7767
|
-
...phase ? { phase } : {},
|
|
7768
|
-
msg: [code, message].filter(Boolean).join(": ") || "the run failed"
|
|
7769
|
-
};
|
|
7770
|
-
}
|
|
7771
|
-
function thrownRunFailureRecord(error, phase) {
|
|
7772
|
-
return runFailureRecord({
|
|
7773
|
-
code: typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0,
|
|
7774
|
-
message: error instanceof Error ? error.message : String(error),
|
|
7775
|
-
phase
|
|
7776
|
-
});
|
|
7777
|
-
}
|
|
7778
|
-
const DETAIL_WRITE_MS = 2e3;
|
|
7779
|
-
function toolLine(record) {
|
|
7780
|
-
if (!record || typeof record !== "object") return null;
|
|
7781
|
-
const { src, level, msg } = record;
|
|
7782
|
-
return src === "build" && level === "debug" && typeof msg === "string" ? msg : null;
|
|
7783
|
-
}
|
|
7784
|
-
function writeBuildDetail(root, claimId, detail) {
|
|
7785
|
-
const file = workspaceBuildDetailFile(root);
|
|
7786
|
-
const tmp = `${file}.tmp-${process.pid}`;
|
|
7787
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
7788
|
-
writeFileSync(tmp, JSON.stringify({
|
|
7789
|
-
claimId,
|
|
7790
|
-
detail
|
|
7791
|
-
}));
|
|
7792
|
-
renameSync(tmp, file);
|
|
7793
|
-
}
|
|
7794
|
-
const COLD_PHASES = [
|
|
7795
|
-
"prebuild",
|
|
7796
|
-
"pods",
|
|
7797
|
-
"compile"
|
|
7798
|
-
];
|
|
7799
|
-
const HIT_PHASES = ["install", "launch"];
|
|
7800
|
-
function settledOutcome(phase, entered) {
|
|
7801
|
-
if (COLD_PHASES.includes(phase)) return "cold";
|
|
7802
|
-
if (phase === "device") return entered.some((entry) => entry.phase === "cache-lookup") ? "hit" : null;
|
|
7803
|
-
return HIT_PHASES.includes(phase) ? "hit" : null;
|
|
7804
|
-
}
|
|
7805
|
-
function projectHistory(projectKey) {
|
|
7806
|
-
try {
|
|
7807
|
-
return readStats$1().record?.history?.[projectKey];
|
|
7808
|
-
} catch {
|
|
7809
|
-
return;
|
|
7810
|
-
}
|
|
7811
|
-
}
|
|
7812
|
-
function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
|
|
7813
|
-
const startedAt = new Date(now()).toISOString();
|
|
7814
|
-
const record = {
|
|
7815
|
-
platform,
|
|
7816
|
-
slot,
|
|
7817
|
-
startedAt,
|
|
7818
|
-
phase: "prepare",
|
|
7819
|
-
phaseStartedAt: startedAt,
|
|
7820
|
-
phases: [{
|
|
7821
|
-
phase: "prepare",
|
|
7822
|
-
startedAt
|
|
7823
|
-
}],
|
|
7824
|
-
claim: {
|
|
7825
|
-
root: claim.root,
|
|
7826
|
-
path: claim.path,
|
|
7827
|
-
claimId: claim.claimId,
|
|
7828
|
-
pid: claim.owner.pid
|
|
7829
|
-
}
|
|
7830
|
-
};
|
|
7831
|
-
let warned = false;
|
|
7832
|
-
const guard = (fn) => {
|
|
7833
|
-
try {
|
|
7834
|
-
fn();
|
|
7835
|
-
} catch (error) {
|
|
7836
|
-
if (warned) return;
|
|
7837
|
-
warned = true;
|
|
7838
|
-
note(`Build progress could not be recorded in the workspace state: ${error?.message || error}`);
|
|
7839
|
-
}
|
|
7840
|
-
};
|
|
7841
|
-
const write = (before = (state) => state) => guard(() => updateWorkspaceState(root, (state) => ({
|
|
7842
|
-
...before(state),
|
|
7843
|
-
[ACTIVE_BUILD_KEY]: record
|
|
7844
|
-
})));
|
|
7845
|
-
write(withInterruptedBuild);
|
|
7846
|
-
let projectKey = null;
|
|
7847
|
-
const parser = createBuildDetailParser();
|
|
7848
|
-
let detailWrittenAt = -Infinity;
|
|
7849
|
-
let detailTimer = null;
|
|
7850
|
-
const flushDetail = () => {
|
|
7851
|
-
detailTimer = null;
|
|
7852
|
-
detailWrittenAt = now();
|
|
7853
|
-
const detail = parser.detail(new Date(detailWrittenAt).toISOString());
|
|
7854
|
-
if (detail) guard(() => writeBuildDetail(root, record.claim.claimId, detail));
|
|
7855
|
-
};
|
|
7856
|
-
const settle = (outcome) => {
|
|
7857
|
-
record.outcome = outcome;
|
|
7858
|
-
if (projectKey && platform !== "macos") record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
|
|
7859
|
-
};
|
|
7860
|
-
const waits = /* @__PURE__ */ new Map();
|
|
7861
|
-
return {
|
|
7862
|
-
step(phase) {
|
|
7863
|
-
if (phase === record.phase) return;
|
|
7864
|
-
const at = new Date(now()).toISOString();
|
|
7865
|
-
record.phase = phase;
|
|
7866
|
-
record.phaseStartedAt = at;
|
|
7867
|
-
record.phases.push({
|
|
7868
|
-
phase,
|
|
7869
|
-
startedAt: at
|
|
7870
|
-
});
|
|
7871
|
-
if (phase !== "wait") delete record.waitingOn;
|
|
7872
|
-
delete record.activity;
|
|
7873
|
-
const outcome = record.outcome || platform === "macos" ? null : settledOutcome(phase, record.phases);
|
|
7874
|
-
if (outcome) settle(outcome);
|
|
7875
|
-
write();
|
|
7876
|
-
},
|
|
7877
|
-
activity(name, at) {
|
|
7878
|
-
if ((record.activity?.name ?? null) === name) return;
|
|
7879
|
-
if (name) record.activity = {
|
|
7880
|
-
name,
|
|
7881
|
-
startedAt: new Date(at ?? now()).toISOString()
|
|
7882
|
-
};
|
|
7883
|
-
else delete record.activity;
|
|
7884
|
-
write();
|
|
7885
|
-
},
|
|
7886
|
-
estimate(key) {
|
|
7887
|
-
if (platform === "macos") return;
|
|
7888
|
-
projectKey = key;
|
|
7889
|
-
record.estimate = estimateBuild(projectHistory(key), platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
|
|
7890
|
-
write();
|
|
7891
|
-
},
|
|
7892
|
-
miss(reason, provisional = false) {
|
|
7893
|
-
record.missReason = reason;
|
|
7894
|
-
settle("cold");
|
|
7895
|
-
if (provisional) record.missProvisional = true;
|
|
7896
|
-
else delete record.missProvisional;
|
|
7897
|
-
write();
|
|
7898
|
-
},
|
|
7899
|
-
hit() {
|
|
7900
|
-
delete record.missReason;
|
|
7901
|
-
delete record.missProvisional;
|
|
7902
|
-
settle("hit");
|
|
7903
|
-
write();
|
|
7904
|
-
},
|
|
7905
|
-
deviceSetup(setup) {
|
|
7906
|
-
if (setup === void 0) return;
|
|
7907
|
-
record.deviceSetup = setup;
|
|
7908
|
-
write();
|
|
7909
|
-
},
|
|
7910
|
-
deviceSetupKnown() {
|
|
7911
|
-
return record.deviceSetup;
|
|
7912
|
-
},
|
|
7913
|
-
place(remote) {
|
|
7914
|
-
const current = record.placement;
|
|
7915
|
-
if (!remote) {
|
|
7916
|
-
if (!current) return;
|
|
7917
|
-
delete record.placement;
|
|
7918
|
-
return write();
|
|
7919
|
-
}
|
|
7920
|
-
if (current?.host === remote.host && current.phase === remote.phase) return;
|
|
7921
|
-
const at = new Date(now()).toISOString();
|
|
7922
|
-
record.placement = {
|
|
7923
|
-
host: remote.host,
|
|
7924
|
-
phase: remote.phase,
|
|
7925
|
-
startedAt: current?.host === remote.host ? current.startedAt : at,
|
|
7926
|
-
phaseStartedAt: at
|
|
7927
|
-
};
|
|
7928
|
-
write();
|
|
7929
|
-
},
|
|
7930
|
-
waitingFor(info, kind) {
|
|
7931
|
-
if (info) waits.set(info.kind, info);
|
|
7932
|
-
else if (kind) waits.delete(kind);
|
|
7933
|
-
else waits.clear();
|
|
7934
|
-
const first = [...waits.values()].toSorted((a, b) => Date.parse(a.since) - Date.parse(b.since))[0];
|
|
7935
|
-
if (first) record.waitingFor = first;
|
|
7936
|
-
else delete record.waitingFor;
|
|
7937
|
-
write();
|
|
7938
|
-
},
|
|
7939
|
-
waitingOn(holder) {
|
|
7940
|
-
if (holder === null) {
|
|
7941
|
-
if (!record.waitingOn) return;
|
|
7942
|
-
delete record.waitingOn;
|
|
7943
|
-
} else {
|
|
7944
|
-
if (record.waitingOn?.path === holder) return;
|
|
7945
|
-
record.waitingOn = { path: holder };
|
|
7946
|
-
}
|
|
7947
|
-
write();
|
|
7948
|
-
},
|
|
7949
|
-
output(line) {
|
|
7950
|
-
const msg = toolLine(line);
|
|
7951
|
-
if (msg === null || !parser.push(msg) || detailTimer) return;
|
|
7952
|
-
const wait = detailWrittenAt + DETAIL_WRITE_MS - now();
|
|
7953
|
-
if (wait <= 0) return flushDetail();
|
|
7954
|
-
detailTimer = setTimeout(flushDetail, wait);
|
|
7955
|
-
detailTimer.unref?.();
|
|
7956
|
-
},
|
|
7957
|
-
durations() {
|
|
7958
|
-
return phaseDurations(record.phases, now());
|
|
7959
|
-
},
|
|
7960
|
-
phase() {
|
|
7961
|
-
return record.phase;
|
|
7962
|
-
},
|
|
7963
|
-
steps() {
|
|
7964
|
-
const detail = parser.detail("");
|
|
7965
|
-
return detail?.unit === "steps" ? detail.total : null;
|
|
7966
|
-
},
|
|
7967
|
-
clear() {
|
|
7968
|
-
if (detailTimer) clearTimeout(detailTimer);
|
|
7969
|
-
detailTimer = null;
|
|
7970
|
-
guard(() => rmSync(workspaceBuildDetailFile(root), { force: true }));
|
|
7971
|
-
guard(() => {
|
|
7972
|
-
clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
|
|
7973
|
-
});
|
|
7974
|
-
}
|
|
7975
|
-
};
|
|
7976
|
-
}
|
|
7977
|
-
function phaseDurations(phases, now) {
|
|
7978
|
-
const out = {};
|
|
7979
|
-
phases.forEach(({ phase, startedAt }, index) => {
|
|
7980
|
-
const start = Date.parse(startedAt);
|
|
7981
|
-
const next = phases[index + 1];
|
|
7982
|
-
const end = next ? Date.parse(next.startedAt) : now;
|
|
7983
|
-
if (!Number.isFinite(start) || !Number.isFinite(end)) return;
|
|
7984
|
-
out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
|
|
7985
|
-
});
|
|
7986
|
-
return out;
|
|
7987
|
-
}
|
|
7988
|
-
function completedPhaseDurations(phases) {
|
|
7989
|
-
if (phases.length < 2) return void 0;
|
|
7990
|
-
const durations = phaseDurations(phases.slice(0, -1), Date.parse(phases.at(-1).startedAt));
|
|
7991
|
-
return Object.keys(durations).length ? durations : void 0;
|
|
7992
|
-
}
|
|
7993
|
-
const HISTORY_FIELDS = [
|
|
7994
|
-
"devicePlacement",
|
|
7995
|
-
"platform",
|
|
7996
|
-
"status",
|
|
7997
|
-
"configuration",
|
|
7998
|
-
"fingerprint",
|
|
7999
|
-
"cacheKey",
|
|
8000
|
-
"cacheHit",
|
|
8001
|
-
"cacheSkipped",
|
|
8002
|
-
"durationMs",
|
|
8003
|
-
"startedAt",
|
|
8004
|
-
"errorCode",
|
|
8005
|
-
"missReason",
|
|
8006
|
-
"buildMachine",
|
|
8007
|
-
"builtOn",
|
|
8008
|
-
"offloadedTo",
|
|
8009
|
-
"offloadFallback",
|
|
8010
|
-
"diagnostics",
|
|
8011
|
-
"compileSteps"
|
|
8012
|
-
];
|
|
8013
|
-
function withHistoryEntry(state, platform, entry) {
|
|
8014
|
-
const saved = state[BUILD_HISTORY_KEY];
|
|
8015
|
-
const history = saved && typeof saved === "object" && !Array.isArray(saved) ? saved : {};
|
|
8016
|
-
const list = Array.isArray(history[platform]) ? history[platform] : [];
|
|
8017
|
-
return {
|
|
8018
|
-
...state,
|
|
8019
|
-
[BUILD_HISTORY_KEY]: {
|
|
8020
|
-
...history,
|
|
8021
|
-
[platform]: [entry, ...list].slice(0, BUILD_HISTORY_LIMIT)
|
|
8022
|
-
}
|
|
8023
|
-
};
|
|
8024
|
-
}
|
|
8025
|
-
function finishedResult(record) {
|
|
8026
|
-
if (record.status === "ok") return "succeeded";
|
|
8027
|
-
return record.errorCode === "STIM_CANCELLED" ? "cancelled" : "failed";
|
|
8028
|
-
}
|
|
8029
|
-
function recordFinishedBuild(root, record, { update = updateWorkspaceState, now = Date.now, artifactOnly = false } = {}) {
|
|
8030
|
-
const platform = record.platform;
|
|
8031
|
-
update(root, (state) => {
|
|
8032
|
-
const active = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
8033
|
-
const own = active?.platform === platform ? active : null;
|
|
8034
|
-
const entry = {
|
|
8035
|
-
...Object.fromEntries(HISTORY_FIELDS.filter((key) => key in record).map((key) => [key, record[key]])),
|
|
8036
|
-
result: finishedResult(record),
|
|
8037
|
-
slot: own?.slot ?? "default",
|
|
8038
|
-
phases: own ? phaseDurations(own.phases, now()) : {}
|
|
8039
|
-
};
|
|
8040
|
-
if (artifactOnly || platform === "macos") return withHistoryEntry(state, platform, entry);
|
|
8041
|
-
const slot = own?.slot ?? "default";
|
|
8042
|
-
const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
|
|
8043
|
-
const savedSlot = isJsonObject(slots[slot]) ? slots[slot] : {};
|
|
8044
|
-
const savedDevice = slot === "default" ? state[platform] : savedSlot[platform];
|
|
8045
|
-
if (record.devicePlacement || isJsonObject(savedDevice)) {
|
|
8046
|
-
const device = isJsonObject(savedDevice) ? { ...savedDevice } : {};
|
|
8047
|
-
if (record.devicePlacement) device.devicePlacement = record.devicePlacement;
|
|
8048
|
-
else delete device.devicePlacement;
|
|
8049
|
-
state = slot === "default" ? {
|
|
8050
|
-
...state,
|
|
8051
|
-
[platform]: device
|
|
8052
|
-
} : {
|
|
8053
|
-
...state,
|
|
8054
|
-
deviceSlots: {
|
|
8055
|
-
...slots,
|
|
8056
|
-
[slot]: {
|
|
8057
|
-
...savedSlot,
|
|
8058
|
-
[platform]: device
|
|
8059
|
-
}
|
|
8060
|
-
}
|
|
8061
|
-
};
|
|
8062
|
-
}
|
|
8063
|
-
return withHistoryEntry({
|
|
8064
|
-
...state,
|
|
8065
|
-
lastBuild: record,
|
|
8066
|
-
[LAST_BUILD_KEYS[platform]]: record
|
|
8067
|
-
}, platform, entry);
|
|
8068
|
-
});
|
|
8069
|
-
}
|
|
8070
|
-
/** Adds one phase's duration to the recorded run of `platform` that started at `startedAt`. */
|
|
8071
|
-
function recordBuildPhase(root, platform, startedAt, phase, ms) {
|
|
8072
|
-
updateWorkspaceState(root, (state) => {
|
|
8073
|
-
const saved = state[BUILD_HISTORY_KEY];
|
|
8074
|
-
const list = isJsonObject(saved) && Array.isArray(saved[platform]) ? saved[platform] : [];
|
|
8075
|
-
const index = list.findIndex((entry) => isJsonObject(entry) && entry.startedAt === startedAt);
|
|
8076
|
-
const entry = list[index];
|
|
8077
|
-
if (!isJsonObject(entry)) return state;
|
|
8078
|
-
const phases = isJsonObject(entry.phases) ? entry.phases : {};
|
|
8079
|
-
const next = [...list];
|
|
8080
|
-
next[index] = {
|
|
8081
|
-
...entry,
|
|
8082
|
-
phases: {
|
|
8083
|
-
...phases,
|
|
8084
|
-
[phase]: Math.round(ms)
|
|
8085
|
-
}
|
|
8086
|
-
};
|
|
8087
|
-
return {
|
|
8088
|
-
...state,
|
|
8089
|
-
[BUILD_HISTORY_KEY]: {
|
|
8090
|
-
...saved,
|
|
8091
|
-
[platform]: next
|
|
8092
|
-
}
|
|
8093
|
-
};
|
|
8094
|
-
});
|
|
8095
|
-
}
|
|
8096
|
-
function withInterruptedBuild(state) {
|
|
8097
|
-
const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
8098
|
-
if (!left) return state;
|
|
8099
|
-
const last = state[BUILD_HISTORY_KEY]?.[left.platform]?.[0];
|
|
8100
|
-
if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
|
|
8101
|
-
return withHistoryEntry(state, left.platform, {
|
|
8102
|
-
platform: left.platform,
|
|
8103
|
-
status: "failed",
|
|
8104
|
-
result: "interrupted",
|
|
8105
|
-
slot: left.slot,
|
|
8106
|
-
configuration: null,
|
|
8107
|
-
fingerprint: null,
|
|
8108
|
-
cacheKey: null,
|
|
8109
|
-
cacheHit: false,
|
|
8110
|
-
cacheSkipped: false,
|
|
8111
|
-
durationMs: null,
|
|
8112
|
-
startedAt: left.startedAt,
|
|
8113
|
-
phases: {
|
|
8114
|
-
...phaseDurations(left.phases, Date.parse(left.phaseStartedAt)),
|
|
8115
|
-
[left.phase]: 0
|
|
8116
|
-
}
|
|
8117
|
-
});
|
|
8118
|
-
}
|
|
8119
|
-
function parseActiveBuild(value) {
|
|
8120
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
8121
|
-
const record = value;
|
|
8122
|
-
const claim = record.claim;
|
|
8123
|
-
if (record.platform !== "ios" && record.platform !== "android" && record.platform !== "macos") return null;
|
|
8124
|
-
if (!isPhase(record.phase)) return null;
|
|
8125
|
-
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
8126
|
-
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
8127
|
-
const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
|
|
8128
|
-
const missReason = parseMissReason(record.missReason);
|
|
8129
|
-
const placement = parsePlacement(record.placement);
|
|
8130
|
-
const waitingOn = parseWaitingOn(record.waitingOn);
|
|
8131
|
-
const waitingFor = parseWaitingFor(record.waitingFor);
|
|
8132
|
-
const estimate = parseEstimate(record.estimate);
|
|
8133
|
-
const activity = parseActivity(record.activity);
|
|
8134
|
-
return {
|
|
8135
|
-
platform: record.platform,
|
|
8136
|
-
slot: typeof record.slot === "string" ? record.slot : "default",
|
|
8137
|
-
startedAt: record.startedAt,
|
|
8138
|
-
phase: record.phase,
|
|
8139
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
8140
|
-
phases,
|
|
8141
|
-
...missReason ? { missReason } : {},
|
|
8142
|
-
...missReason && record.missProvisional === true ? { missProvisional: true } : {},
|
|
8143
|
-
...placement ? { placement } : {},
|
|
8144
|
-
...waitingOn ? { waitingOn } : {},
|
|
8145
|
-
...waitingFor ? { waitingFor } : {},
|
|
8146
|
-
...typeof record.deviceSetup === "boolean" ? { deviceSetup: record.deviceSetup } : {},
|
|
8147
|
-
...record.outcome === "hit" || record.outcome === "cold" ? { outcome: record.outcome } : {},
|
|
8148
|
-
...estimate ? { estimate } : {},
|
|
8149
|
-
...activity ? { activity } : {},
|
|
8150
|
-
claim: {
|
|
8151
|
-
root: claim.root,
|
|
8152
|
-
path: typeof claim.path === "string" ? claim.path : "",
|
|
8153
|
-
claimId: claim.claimId,
|
|
8154
|
-
pid: typeof claim.pid === "number" ? claim.pid : 0
|
|
8155
|
-
}
|
|
8156
|
-
};
|
|
8157
|
-
}
|
|
8158
|
-
function parsePlacement(value) {
|
|
8159
|
-
if (!value || typeof value !== "object") return null;
|
|
8160
|
-
const { host, phase, startedAt, phaseStartedAt } = value;
|
|
8161
|
-
if ([
|
|
8162
|
-
host,
|
|
8163
|
-
phase,
|
|
8164
|
-
startedAt,
|
|
8165
|
-
phaseStartedAt
|
|
8166
|
-
].some((field) => typeof field !== "string")) return null;
|
|
8167
|
-
return {
|
|
8168
|
-
host,
|
|
8169
|
-
phase,
|
|
8170
|
-
startedAt,
|
|
8171
|
-
phaseStartedAt
|
|
8172
|
-
};
|
|
8173
|
-
}
|
|
8174
|
-
function parseWaitingFor(value) {
|
|
8175
|
-
if (!value || typeof value !== "object") return null;
|
|
8176
|
-
const { kind, inUse, max, since } = value;
|
|
8177
|
-
if (kind !== "build-slot" && kind !== "device-slot") return null;
|
|
8178
|
-
if (!Number.isInteger(inUse) || inUse < 0 || !Number.isInteger(max) || max <= 0) return null;
|
|
8179
|
-
if (typeof since !== "string" || !Number.isFinite(Date.parse(since))) return null;
|
|
8180
|
-
return {
|
|
8181
|
-
kind,
|
|
8182
|
-
inUse,
|
|
8183
|
-
max,
|
|
8184
|
-
since
|
|
8185
|
-
};
|
|
8186
|
-
}
|
|
8187
|
-
function parseActivity(value) {
|
|
8188
|
-
if (!value || typeof value !== "object") return null;
|
|
8189
|
-
const { name, startedAt } = value;
|
|
8190
|
-
if (name !== "booting" && name !== "bundling" && name !== "waiting-ready") return null;
|
|
8191
|
-
return typeof startedAt === "string" ? {
|
|
8192
|
-
name,
|
|
8193
|
-
startedAt
|
|
8194
|
-
} : null;
|
|
8195
|
-
}
|
|
8196
|
-
function parseWaitingOn(value) {
|
|
8197
|
-
const path = value?.path;
|
|
8198
|
-
return typeof path === "string" && path ? { path } : null;
|
|
8199
|
-
}
|
|
8200
|
-
function parseEstimate(value) {
|
|
8201
|
-
if (!value || typeof value !== "object") return null;
|
|
8202
|
-
const { outcome, expectedMs, basis, phaseMs, planned } = value;
|
|
8203
|
-
if (outcome !== null && outcome !== "hit" && outcome !== "cold") return null;
|
|
8204
|
-
if (expectedMs !== null && typeof expectedMs !== "number") return null;
|
|
8205
|
-
if (typeof basis !== "number" || !Array.isArray(planned) || !phaseMs || typeof phaseMs !== "object") return null;
|
|
8206
|
-
const durations = Object.entries(phaseMs).filter((entry) => isPhase(entry[0]) && typeof entry[1] === "number");
|
|
8207
|
-
return {
|
|
8208
|
-
outcome,
|
|
8209
|
-
expectedMs,
|
|
8210
|
-
basis,
|
|
8211
|
-
phaseMs: Object.fromEntries(durations),
|
|
8212
|
-
planned: planned.filter(isPhase)
|
|
8213
|
-
};
|
|
8214
|
-
}
|
|
8215
|
-
function isPhase(value) {
|
|
8216
|
-
return BUILD_PHASES.includes(value);
|
|
8217
|
-
}
|
|
8218
|
-
function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
|
|
8219
|
-
if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
|
|
8220
|
-
if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
|
|
8221
|
-
return survey.unresolved.length ? "unknown" : "stale";
|
|
8222
|
-
}
|
|
8223
|
-
function median(values) {
|
|
8224
|
-
if (!values.length) return null;
|
|
8225
|
-
const sorted = values.toSorted((a, b) => a - b);
|
|
8226
|
-
const mid = Math.floor(sorted.length / 2);
|
|
8227
|
-
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
8228
|
-
}
|
|
8229
|
-
function estimateBuild(history, platform, known, deviceSetup) {
|
|
8230
|
-
const lists = platform === "macos" ? void 0 : history?.[platform];
|
|
8231
|
-
const outcome = known ?? latestOutcome(lists);
|
|
8232
|
-
const samples = matchDeviceSetup(outcome && lists?.[outcome] || [], deviceSetup);
|
|
8233
|
-
const phaseMs = {};
|
|
8234
|
-
const planned = [];
|
|
8235
|
-
for (const phase of BUILD_PHASES) {
|
|
8236
|
-
const durations = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
|
|
8237
|
-
const ms = median(durations);
|
|
8238
|
-
if (ms === null) continue;
|
|
8239
|
-
phaseMs[phase] = ms;
|
|
8240
|
-
if (durations.length * 2 >= samples.length) planned.push(phase);
|
|
8241
|
-
}
|
|
8242
|
-
return {
|
|
8243
|
-
outcome,
|
|
8244
|
-
expectedMs: median(samples.map((sample) => sample.durationMs)),
|
|
8245
|
-
basis: samples.length,
|
|
8246
|
-
phaseMs,
|
|
8247
|
-
planned
|
|
8248
|
-
};
|
|
8249
|
-
}
|
|
8250
|
-
const MIN_TAGGED_SAMPLES = 3;
|
|
8251
|
-
function matchDeviceSetup(samples, deviceSetup) {
|
|
8252
|
-
if (deviceSetup === void 0) return samples;
|
|
8253
|
-
const tagged = samples.filter((sample) => sample.deviceSetup === deviceSetup);
|
|
8254
|
-
if (deviceSetup || tagged.length >= MIN_TAGGED_SAMPLES) return tagged;
|
|
8255
|
-
return samples.filter((sample) => sample.deviceSetup !== true);
|
|
8256
|
-
}
|
|
8257
|
-
function latestOutcome(lists) {
|
|
8258
|
-
let latest = null;
|
|
8259
|
-
for (const outcome of ["hit", "cold"]) {
|
|
8260
|
-
const last = lists?.[outcome]?.at(-1);
|
|
8261
|
-
const at = last ? Date.parse(last.at) : NaN;
|
|
8262
|
-
if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
|
|
8263
|
-
outcome,
|
|
8264
|
-
at
|
|
8265
|
-
};
|
|
8266
|
-
}
|
|
8267
|
-
return latest?.outcome ?? null;
|
|
8268
|
-
}
|
|
8269
|
-
function buildReport(record, { state, history }) {
|
|
8270
|
-
const estimate = record.estimate ?? estimateBuild(history, record.platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
|
|
8271
|
-
const plannedPhases = estimate.planned.flatMap((phase) => {
|
|
8272
|
-
const expectedMs = estimate.phaseMs[phase];
|
|
8273
|
-
return expectedMs === void 0 ? [] : [{
|
|
8274
|
-
phase,
|
|
8275
|
-
expectedMs
|
|
8276
|
-
}];
|
|
8277
|
-
});
|
|
8278
|
-
const completedPhaseMs = completedPhaseDurations(record.phases);
|
|
8279
|
-
return {
|
|
8280
|
-
platform: record.platform,
|
|
8281
|
-
slot: record.slot,
|
|
8282
|
-
state,
|
|
8283
|
-
phase: record.phase,
|
|
8284
|
-
startedAt: record.startedAt,
|
|
8285
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
8286
|
-
outcome: estimate.outcome,
|
|
8287
|
-
outcomeKnown: record.outcome !== void 0,
|
|
8288
|
-
...record.outcome && record.phases.some(({ phase }) => phase === "cache-lookup") ? { cacheLookupOutcome: record.outcome === "hit" ? "hit" : "miss" } : {},
|
|
8289
|
-
expectedMs: estimate.expectedMs,
|
|
8290
|
-
expectedPhaseMs: estimate.phaseMs[record.phase] ?? null,
|
|
8291
|
-
...completedPhaseMs ? { completedPhaseMs } : {},
|
|
8292
|
-
basis: estimate.basis,
|
|
8293
|
-
plannedPhases: plannedPhases.length ? plannedPhases : null,
|
|
8294
|
-
...record.missReason ? { missReason: record.missReason } : {},
|
|
8295
|
-
...record.missReason && record.missProvisional ? { missProvisional: true } : {},
|
|
8296
|
-
placement: record.placement ?? "local",
|
|
8297
|
-
...record.waitingOn ? { waitingOn: record.waitingOn } : {},
|
|
8298
|
-
...record.waitingFor ? { waitingFor: record.waitingFor } : {},
|
|
8299
|
-
...record.activity ? { activity: { ...record.activity } } : {}
|
|
8300
|
-
};
|
|
8301
|
-
}
|
|
8302
|
-
/**
|
|
8303
|
-
* The run's `bundling` activity with Metro's percent, when the request Metro reports in flight is the one the activity
|
|
8304
|
-
* started on: same platform and same start, since both come from the request's `bundle_response_started` record.
|
|
8305
|
-
*/
|
|
8306
|
-
function bundlingActivity(activity, platform, bundle) {
|
|
8307
|
-
if (activity?.name !== "bundling" || !bundle?.bundling || bundle.percent === void 0) return activity;
|
|
8308
|
-
if (bundle.platform !== platform || bundle.startedAt !== activity.startedAt) return activity;
|
|
8309
|
-
return {
|
|
8310
|
-
...activity,
|
|
8311
|
-
percent: bundle.percent
|
|
8312
|
-
};
|
|
8313
|
-
}
|
|
8314
|
-
function remainingText(remainingMs) {
|
|
8315
|
-
return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
|
|
8316
|
-
}
|
|
8317
|
-
function activityText({ name, percent, startedAt }, now) {
|
|
8318
|
-
return `${name === "booting" ? "booting" : name === "waiting-ready" ? "waiting for app ready" : percent === void 0 ? "bundling JS" : `bundling JS ${percent}%`}, ${formatElapsed(Math.max(0, now - Date.parse(startedAt)))}`;
|
|
8319
|
-
}
|
|
8320
|
-
function buildStatusLine(report, now) {
|
|
8321
|
-
const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
|
|
8322
|
-
if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
|
|
8323
|
-
const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
|
|
8324
|
-
const remote = typeof report.placement === "object" ? ` on ${report.placement.host} (${report.placement.phase}, ${formatElapsed(Math.max(0, now - Date.parse(report.placement.phaseStartedAt)))})` : "";
|
|
8325
|
-
const waiting = report.waitingOn ? ` on ${report.waitingOn.path}` : "";
|
|
8326
|
-
const activity = report.activity ? ` (${activityText(report.activity, now)})` : "";
|
|
8327
|
-
const head = `build: ${report.platform}${slot} ${report.phase}${activity}${waiting}${remote}, ${formatElapsed(elapsedMs)} elapsed`;
|
|
8328
|
-
if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
|
|
8329
|
-
if (report.expectedMs === null) return head;
|
|
8330
|
-
const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
|
|
8331
|
-
const remainingMs = report.expectedMs - elapsedMs;
|
|
8332
|
-
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
8333
|
-
}
|
|
8334
|
-
//#endregion
|
|
8335
|
-
//#region src/commands/gc/idle.ts
|
|
8336
|
-
function findOwnedDeviceActivity({ config, sims, androidSerial, readActivity, deadProjects = [] }) {
|
|
8337
|
-
const booted = new Map(sims.filter((sim) => sim.state === "Booted").map((sim) => [sim.udid, sim.name]));
|
|
8338
|
-
const dead = new Set(deadProjects);
|
|
8339
|
-
const found = [];
|
|
8340
|
-
for (const [project, record] of Object.entries(config?.projects ?? {})) {
|
|
8341
|
-
if (dead.has(project)) continue;
|
|
8342
|
-
for (const { slot, platforms } of projectDeviceSlots(record)) {
|
|
8343
|
-
const ios = platforms.ios;
|
|
8344
|
-
if (ios?.owned && ios.deviceUdid && booted.has(ios.deviceUdid)) found.push({
|
|
8345
|
-
kind: "ios",
|
|
8346
|
-
id: ios.deviceUdid,
|
|
8347
|
-
name: booted.get(ios.deviceUdid) ?? ios.deviceUdid,
|
|
8348
|
-
project,
|
|
8349
|
-
slot,
|
|
8350
|
-
activity: readActivity({
|
|
8351
|
-
platform: "ios",
|
|
8352
|
-
id: ios.deviceUdid,
|
|
8353
|
-
slot,
|
|
8354
|
-
workspace: project
|
|
8355
|
-
})
|
|
8356
|
-
});
|
|
8357
|
-
const android = platforms.android;
|
|
8358
|
-
const serial = android?.owned && android.avdName ? androidSerial(android.avdName) : null;
|
|
8359
|
-
if (android?.avdName && serial) found.push({
|
|
8360
|
-
kind: "android",
|
|
8361
|
-
id: android.avdName,
|
|
8362
|
-
name: android.avdName,
|
|
8363
|
-
project,
|
|
8364
|
-
slot,
|
|
8365
|
-
activity: readActivity({
|
|
8366
|
-
platform: "android",
|
|
8367
|
-
id: serial,
|
|
8368
|
-
slot,
|
|
8369
|
-
workspace: project
|
|
8370
|
-
})
|
|
8371
|
-
});
|
|
8372
|
-
}
|
|
8373
|
-
}
|
|
8374
|
-
return found;
|
|
8375
|
-
}
|
|
8376
|
-
function findIdleDevices({ buildInProgress, now, ...inputs }) {
|
|
8377
|
-
return idleDevicesFromActivity(findOwnedDeviceActivity(inputs), buildInProgress, now);
|
|
8378
|
-
}
|
|
8379
|
-
function idleDevicesFromActivity(devices, buildInProgress, now) {
|
|
8380
|
-
return devices.filter((device) => device.activity.state === "idle").map(({ kind, id, name, project, slot, activity }) => ({
|
|
8381
|
-
kind,
|
|
8382
|
-
id,
|
|
8383
|
-
name,
|
|
8384
|
-
project,
|
|
8385
|
-
slot,
|
|
8386
|
-
lastActivityAt: activity.lastActivityAt ?? null,
|
|
8387
|
-
idleForMs: idleForMs(activity, now),
|
|
8388
|
-
buildInProgress: buildInProgress(project)
|
|
8389
|
-
}));
|
|
8390
|
-
}
|
|
8391
|
-
function idleShutdownCandidates(devices, idleMs) {
|
|
8392
|
-
return devices.filter((d) => !d.buildInProgress && d.idleForMs !== null && d.idleForMs >= idleMs);
|
|
8393
|
-
}
|
|
8394
|
-
function parseIdleDuration(value) {
|
|
8395
|
-
const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value.trim());
|
|
8396
|
-
if (!match) return null;
|
|
8397
|
-
const unit = {
|
|
8398
|
-
m: 6e4,
|
|
8399
|
-
h: 36e5,
|
|
8400
|
-
d: 864e5
|
|
8401
|
-
}[match[2]];
|
|
8402
|
-
return Number(match[1]) * unit;
|
|
8403
|
-
}
|
|
8404
|
-
function workspaceBuildInProgress(project) {
|
|
8405
|
-
const record = parseActiveBuild(readWorkspaceState$1(project)?.[ACTIVE_BUILD_KEY]);
|
|
8406
|
-
if (!record) return false;
|
|
8407
|
-
try {
|
|
8408
|
-
return activeBuildState(record.claim) !== "stale";
|
|
8409
|
-
} catch {
|
|
8410
|
-
return true;
|
|
8411
|
-
}
|
|
8412
|
-
}
|
|
8413
|
-
function deviceActivityInputs(config, sims, now, env) {
|
|
8414
|
-
const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
|
|
8415
|
-
return {
|
|
8416
|
-
config,
|
|
8417
|
-
sims,
|
|
8418
|
-
readActivity: createActivityReader({
|
|
8419
|
-
now,
|
|
8420
|
-
env
|
|
8421
|
-
}),
|
|
8422
|
-
androidSerial: (avdName) => {
|
|
8423
|
-
try {
|
|
8424
|
-
return resolve(avdName).serial ?? null;
|
|
8425
|
-
} catch {
|
|
8426
|
-
return null;
|
|
8427
|
-
}
|
|
8428
|
-
}
|
|
8429
|
-
};
|
|
8430
|
-
}
|
|
8431
|
-
function collectOwnedDeviceActivity(config, sims, now = Date.now(), env) {
|
|
8432
|
-
return findOwnedDeviceActivity(deviceActivityInputs(config, sims, now, env));
|
|
8433
|
-
}
|
|
8434
|
-
function collectIdleDevices(config, sims, deadProjects, now = Date.now(), env) {
|
|
8435
|
-
return findIdleDevices({
|
|
8436
|
-
...deviceActivityInputs(config, sims, now, env),
|
|
8437
|
-
deadProjects,
|
|
8438
|
-
now,
|
|
8439
|
-
buildInProgress: workspaceBuildInProgress
|
|
8440
|
-
});
|
|
8441
|
-
}
|
|
8442
|
-
async function deviceActivityInputsAsync(config, sims, now, env, deadProjects = [], signal, operation) {
|
|
8443
|
-
const resolve = ownedAvdSerialResolverAsync({
|
|
8444
|
-
timeoutMs: 5e3,
|
|
8445
|
-
signal,
|
|
8446
|
-
operation
|
|
8447
|
-
});
|
|
8448
|
-
const serials = /* @__PURE__ */ new Map();
|
|
8449
|
-
for (const [project, record] of Object.entries(config?.projects ?? {})) {
|
|
8450
|
-
signal?.throwIfAborted();
|
|
8451
|
-
if (deadProjects.includes(project)) continue;
|
|
8452
|
-
for (const { platforms } of projectDeviceSlots(record)) {
|
|
8453
|
-
const android = platforms.android;
|
|
8454
|
-
if (!android?.owned || !android.avdName || serials.has(android.avdName)) continue;
|
|
8455
|
-
try {
|
|
8456
|
-
serials.set(android.avdName, (await resolve(android.avdName)).serial ?? null);
|
|
8457
|
-
} catch (error) {
|
|
8458
|
-
if (error instanceof WorkspaceProcessCleanupError) throw error;
|
|
8459
|
-
signal?.throwIfAborted();
|
|
8460
|
-
serials.set(android.avdName, null);
|
|
8461
|
-
}
|
|
8462
|
-
}
|
|
8463
|
-
}
|
|
8464
|
-
return {
|
|
8465
|
-
config,
|
|
8466
|
-
sims,
|
|
8467
|
-
readActivity: createActivityReaderAsync({
|
|
8468
|
-
now,
|
|
8469
|
-
env,
|
|
8470
|
-
signal,
|
|
8471
|
-
operation
|
|
8472
|
-
}),
|
|
8473
|
-
androidSerial: (name) => serials.get(name) ?? null
|
|
8474
|
-
};
|
|
8475
|
-
}
|
|
8476
|
-
async function collectOwnedDeviceActivityAsync(config, sims, now = Date.now(), env, signal, operation) {
|
|
8477
|
-
const devices = findOwnedDeviceActivity(await deviceActivityInputsAsync(config, sims, now, env, [], signal, operation));
|
|
8478
|
-
return Promise.all(devices.map(async (device) => Object.assign({}, device, { activity: await device.activity })));
|
|
8479
|
-
}
|
|
8480
|
-
async function collectIdleDevicesAsync(config, sims, deadProjects, now = Date.now(), env, signal, operation) {
|
|
8481
|
-
const pending = findOwnedDeviceActivity({
|
|
8482
|
-
...await deviceActivityInputsAsync(config, sims, now, env, deadProjects, signal, operation),
|
|
8483
|
-
deadProjects
|
|
8484
|
-
});
|
|
8485
|
-
return idleDevicesFromActivity(await Promise.all(pending.map(async (device) => Object.assign({}, device, { activity: await device.activity }))), workspaceBuildInProgress, now);
|
|
8486
|
-
}
|
|
8487
|
-
function idleDeviceLines(devices) {
|
|
8488
|
-
if (devices.length === 0) return [];
|
|
8489
|
-
return [`Idle owned devices (${devices.length}) - booted with no driver, claim, or recent activity:`, ...devices.map((d) => {
|
|
8490
|
-
const slot = d.slot === "default" ? "" : ` [${d.slot}]`;
|
|
8491
|
-
const idle = d.idleForMs === null ? "idle for an unknown time" : `idle ${formatLongDuration(d.idleForMs)}`;
|
|
8492
|
-
const build = d.buildInProgress ? ", build in progress" : "";
|
|
8493
|
-
return ` ${d.kind}${slot} ${d.name} (${d.project}) -- ${idle}${build}`;
|
|
8494
|
-
})];
|
|
8495
|
-
}
|
|
8496
|
-
async function shutDownIdleDevices(devices, idleMs, recollect, { log, record } = GC_OUTPUT, signal, operation) {
|
|
8497
|
-
signal?.throwIfAborted();
|
|
8498
|
-
const candidates = idleShutdownCandidates(devices, idleMs);
|
|
8499
|
-
const shutDown = [];
|
|
8500
|
-
if (candidates.length === 0) {
|
|
8501
|
-
log(chalk.dim(`No owned device has been idle for ${formatLongDuration(idleMs)} or more.`));
|
|
8502
|
-
return {
|
|
8503
|
-
failures: 0,
|
|
8504
|
-
shutDown
|
|
8505
|
-
};
|
|
8506
|
-
}
|
|
8507
|
-
const fresh = idleShutdownCandidates(await recollect(), idleMs);
|
|
8508
|
-
signal?.throwIfAborted();
|
|
8509
|
-
let failures = 0;
|
|
8510
|
-
for (const device of candidates) {
|
|
8511
|
-
signal?.throwIfAborted();
|
|
8512
|
-
const what = `${device.kind} ${device.name}`;
|
|
8513
|
-
const current = fresh.find((d) => d.kind === device.kind && d.id === device.id && d.project === device.project && d.slot === device.slot);
|
|
8514
|
-
if (!current) {
|
|
8515
|
-
log(chalk.dim(`Kept ${what}: it is no longer idle for ${formatLongDuration(idleMs)}.`));
|
|
8516
|
-
record("idleDevice", "kept", device.name, {
|
|
8517
|
-
id: device.id,
|
|
8518
|
-
detail: `it is no longer idle for ${formatLongDuration(idleMs)}`
|
|
8519
|
-
});
|
|
8520
|
-
continue;
|
|
8521
|
-
}
|
|
8522
|
-
const outcome = device.kind === "ios" ? await teardownOwnedIosSim(device.id, {
|
|
8523
|
-
label: device.name,
|
|
8524
|
-
operation
|
|
8525
|
-
}) : await teardownOwnedAvd(device.id, {
|
|
8526
|
-
owner: {
|
|
8527
|
-
projectPath: device.project,
|
|
8528
|
-
slot: device.slot
|
|
8529
|
-
},
|
|
8530
|
-
operation
|
|
8531
|
-
});
|
|
8532
|
-
if (outcome.status === "torn-down") {
|
|
8533
|
-
shutDown.push(device);
|
|
8534
|
-
log(chalk.green(`Shut down ${what}, idle ${formatLongDuration(current.idleForMs)}`));
|
|
8535
|
-
record("idleDevice", "done", device.name, {
|
|
8536
|
-
id: device.id,
|
|
8537
|
-
detail: `idle ${formatLongDuration(current.idleForMs)}`
|
|
8538
|
-
});
|
|
8539
|
-
} else if (outcome.status === "missing") log(chalk.dim(`${what} is already gone; nothing to shut down.`));
|
|
8540
|
-
else if (outcome.status === "skipped") {
|
|
8541
|
-
log(chalk.yellow(`Skipped ${what}: ${outcome.reason}`));
|
|
8542
|
-
record("idleDevice", "kept", device.name, {
|
|
8543
|
-
id: device.id,
|
|
8544
|
-
detail: outcome.reason
|
|
8545
|
-
});
|
|
8546
|
-
} else {
|
|
8547
|
-
failures++;
|
|
8548
|
-
log(chalk.red(`Failed to shut down ${what}: ${outcome.reason}`));
|
|
8549
|
-
record("idleDevice", "failed", device.name, {
|
|
8550
|
-
id: device.id,
|
|
8551
|
-
detail: outcome.reason
|
|
8552
|
-
});
|
|
8553
|
-
}
|
|
8554
|
-
}
|
|
8555
|
-
return {
|
|
8556
|
-
failures,
|
|
8557
|
-
shutDown
|
|
8558
|
-
};
|
|
8559
|
-
}
|
|
8560
|
-
//#endregion
|
|
8561
|
-
//#region src/maintenance/log.ts
|
|
8562
|
-
function openRetainedLog(file, settings) {
|
|
8563
|
-
ensurePrivateDir(dirname(file));
|
|
8564
|
-
const rotated = rotatedLogPath(file);
|
|
8565
|
-
withDirLock(`${file}.lock`, () => {
|
|
8566
|
-
try {
|
|
8567
|
-
if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
|
|
8568
|
-
} catch {}
|
|
8569
|
-
});
|
|
8570
|
-
return createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
|
|
8571
|
-
}
|
|
8572
|
-
function maintenanceLogger(settings, pass, trigger) {
|
|
8573
|
-
const file = maintenanceNdjsonFile();
|
|
8574
|
-
const writer = openRetainedLog(file, settings);
|
|
8575
|
-
return {
|
|
8576
|
-
write(event, level, msg, fields = {}) {
|
|
8577
|
-
if (level === "debug" && !settings.logChecks) return null;
|
|
8578
|
-
const record = {
|
|
8579
|
-
...fields,
|
|
8580
|
-
ts: Date.now(),
|
|
8581
|
-
src: "maintenance",
|
|
8582
|
-
level,
|
|
8583
|
-
msg,
|
|
8584
|
-
event,
|
|
8585
|
-
pass,
|
|
8586
|
-
trigger,
|
|
8587
|
-
mode: settings.mode === "on" ? "on" : "report"
|
|
8588
|
-
};
|
|
8589
|
-
if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
|
|
8590
|
-
if (typeof fields.workspace === "string" && [
|
|
8591
|
-
"maintenance_action",
|
|
8592
|
-
"maintenance_failure",
|
|
8593
|
-
"maintenance_skip"
|
|
8594
|
-
].includes(event)) {
|
|
8595
|
-
const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
|
|
8596
|
-
try {
|
|
8597
|
-
if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
|
|
8598
|
-
} finally {
|
|
8599
|
-
workspace.close();
|
|
8600
|
-
}
|
|
8601
|
-
}
|
|
8602
|
-
return record;
|
|
8603
|
-
},
|
|
8604
|
-
close: () => writer.close()
|
|
8605
|
-
};
|
|
8606
|
-
}
|
|
8607
|
-
//#endregion
|
|
8608
|
-
//#region src/commands/gc/log.ts
|
|
8609
|
-
const VERBS = {
|
|
8610
|
-
done: "Cleared",
|
|
8611
|
-
kept: "Kept",
|
|
8612
|
-
failed: "Failed to clear"
|
|
8613
|
-
};
|
|
8614
|
-
function gcLogRecord(run, result, ts) {
|
|
8615
|
-
const path = [result.id, result.label].find((value) => value !== null && isAbsolute(value)) ?? null;
|
|
8616
|
-
const size = result.bytes ? ` (${formatBytes(result.bytes)})` : "";
|
|
8617
|
-
const why = result.detail ? `: ${result.detail}` : "";
|
|
8618
|
-
return {
|
|
8619
|
-
ts,
|
|
8620
|
-
src: "gc",
|
|
8621
|
-
level: result.status === "failed" ? "error" : "info",
|
|
8622
|
-
msg: `${VERBS[result.status]} ${result.kind} ${result.label}${size}${why}`,
|
|
8623
|
-
event: "gc_item",
|
|
8624
|
-
runId: run.runId ?? runId(),
|
|
8625
|
-
trigger: run.trigger,
|
|
8626
|
-
...run.via === void 0 ? {} : { via: run.via },
|
|
8627
|
-
...run.options === void 0 ? {} : { options: run.options },
|
|
8628
|
-
kind: result.kind,
|
|
8629
|
-
status: result.status,
|
|
8630
|
-
label: result.label,
|
|
8631
|
-
id: result.id,
|
|
8632
|
-
path,
|
|
8633
|
-
bytes: result.bytes,
|
|
8634
|
-
detail: result.detail
|
|
7397
|
+
ts,
|
|
7398
|
+
src: "gc",
|
|
7399
|
+
level: result.status === "failed" ? "error" : "info",
|
|
7400
|
+
msg: `${VERBS[result.status]} ${result.kind} ${result.label}${size}${why}`,
|
|
7401
|
+
event: "gc_item",
|
|
7402
|
+
runId: run.runId ?? runId(),
|
|
7403
|
+
trigger: run.trigger,
|
|
7404
|
+
...run.via === void 0 ? {} : { via: run.via },
|
|
7405
|
+
...run.options === void 0 ? {} : { options: run.options },
|
|
7406
|
+
kind: result.kind,
|
|
7407
|
+
status: result.status,
|
|
7408
|
+
label: result.label,
|
|
7409
|
+
id: result.id,
|
|
7410
|
+
path,
|
|
7411
|
+
bytes: result.bytes,
|
|
7412
|
+
detail: result.detail
|
|
8635
7413
|
};
|
|
8636
7414
|
}
|
|
8637
7415
|
function openGcLog(run) {
|
|
@@ -8704,6 +7482,38 @@ function gcOptionsOf(opts) {
|
|
|
8704
7482
|
};
|
|
8705
7483
|
}
|
|
8706
7484
|
//#endregion
|
|
7485
|
+
//#region src/maintenance/pressure.ts
|
|
7486
|
+
/**
|
|
7487
|
+
* The free-disk floor of each level in MiB. Level 2 has no floor of its own: it runs when level 1 left free disk
|
|
7488
|
+
* under the budget floor, and stops once free disk is back above it. Its urgent threshold only sets the reported level.
|
|
7489
|
+
*/
|
|
7490
|
+
function levelFloors(budget, settings) {
|
|
7491
|
+
const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
|
|
7492
|
+
return {
|
|
7493
|
+
1: floor,
|
|
7494
|
+
2: floor,
|
|
7495
|
+
3: Math.max(settings.criticalFreeDiskGb * 1024, budget.hardFloorDiskMb),
|
|
7496
|
+
urgent: settings.urgentFreeDiskGb * 1024
|
|
7497
|
+
};
|
|
7498
|
+
}
|
|
7499
|
+
function diskPressureLevel(freeMb, budget, settings) {
|
|
7500
|
+
const floors = levelFloors(budget, settings);
|
|
7501
|
+
if (freeMb < floors[3]) return 3;
|
|
7502
|
+
if (freeMb < floors.urgent) return 2;
|
|
7503
|
+
return freeMb < floors[1] ? 1 : 0;
|
|
7504
|
+
}
|
|
7505
|
+
function lowestFree(disk) {
|
|
7506
|
+
return disk.length ? Math.min(...disk.map((volume) => volume.freeMb)) : Infinity;
|
|
7507
|
+
}
|
|
7508
|
+
/** Whether an action planned at a pressure level may still run with this much free disk. */
|
|
7509
|
+
function levelStillShort(action, freeMb, budget, settings) {
|
|
7510
|
+
return action.level === void 0 || freeMb < levelFloors(budget, settings)[action.level];
|
|
7511
|
+
}
|
|
7512
|
+
/** The protection window in milliseconds: protectRecentHours, or maintenance.pressureProtectMinutes for actions of level 2 and 3. */
|
|
7513
|
+
function protectWindowMs(action, settings) {
|
|
7514
|
+
return action.level === void 0 ? settings.protectRecentHours * 36e5 : settings.pressureProtectMinutes * 6e4;
|
|
7515
|
+
}
|
|
7516
|
+
//#endregion
|
|
8707
7517
|
//#region src/supervisor/stop-cause.ts
|
|
8708
7518
|
function requestDevServerStop(root, processToken, requester) {
|
|
8709
7519
|
if (!processToken) return;
|
|
@@ -9229,9 +8039,10 @@ async function reclaimWorkspaceOutputs({ root, dryRun, now, note, record, diskRe
|
|
|
9229
8039
|
targets: clearable.map((entry) => entry.projectRoot),
|
|
9230
8040
|
failures: 0
|
|
9231
8041
|
};
|
|
8042
|
+
const locked = report.workspaces.filter((entry) => keptByLock(entry) && entry.projectRoot !== null && other(entry.projectRoot));
|
|
9232
8043
|
const targets = [];
|
|
9233
8044
|
let failures = 0;
|
|
9234
|
-
for (const entry of clearable) {
|
|
8045
|
+
for (const entry of [...locked, ...clearable]) {
|
|
9235
8046
|
const result = await clearWorkspaceOutputs({
|
|
9236
8047
|
...report,
|
|
9237
8048
|
workspaces: [entry]
|
|
@@ -9256,13 +8067,26 @@ function cacheLabel(cache) {
|
|
|
9256
8067
|
function trimmableCaches(env = process.env, cwd) {
|
|
9257
8068
|
return planCacheEmptying(discoverCaches(env, cwd), false, env).filter((cache) => cache.prune !== "report-only" && cache.prune !== "atomic" && !cache.machineGlobal);
|
|
9258
8069
|
}
|
|
9259
|
-
async function reclaimStaleCacheEntries({ dryRun, note, record, env, cwd, signal }) {
|
|
8070
|
+
async function reclaimStaleCacheEntries({ dryRun, note, record, env, cwd, now, freeMb, signal }) {
|
|
9260
8071
|
const caches = trimmableCaches(env, cwd);
|
|
9261
8072
|
if (dryRun) return {
|
|
9262
8073
|
targets: caches.map(cacheLabel),
|
|
9263
8074
|
failures: 0
|
|
9264
8075
|
};
|
|
8076
|
+
const current = {
|
|
8077
|
+
at: now,
|
|
8078
|
+
freeMb,
|
|
8079
|
+
marker: sweepMarker(caches, 14)
|
|
8080
|
+
};
|
|
8081
|
+
if (canSkipEmptySweep(readEmptySweep(), current)) {
|
|
8082
|
+
note(chalk.dim(phaseLine("budget", `cache trim skipped: the last one, under ${EMPTY_SWEEP_WINDOW_MS / 6e4} minutes ago with the same caches and about the same free disk, found nothing older than 14d`)));
|
|
8083
|
+
return {
|
|
8084
|
+
targets: [],
|
|
8085
|
+
failures: 0
|
|
8086
|
+
};
|
|
8087
|
+
}
|
|
9265
8088
|
const { trimmed, failures } = await trimCaches(caches, 14, stepOutput(note, record), signal);
|
|
8089
|
+
writeEmptySweep(trimmed.length === 0 && failures === 0 ? current : null);
|
|
9266
8090
|
return {
|
|
9267
8091
|
targets: trimmed.map(cacheLabel),
|
|
9268
8092
|
failures
|
|
@@ -9310,23 +8134,22 @@ async function spaceUsers(env = process.env, signal, operation) {
|
|
|
9310
8134
|
["Android emulators", join(home, ".android", "avd")]
|
|
9311
8135
|
];
|
|
9312
8136
|
const measured = /* @__PURE__ */ new Set();
|
|
9313
|
-
const
|
|
8137
|
+
const targets = [];
|
|
9314
8138
|
for (const [label, path] of candidates) {
|
|
9315
8139
|
const canonical = canonicalPath(path);
|
|
9316
8140
|
if (measured.has(canonical) || [...measured].some((dir) => canonical.startsWith(`${dir}${sep}`))) continue;
|
|
9317
8141
|
measured.add(canonical);
|
|
9318
|
-
if (
|
|
9319
|
-
const bytes = await measuredDirectorySizeAsync(path, {
|
|
9320
|
-
timeoutMs: USAGE_TIMEOUT_MS,
|
|
9321
|
-
signal,
|
|
9322
|
-
operation
|
|
9323
|
-
});
|
|
9324
|
-
if (bytes) users.push({
|
|
9325
|
-
label: `${label} ${path}`,
|
|
9326
|
-
bytes
|
|
9327
|
-
});
|
|
8142
|
+
if (existsSync(path)) targets.push([label, path]);
|
|
9328
8143
|
}
|
|
9329
|
-
|
|
8144
|
+
const sizes = await Promise.all(targets.map(([, path]) => measuredDirectorySizeAsync(path, {
|
|
8145
|
+
timeoutMs: USAGE_TIMEOUT_MS,
|
|
8146
|
+
signal,
|
|
8147
|
+
operation
|
|
8148
|
+
})));
|
|
8149
|
+
return targets.flatMap(([label, path], index) => sizes[index] ? [{
|
|
8150
|
+
label: `${label} ${path}`,
|
|
8151
|
+
bytes: sizes[index]
|
|
8152
|
+
}] : []).toSorted((a, b) => b.bytes - a.bytes).map(({ label, bytes }) => `${label}: ${formatBytes(bytes)}`);
|
|
9330
8153
|
}
|
|
9331
8154
|
const DEFAULT_DEPS = {
|
|
9332
8155
|
volumes: readVolumeSpace,
|
|
@@ -9390,6 +8213,7 @@ async function enforceBudget({ root, note, dryRun = false, budget: resolved, env
|
|
|
9390
8213
|
note,
|
|
9391
8214
|
record: gcResults?.record,
|
|
9392
8215
|
now: deps.now(),
|
|
8216
|
+
freeMb: lowestFree(measure.volumes),
|
|
9393
8217
|
diskRecovered: async () => budgetShortfalls(budget, {
|
|
9394
8218
|
volumes: await (deps.volumesAsync?.(paths) ?? deps.volumes(paths)),
|
|
9395
8219
|
memory: null
|
|
@@ -9546,5 +8370,139 @@ function budgetLine(report) {
|
|
|
9546
8370
|
const { budget } = report;
|
|
9547
8371
|
return `${report.volumes.length ? `${report.volumes.map((v) => `${v.freeGb} GB free on ${v.volume}`).join(", ")} (reclaims below ${Math.max(budget.minFreeDiskGb, budget.hardFloorDiskGb)} GB, ${budget.hardFloorDiskGb ? `refuses below ${budget.hardFloorDiskGb} GB` : "never refuses"})` : "disk budget off"}; ${report.memory ? `roughly ${report.memory.committedGb} GB of a ${budget.maxCommittedMemoryGb} GB memory budget committed` : "memory budget off"}`;
|
|
9548
8372
|
}
|
|
8373
|
+
function ccacheInstallCommand(platform = process.platform) {
|
|
8374
|
+
return platform === "darwin" ? "brew install ccache" : platform === "linux" ? "sudo apt install ccache" : "install ccache";
|
|
8375
|
+
}
|
|
8376
|
+
const CCACHE_SLOPPINESS = "pch_defines,time_macros";
|
|
8377
|
+
const STATS_LOG_FILE = "ccache-stats.log";
|
|
8378
|
+
const CCACHE_UNAVAILABLE = {
|
|
8379
|
+
status: "unavailable",
|
|
8380
|
+
hits: null,
|
|
8381
|
+
misses: null,
|
|
8382
|
+
hitRatePercent: null
|
|
8383
|
+
};
|
|
8384
|
+
const CCACHE_NOT_RUN = {
|
|
8385
|
+
status: "not-run",
|
|
8386
|
+
hits: null,
|
|
8387
|
+
misses: null,
|
|
8388
|
+
hitRatePercent: null
|
|
8389
|
+
};
|
|
8390
|
+
function ccacheStatsLog(root) {
|
|
8391
|
+
return join(workspaceLogsDir$1(root), STATS_LOG_FILE);
|
|
8392
|
+
}
|
|
8393
|
+
function ccacheMaxSize(config = loadConfig$1(), env = process.env) {
|
|
8394
|
+
const { value, error } = machineNumber("caches.ccacheMaxGb", config, env);
|
|
8395
|
+
return error || value === void 0 ? "5G" : `${value}G`;
|
|
8396
|
+
}
|
|
8397
|
+
function ccacheEnvironment({ binary, dir, workspaceRoot, statsLog, maxSize = "5G" }) {
|
|
8398
|
+
return {
|
|
8399
|
+
CMAKE_C_COMPILER_LAUNCHER: binary,
|
|
8400
|
+
CMAKE_CXX_COMPILER_LAUNCHER: binary,
|
|
8401
|
+
CCACHE_DIR: dir,
|
|
8402
|
+
CCACHE_BASEDIR: workspaceRoot,
|
|
8403
|
+
CCACHE_NOHASHDIR: "true",
|
|
8404
|
+
CCACHE_SLOPPINESS,
|
|
8405
|
+
CCACHE_MAXSIZE: maxSize,
|
|
8406
|
+
CCACHE_STATSLOG: statsLog
|
|
8407
|
+
};
|
|
8408
|
+
}
|
|
8409
|
+
function parseCcacheBinary(output) {
|
|
8410
|
+
const first = String(output ?? "").split("\n")[0]?.trim();
|
|
8411
|
+
if (!first || !isAbsolute(first)) return null;
|
|
8412
|
+
return first;
|
|
8413
|
+
}
|
|
8414
|
+
const CMAKE_LAUNCHER = /CMAKE_(C|CXX)_COMPILER_LAUNCHER\b/;
|
|
8415
|
+
function projectCmakeLauncher(source) {
|
|
8416
|
+
if (typeof source !== "string") return null;
|
|
8417
|
+
const match = CMAKE_LAUNCHER.exec(source);
|
|
8418
|
+
return match ? `CMAKE_${match[1]}_COMPILER_LAUNCHER` : null;
|
|
8419
|
+
}
|
|
8420
|
+
const HIT_COUNTERS = /* @__PURE__ */ new Set(["direct_cache_hit", "preprocessed_cache_hit"]);
|
|
8421
|
+
function parseCcacheStatsLog(text) {
|
|
8422
|
+
if (typeof text !== "string") return null;
|
|
8423
|
+
let hits = 0;
|
|
8424
|
+
let misses = 0;
|
|
8425
|
+
for (const raw of text.split("\n")) {
|
|
8426
|
+
const line = raw.trim();
|
|
8427
|
+
if (HIT_COUNTERS.has(line)) hits += 1;
|
|
8428
|
+
else if (line === "cache_miss") misses += 1;
|
|
8429
|
+
}
|
|
8430
|
+
const total = hits + misses;
|
|
8431
|
+
if (total === 0) return null;
|
|
8432
|
+
return {
|
|
8433
|
+
status: "reported",
|
|
8434
|
+
hits,
|
|
8435
|
+
misses,
|
|
8436
|
+
hitRatePercent: Math.round(hits / total * 1e3) / 10
|
|
8437
|
+
};
|
|
8438
|
+
}
|
|
8439
|
+
function readCcacheActivity(statsLog) {
|
|
8440
|
+
let text;
|
|
8441
|
+
try {
|
|
8442
|
+
text = readFileSync(statsLog, "utf-8");
|
|
8443
|
+
} catch {
|
|
8444
|
+
return CCACHE_UNAVAILABLE;
|
|
8445
|
+
}
|
|
8446
|
+
return parseCcacheStatsLog(text) ?? CCACHE_UNAVAILABLE;
|
|
8447
|
+
}
|
|
8448
|
+
function ccacheActivityLine(activity) {
|
|
8449
|
+
if (activity.status === "reported") return `${activity.hits} hits / ${activity.misses} misses (${activity.hitRatePercent}%)`;
|
|
8450
|
+
if (activity.status === "not-run") return "not run; artifact cache supplied the app";
|
|
8451
|
+
return "unavailable; no C++ compile went through ccache";
|
|
8452
|
+
}
|
|
8453
|
+
function lookupCcache() {
|
|
8454
|
+
try {
|
|
8455
|
+
return parseCcacheBinary(getExecutor().findExecutable("ccache"));
|
|
8456
|
+
} catch {
|
|
8457
|
+
return null;
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8460
|
+
function readOrNull(file) {
|
|
8461
|
+
try {
|
|
8462
|
+
return readFileSync(file, "utf-8");
|
|
8463
|
+
} catch {
|
|
8464
|
+
return null;
|
|
8465
|
+
}
|
|
8466
|
+
}
|
|
8467
|
+
function canonical(root) {
|
|
8468
|
+
try {
|
|
8469
|
+
return realpathSync(root);
|
|
8470
|
+
} catch {
|
|
8471
|
+
return root;
|
|
8472
|
+
}
|
|
8473
|
+
}
|
|
8474
|
+
function resolveCcache({ root, layout = defaultAndroidLayout(root), dir = sharedCcache$1(), lookup = lookupCcache, env = process.env, onNote = (line) => console.error(line) }) {
|
|
8475
|
+
const binary = lookup();
|
|
8476
|
+
if (!binary) {
|
|
8477
|
+
onNote(chalk.dim(phaseLine("cache", `ccache off (not installed; ${ccacheInstallCommand()})`)));
|
|
8478
|
+
return null;
|
|
8479
|
+
}
|
|
8480
|
+
const { moduleDir } = layout;
|
|
8481
|
+
const declared = projectCmakeLauncher(readOrNull(join(moduleDir, "build.gradle")) ?? readOrNull(join(moduleDir, "build.gradle.kts")));
|
|
8482
|
+
if (declared) {
|
|
8483
|
+
onNote(chalk.dim(phaseLine("cache", `ccache off (${join(relative(root, moduleDir), "build.gradle")} sets ${declared} itself)`)));
|
|
8484
|
+
return null;
|
|
8485
|
+
}
|
|
8486
|
+
const statsLog = ccacheStatsLog(root);
|
|
8487
|
+
register({
|
|
8488
|
+
dir,
|
|
8489
|
+
registeredBy: root,
|
|
8490
|
+
name: "ccache",
|
|
8491
|
+
prune: "atomic",
|
|
8492
|
+
note: "ccache keeps itself under CCACHE_MAXSIZE, so it is emptied whole or not at all"
|
|
8493
|
+
});
|
|
8494
|
+
onNote(chalk.dim(phaseLine("cache", `ccache on (${dir})`)));
|
|
8495
|
+
return {
|
|
8496
|
+
dir,
|
|
8497
|
+
statsLog,
|
|
8498
|
+
env: ccacheEnvironment({
|
|
8499
|
+
binary,
|
|
8500
|
+
dir,
|
|
8501
|
+
workspaceRoot: canonical(root),
|
|
8502
|
+
statsLog,
|
|
8503
|
+
maxSize: ccacheMaxSize(loadConfig$1(), env)
|
|
8504
|
+
})
|
|
8505
|
+
};
|
|
8506
|
+
}
|
|
9549
8507
|
//#endregion
|
|
9550
|
-
export {
|
|
8508
|
+
export { gradleVersionLines as $, memoryCacheKind as $n, INSTALL_ERROR as $t, diskPressureLevel as A, checkEasAuth as An, ensureRemoteBootOwned as At, includesArchives as B, bundleInvocation as Bn, RELEASE_VERIFY_WAIT_MS as Bt, devServerStopLevel as C, gateMetroOrigin as Cn, describeError as Ct, requestDevServerStop as D, RESOLVE_TIMEOUT_MS as Dn, bundleEntryPoint as Dt, metroLastStop as E, runProcessOperation as En, binOnPath as Et, gcOptionsOf as F, providerFromConfig as Fn, withEasProjectLock as Ft, planCacheEmptying as G, easCliSupport as Gn, unattributedLaunchLines as Gt, includesRecordings as H, remoteCommand as Hn, isBundleProof as Ht, maintenanceItem as I, readProjectConfig as In, LAUNCH_BUNDLING as It, selectsBeyondCaches as J, parseArchiveSelector as Jn, verifyLaunch as Jt, previewScopedEmptying as K, easCliUpgradeRemedy as Kn, unverifiedLaunchLines as Kt, openGcLog as L, resolveEasCliBin as Ln, LAUNCH_FATAL as Lt, levelStillShort as M, isEasAuthFailureText as Mn, remoteAndroidDeps as Mt, lowestFree as N, loadProjectProvider as Nn, remoteIosDeps as Nt, vanishedSupervisorMessage as O, UPLOAD_TIMEOUT_MS as On, endRecordedSession as Ot, protectWindowMs as P, ownerFromConfig as Pn, resolveRemoteContext as Pt, deleteGradleVersions as Q, inspectWatchmanMemory as Qn, DEFAULT_METRO_PORT as Qt, maintenanceLogger as R, resolveRemote as Rn, LAUNCH_UNVERIFIED as Rt, describeMetroLastStop as S, readRemoteSimulatorArch as Sn, deleteEasSessions as St, logVanishedSupervisor as T, processContext as Tn, REMOTE_SESSION_ERROR as Tt, includesWorkspaceOutputs as U, MIN_EAS_CLI_DEVICE_VERSION as Un, readCollectorRecords as Ut, includesParkedDevices as V, remoteCliInvocation as Vn, VERIFY_TIMEOUT_MS as Vt, isWorkspacesScope as W, MIN_EAS_CLI_SIMULATOR_VERSION as Wn, readMetroRecords as Wt, collectGradleVersions as X, WATCHMAN_KIND as Xn, APP_READINESS_TIMEOUT_MS as Xt, trimCaches as Y, GRADLE_DAEMONS_KIND as Yn, verifyReleaseLaunch as Yt, deleteGradleVersion as Z, collectMemoryReport as Zn, ADB_INSTALL_TIMEOUT_MS as Zt, resolveBudget as _, reverseMetroPorts as _n, findStaleDeviceRecords as _t, projectCmakeLauncher as a, devClientUrl as an, scopedMemoryReport as ar, DEVICE_LIST_TIMEOUT_MS$1 as at, stopOwnedMetroForReset as b, readBundleSchemes as bn, withAndroidAvdSizes as bt, budgetGate as c, hasMetroReverse as cn, attributeMachineUsage as cr, collectParkedSims as ct, enforceBudget as d, installIosApp as dn, pruneCache as dr, deleteProjectDevices as dt, IOS_DEV_MENU_OFF_DEFAULTS_PLIST as en, memoryLines as er, gradleVersionsPending as et, inspectBudget as f, iosAppProcess as fn, sizeCaches as fr, describeParkedSims as ft, readVolumeSpaceAsync as g, restartedAppNote as gn, findOrphanedDevices as gt, readVolumeSpace as h, launchIosApp as hn, eraseParkedDevices as ht, ccacheInstallCommand as i, clearOtherUserApps as in, reclaimMemory as ir, collectInventory as it, levelFloors as j, easAuthNote as jn, readInstalledEasCliVersionAsync as jt, withdrawDevServerStopRequest as k, cacheLevel as kn, ensureMetroReachable as kt, budgetLine as l, installAndroidApp as ln, readFootprints as lr, deleteParkedAvds as lt, peekBudget as m, launchAndroidReleaseApp as mn, deviceSweepIsScoped as mt, CCACHE_UNAVAILABLE as n, androidDevClientUrl as nn, memorySweepIsScoped as nr, waitForGradleExit as nt, readCcacheActivity as o, deviceShellArg as on, stopIdleGradleDaemons as or, collectDeviceLeases as ot, machineNumber as p, launchAndroidApp as pn, describeUnverifiableDevices as pt, selectCaches as q, ownedSessionName as qn, verifyAndroidReleaseLaunch as qt, ccacheActivityLine as r, appProcessFromPid as rn, memoryWorkPending as rr, getMachineCacheReport as rt, resolveCcache as s, ensureMetroReverse as sn, phase as sr, collectParkedAvds as st, CCACHE_NOT_RUN as t, androidAppProcess as tn, memoryScope as tr, includesGradleVersions as tt, cacheLabel as u, installConflictKind as un, discoverCaches as ur, deleteParkedSims as ut, trimmableCaches as v, writeDebugHttpHost as vn, findStaleProjectDevices as vt, devServerStopRecord as w, exitAfterFlush as wn, withRemoteSessionGcLocks as wt, describeDevServerStop as x, schemesFromInfoPlist as xn, collectEasSessionSweep as xt, stopOwnedMetro as y, pickDevClientScheme as yn, unverifiedDeviceCommand as yt, emptyCaches as z, uploadRemote as zn, MANIFEST_VERIFY_TIMEOUT_MS as zt };
|