stim 1.17.2 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -1
- package/dist/{activity-IRvJY_ru.mjs → activity-BxnkDZDi.mjs} +4 -4
- package/dist/{agent-device-usage-output-BK41vnzN.mjs → agent-device-usage-output-CZ66YA4T.mjs} +8 -8
- package/dist/android-BKA16DTf.mjs +4 -0
- package/dist/{android-B9yaNKwa.mjs → android-BvwuMUJ9.mjs} +192 -98
- package/dist/{android-DE4v59Mb.mjs → android-CBwCNicO.mjs} +2 -2
- package/dist/{android-B_YNZy61.mjs → android-DC3ZLuw0.mjs} +9 -9
- package/dist/{android-cas-ZFpjJBL_.mjs → android-cas-BBFyr9CA.mjs} +5 -5
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/api-D0VtFhqk.mjs +152 -0
- package/dist/api-run.d.mts +1 -0
- package/dist/api-run.mjs +145 -0
- package/dist/api.d.mts +212 -0
- package/dist/api.mjs +2 -0
- package/dist/{app-install-VPkI5WEg.mjs → app-install-D-PUENug.mjs} +3 -3
- package/dist/{attempt-Bk2ouQVL.mjs → attempt-DW-mQqM7.mjs} +14 -4
- package/dist/{budget-DfcgFdQB.mjs → budget-DIhL2BKx.mjs} +1578 -58
- package/dist/build-facts-DcLv2HSd.d.mts +111 -0
- package/dist/{cache-manifest-DnUHBJaU.mjs → cache-manifest-BI7ozfmH.mjs} +3 -3
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BrcVWQyD.mjs → chrome-DJnmnS5q.mjs} +1 -1
- package/dist/cli-DNJMwADx.mjs +68 -0
- package/dist/cli.mjs +1 -1
- package/dist/{client-SvBdgObD.mjs → client-DzhapoMB.mjs} +139 -32
- package/dist/collector-run.mjs +9 -9
- package/dist/{command-output-CDAIFD-8.mjs → command-output-CBtzyIgF.mjs} +2 -2
- package/dist/{config-D0DbpZtM.mjs → config-CgYMahz7.mjs} +5 -5
- package/dist/{created-devices-CpvzBL25.mjs → created-devices-DKbeWsiK.mjs} +2 -2
- package/dist/{dependency-state-CLcBHH2M.mjs → dependency-state-xKoOypBm.mjs} +2 -2
- package/dist/{detached-entry-CiTEgMR1.mjs → detached-entry-BLfcgc4O.mjs} +1 -1
- package/dist/{dev-client-B-XC4uRH.mjs → dev-client-CLnIH02x.mjs} +2 -2
- package/dist/{device-C8IOoJPv.mjs → device-D7oCHGWi.mjs} +8 -8
- package/dist/{device-capacity-ZC4XSZ4R.mjs → device-capacity-EUOOYr8T.mjs} +13 -13
- package/dist/device-host-worker.mjs +19 -19
- package/dist/{device-ios-C2Um-XUR.mjs → device-ios-6MewKKnc.mjs} +13 -13
- package/dist/{device-lease-DpoS36_u.mjs → device-lease-Co-EwifR.mjs} +9 -9
- package/dist/{device-lease-run-B8YltIH_.mjs → device-lease-run-w1xhCqIW.mjs} +4 -4
- package/dist/{device-pool-3o7s5lo4.mjs → device-pool-F5WvRPtD.mjs} +3 -3
- package/dist/{device-remote-hFSkpfQu.mjs → device-remote-tHbd1fKy.mjs} +15 -15
- package/dist/{doctor-CFv1fCrF.mjs → doctor-B9ckYUoU.mjs} +33 -30
- package/dist/{error-diagnostics-C-NMnhrk.mjs → error-diagnostics-BRXOqDzG.mjs} +11 -11
- package/dist/{exec-CaErVv7t.mjs → exec-DWhCZDGm.mjs} +65 -2
- package/dist/{gc-DEmkg3Xh.mjs → gc-Dh6mXOKC.mjs} +23 -469
- package/dist/{gradle-dJpre3Yn.mjs → gradle-C6GKnunQ.mjs} +6 -6
- package/dist/{guide-status-Du-ZQ3FD.mjs → guide-status-Bhf9SJXc.mjs} +3 -3
- package/dist/{guide-CSmhMTf8.mjs → guide-tm6igAaa.mjs} +290 -53
- package/dist/{hosted-android-E1Heoqnv.mjs → hosted-android-Bv285t_t.mjs} +3 -3
- package/dist/{hosted-client-Bp4knSwu.mjs → hosted-client-C-rMtppF.mjs} +2 -2
- package/dist/{hosted-ios-BnbeYOUD.mjs → hosted-ios-D5mNmtj4.mjs} +1 -1
- package/dist/{hosted-logs-OcgIBvCT.mjs → hosted-logs-DN8Iz4mJ.mjs} +9 -9
- package/dist/{hosted-macos-DcxKjtfH.mjs → hosted-macos-B-wEjlwG.mjs} +5 -5
- package/dist/{hosted-native-1Ebbig4w.mjs → hosted-native-DeeOG8xZ.mjs} +6 -6
- package/dist/{idle-shutdown-IGyNV8Cr.mjs → idle-shutdown-jjtxAn5C.mjs} +7 -8
- package/dist/{ios-DSfnPfse.mjs → ios-B3SbOWdw.mjs} +19 -7
- package/dist/{ios-Cr1h5gnO.mjs → ios-Bvbf0SGY.mjs} +1 -1
- package/dist/{ios-BJ4XUSe1.mjs → ios-CPdkoKaa.mjs} +181 -95
- package/dist/ios-DNpdygiv.mjs +7 -0
- package/dist/{ios-device-Ee7sDXfp.mjs → ios-device-Bn7jWDB1.mjs} +1 -1
- package/dist/{ios-device-pAN4t54-.mjs → ios-device-vOaByMhw.mjs} +3 -3
- package/dist/{ios-state-8L3lgum6.mjs → ios-state-B2pES6Vs.mjs} +1 -1
- package/dist/{launch-verify-lTnWZikR.mjs → launch-verify-hskNcWkZ.mjs} +5 -5
- package/dist/{logs-BAaS7gS2.mjs → logs-1Ylc1Ri6.mjs} +13 -13
- package/dist/macos-Ck7OBMNY.mjs +2 -0
- package/dist/{macos-BIRQS90f.mjs → macos-DF6C7wUU.mjs} +118 -34
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +349 -47
- package/dist/{metro-g8NqiJp-.mjs → metro-Dh8T4Ytd.mjs} +5 -5
- package/dist/{metro-gateway-C-ijGI2F.mjs → metro-gateway-CEUw9RMH.mjs} +4 -4
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-BAHFcJm6.mjs} +16 -2
- package/dist/{named-ports-C8m8EQs2.mjs → named-ports-BFIz1Shz.mjs} +61 -6
- package/dist/{native-run-D1Q56rAD.mjs → native-run-B06FkmZx.mjs} +4 -4
- package/dist/{native-runtime-BEK171xQ.mjs → native-runtime-D_603JiC.mjs} +6 -6
- package/dist/{ndjson-PclOIwVY.mjs → ndjson-LGZAMsqa.mjs} +8 -4
- package/dist/offload-worker.d.mts +3 -17
- package/dist/offload-worker.mjs +10 -11
- package/dist/{ownership-DyRQru0q.mjs → ownership-D6Se7gg_.mjs} +3 -3
- package/dist/{page-QF_Ke10s.mjs → page-Bv9s2KwY.mjs} +1 -1
- package/dist/placement-log-BcPhRwR4.mjs +84 -0
- package/dist/{build-plan-BDsSi09V.mjs → plan-placement-CtxkCO54.mjs} +122 -48
- package/dist/{ports-4nYqxPWC.mjs → ports-BLTtfBq-.mjs} +3 -3
- package/dist/{prebuild-D7RUMkwN.mjs → prebuild-juCyreaR.mjs} +5 -5
- package/dist/preview-D5V07Nrl.mjs +987 -0
- package/dist/{rolldown-runtime-BsOwBuO_.mjs → process-identity-Biv3arCO.mjs} +11 -1
- package/dist/{project-D47Rh0ly.mjs → project-C3ChRLZy.mjs} +4 -68
- package/dist/projects-DD7dBTCj.mjs +92 -0
- package/dist/{pull-request-pxnDCQzn.mjs → pull-request-u4vp7zmK.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/{recordings-BNgsD1Tr.mjs → recordings-BAWltsVt.mjs} +1 -1
- package/dist/{reload-DcRxj3qG.mjs → reload-DvyWzVjJ.mjs} +15 -15
- package/dist/{remote-cache-Ci4DQYYj.mjs → remote-cache-BGg7aGIZ.mjs} +5 -5
- package/dist/{run-CkE9y0nc.mjs → run-vhtDgpHO.mjs} +5 -5
- package/dist/{server-bare-BkrSxSsZ.mjs → server-bare-B9E7S1aR.mjs} +4 -5
- package/dist/server-expo-Db9HBUoa.mjs +2 -0
- package/dist/{server-expo-CHTyXD0G.mjs → server-expo-DoBHhuzK.mjs} +5 -6
- package/dist/{settings-SR9OmW9h.mjs → settings-Byp2AQ_E.mjs} +6 -5
- package/dist/{settings-Cfd-0r2d.mjs → settings-CQyMElEP.mjs} +24 -763
- package/dist/{settings-BBpMcDbD.mjs → settings-Djl-mpjX.mjs} +1 -1
- package/dist/settings.schema.json +126 -3
- package/dist/{simslim-BWNrc3M3.mjs → simslim-EHBQ2R4G.mjs} +7 -7
- package/dist/{slot-launch-DmjBmpQV.mjs → slot-launch-C1nqh4mu.mjs} +6 -6
- package/dist/{spawn-claims-D0XfSe8u.mjs → spawn-claims-Kqiifsk2.mjs} +1 -1
- package/dist/{spawn-entry-jw19m8Nl.mjs → spawn-entry-Dcb7sDUz.mjs} +1 -0
- package/dist/{stage-CzaiwFsI.mjs → stage-g_WqWeaE.mjs} +14 -3
- package/dist/{start-DUz3mYdb.mjs → start-D-IeOyoK.mjs} +19 -19
- package/dist/{start-AlfCPRVU.mjs → start-NTc1Ifqs.mjs} +1 -1
- package/dist/{state-PeQiJuIu.mjs → state-BG-aAk4k.mjs} +4 -4
- package/dist/{state-B4PQFXMW.d.mts → state-lKh8shBp.d.mts} +2 -3
- package/dist/{state-DyaNTgfR.mjs → state-xnqpx3AD.mjs} +2 -2
- package/dist/{stats-Bq4fJOdB.mjs → stats-DY6ekz8F.mjs} +5 -5
- package/dist/{status-DlKvVJBE.mjs → status-BEeL6IKz.mjs} +6 -4
- package/dist/{status-BA2pehwf.mjs → status-DCjZeE-K.mjs} +33 -34
- package/dist/{status-CzS4bPO9.mjs → status-Dcr0Qexd.mjs} +5 -5
- package/dist/{stim-desktop-Cnz8CPnl.mjs → stim-desktop-Behws_fi.mjs} +1 -1
- package/dist/{stim-installations-QMEI32v1.mjs → stim-installations-aR_WsNOA.mjs} +1 -1
- package/dist/{stop-BIiM49EY.mjs → stop-BGhKMOuH.mjs} +5 -5
- package/dist/{stop-DQIasgKp.mjs → stop-BTjs3xbc.mjs} +17 -18
- package/dist/{stop-zF1y04f2.mjs → stop-DIJtD2GL.mjs} +2 -2
- package/dist/supervisor-run.d.mts +24 -22
- package/dist/supervisor-run.mjs +21 -22
- package/dist/{support-CsJNVfOc.mjs → support-BaayeYCf.mjs} +7 -7
- package/dist/{support-WvD__tSV.mjs → support-Bwvbrq5-.mjs} +5 -5
- package/dist/{toolchain-DNyR3NPq.mjs → toolchain-Bnyd_K3A.mjs} +471 -22
- package/dist/{trigger-Bemu8ytw.mjs → trigger-CJMhwXe8.mjs} +5 -5
- package/dist/trigger-DWAq9hkw.mjs +2 -0
- package/dist/{warm-progress-DF4JRvYI.mjs → warm-progress-CjB-MP6H.mjs} +7 -7
- package/dist/web-B6_bFDn7.mjs +2 -0
- package/dist/{web-Dl0KSRHf.mjs → web-DTU0uiWj.mjs} +22 -22
- package/dist/web-run.mjs +10 -10
- package/dist/{workspace-state-DqcCbpE7.mjs → workspace-state-C59dqG-Z.mjs} +3 -3
- package/dist/{ownership-BMLqyBgJ.mjs → workspaces-xXItD8Dj.mjs} +577 -23
- package/dist/{worktree-j3IcFAI5.mjs → worktree-BJfnU6r5.mjs} +1 -1
- package/dist/{worktree-Be_7NLKy.mjs → worktree-BSYlofkq.mjs} +234 -35
- package/dist/worktree-CsKYexJM.mjs +753 -0
- package/package.json +10 -5
- package/dist/build-progress-D0WkjCPd.mjs +0 -1036
- package/dist/build-slots-41v_d2x9.mjs +0 -142
- package/dist/cli-CYXb29oE.mjs +0 -51
- package/dist/deps-iKw0eD4P.mjs +0 -438
- package/dist/errors-B6W7FkxQ.mjs +0 -15
- package/dist/idle-BXG__1BA.mjs +0 -176
- package/dist/in-use-CvGOUn-x.mjs +0 -130
- package/dist/preview-B-g9d7kV.mjs +0 -318
- package/dist/process-identity-BmRm1qV0.mjs +0 -12
- package/dist/server-expo-CeakhI8P.mjs +0 -2
- package/dist/state-BKa8wNN5.mjs +0 -148
- package/dist/stop-cause-rhmGfwvt.mjs +0 -97
- package/dist/trigger-CXts6qt1.mjs +0 -2
- package/dist/watchman-APYjXSQa.mjs +0 -48
- package/dist/workspace-process-lock-2mNzOlaB.mjs +0 -58
- package/dist/workspaces-Bcib97-6.mjs +0 -306
|
@@ -1,25 +1,192 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
1
|
+
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
|
|
4
3
|
import { t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
5
|
-
import { l as phaseLine } from "./command-output-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { t as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { r as
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
4
|
+
import { a as formatElapsed, l as phaseLine } from "./command-output-CBtzyIgF.mjs";
|
|
5
|
+
import { D as withConfigLock$1, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, P as measuredDirectorySize, _ as loadConfig$1, d as getConfigDir, g as isPathPrefix, j as formatBytes, k as acquireAvdClaim, p as getProject, z as deviceSlotPlatforms } from "./config-CgYMahz7.mjs";
|
|
6
|
+
import { y as repoRoot } from "./worktree-CsKYexJM.mjs";
|
|
7
|
+
import { o as pidExists, u as signalProcessTree } from "./metro-Dh8T4Ytd.mjs";
|
|
8
|
+
import { S as workspaceName, g as workspaceAgentDeviceDir, r as readWorkspaceState$1, s as workspaceLastUsed, v as workspaceDir } from "./workspace-state-C59dqG-Z.mjs";
|
|
9
|
+
import { _ as removeSingletonFiles, c as webClaimRoot, f as webProfileDir, g as liveProfileHolder, h as chromeProcessState, i as clearWebRecord, o as readWebRecord, t as CDP_PORT_LABEL, u as webFacts } from "./state-BG-aAk4k.mjs";
|
|
10
|
+
import { t as agentDeviceDaemon, u as readAgentDeviceRecords } from "./activity-BxnkDZDi.mjs";
|
|
11
|
+
import { h as listBuildLocks } from "./device-lease-Co-EwifR.mjs";
|
|
12
|
+
import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-Kqiifsk2.mjs";
|
|
13
|
+
import { n as readCreatedDevices$1, r as recordCreatedDevice, t as forgetCreatedDevice } from "./created-devices-DKbeWsiK.mjs";
|
|
14
|
+
import { B as ownedAvdSystemImage, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, M as listOrphanedAvdDirectories, O as listAdbDevices, X as shutdownAndroidEmulator, Z as sleepSync, _ as avdStorageRoots, dt as parkSim, et as waitForAndroidEmulatorShutdown, f as assertOwnedAvdStopped, h as avdPathExists, it as isStimOwnedAvd, lt as eraseParkedAfter, mt as removeParkedAfter, nt as wipeAvdUserData, pt as readParked, x as deleteAvd } from "./android-DC3ZLuw0.mjs";
|
|
15
|
+
import { D as shutdownIosSim, T as resolveOwnedIosSim, _ as parkedSimName, c as eraseIosSim, o as deleteIosSim, p as listIosDeviceTypes, s as deleteParkedIosSim, v as parseRuntimeVersion, x as renameIosSim } from "./ios-B3SbOWdw.mjs";
|
|
16
|
+
import { J as resolveTailscaleBinary } from "./settings-CQyMElEP.mjs";
|
|
17
|
+
import { a as withWorkspaceProcessLock, o as workspaceProcessLockError, r as releaseBrowserPort, s as workspaceProcessLockPath } from "./named-ports-BFIz1Shz.mjs";
|
|
18
|
+
import { i as macosRuntimeClaim } from "./state-xnqpx3AD.mjs";
|
|
19
|
+
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync } from "node:fs";
|
|
18
20
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
21
|
+
import { basename as basename$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
|
|
22
|
+
import { buildSlotsDir, hostedNativeRecords, isJsonObject, macosAppState, parseHostedNativePlacement, readJsonFile, readMacosRecord, tryAcquireBuildSlotClaim, unreadableHostedNative } from "@stim-cli/core/state";
|
|
19
23
|
import { homedir } from "node:os";
|
|
24
|
+
import chalk from "chalk";
|
|
20
25
|
import { isDeepStrictEqual } from "node:util";
|
|
26
|
+
import { existsSync as existsSync$1, lstatSync as lstatSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
|
|
27
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
21
28
|
import { resolve4 } from "node:dns/promises";
|
|
22
29
|
import { request } from "node:https";
|
|
30
|
+
//#region src/commands/gc/paths.ts
|
|
31
|
+
function canonicalPath(p) {
|
|
32
|
+
try {
|
|
33
|
+
return realpathSync$1(p);
|
|
34
|
+
} catch {
|
|
35
|
+
return resolve$1(p);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/commands/gc/results.ts
|
|
40
|
+
const results = [];
|
|
41
|
+
function recordGcResult(kind, status, label, { id = null, bytes = null, detail = null } = {}) {
|
|
42
|
+
results.push({
|
|
43
|
+
kind,
|
|
44
|
+
status,
|
|
45
|
+
label,
|
|
46
|
+
id,
|
|
47
|
+
bytes,
|
|
48
|
+
detail
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function takeGcResults() {
|
|
52
|
+
return results.splice(0);
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/engine/build-slots.ts
|
|
56
|
+
const SLOT_PREFIX = "slot-";
|
|
57
|
+
const SLOT_POLL_MS = 1e3;
|
|
58
|
+
const SLOT_PROGRESS_MS = 3e4;
|
|
59
|
+
const SLOT_CEILING_MS = 54e5;
|
|
60
|
+
function sleepAsync$1(ms) {
|
|
61
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
62
|
+
}
|
|
63
|
+
function toRecord(holder) {
|
|
64
|
+
const details = holder.details;
|
|
65
|
+
return {
|
|
66
|
+
pid: holder.owner.pid,
|
|
67
|
+
index: typeof details.index === "number" ? details.index : null,
|
|
68
|
+
projectRoot: typeof details.projectRoot === "string" ? details.projectRoot : null,
|
|
69
|
+
startedAt: holder.startedAt || null,
|
|
70
|
+
logFile: typeof details.logFile === "string" ? details.logFile : null
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function tryAcquireBuildSlot({ max, root = null, logFile = null }) {
|
|
74
|
+
if (!max || max <= 0) return {
|
|
75
|
+
acquired: true,
|
|
76
|
+
unlimited: true
|
|
77
|
+
};
|
|
78
|
+
const got = tryAcquireBuildSlotClaim({
|
|
79
|
+
max,
|
|
80
|
+
details: {
|
|
81
|
+
projectRoot: root,
|
|
82
|
+
logFile
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
if (!got) return null;
|
|
86
|
+
declareSpawnsOn(got.claim);
|
|
87
|
+
return {
|
|
88
|
+
acquired: true,
|
|
89
|
+
path: got.path,
|
|
90
|
+
index: got.index,
|
|
91
|
+
slot: {
|
|
92
|
+
pid: got.claim.owner.pid,
|
|
93
|
+
index: got.index,
|
|
94
|
+
projectRoot: root,
|
|
95
|
+
startedAt: got.claim.startedAt,
|
|
96
|
+
logFile
|
|
97
|
+
},
|
|
98
|
+
claim: got.claim
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function slotWaitingLine({ max, elapsedMs }) {
|
|
102
|
+
return `${"build".padEnd(11)} waiting for a build slot (all ${max} in use, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle concurrency`;
|
|
103
|
+
}
|
|
104
|
+
async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, waitingFor = () => {}, sleep = sleepAsync$1, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS }) {
|
|
105
|
+
if (!max || max <= 0) return {
|
|
106
|
+
acquired: true,
|
|
107
|
+
unlimited: true
|
|
108
|
+
};
|
|
109
|
+
const started = now();
|
|
110
|
+
let lastProgress = started;
|
|
111
|
+
let waited = false;
|
|
112
|
+
try {
|
|
113
|
+
for (;;) {
|
|
114
|
+
const got = tryAcquireBuildSlot({
|
|
115
|
+
max,
|
|
116
|
+
root,
|
|
117
|
+
logFile
|
|
118
|
+
});
|
|
119
|
+
if (got) return {
|
|
120
|
+
...got,
|
|
121
|
+
slotWaitMs: waited ? Math.max(0, Math.round(now() - started)) : 0
|
|
122
|
+
};
|
|
123
|
+
waited = true;
|
|
124
|
+
waitingFor({
|
|
125
|
+
kind: "build-slot",
|
|
126
|
+
inUse: max,
|
|
127
|
+
max,
|
|
128
|
+
since: new Date(started).toISOString()
|
|
129
|
+
});
|
|
130
|
+
const elapsed = now() - started;
|
|
131
|
+
if (elapsed >= ceilingMs) {
|
|
132
|
+
const err = /* @__PURE__ */ new Error(`Waited ${formatElapsed(elapsed)} for one of ${max} build slots, and every slot is held by a process that is still running, or by a holder Stim cannot identify. Slots live under ` + buildSlotsDir() + "; remove a slot directory whose builder is not really building, or raise concurrency.maxBuilds.");
|
|
133
|
+
err.code = "STIM_BUILD_SLOT_TIMEOUT";
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
if (now() - lastProgress >= progressMs) {
|
|
137
|
+
lastProgress = now();
|
|
138
|
+
out(slotWaitingLine({
|
|
139
|
+
max,
|
|
140
|
+
elapsedMs: elapsed
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
await sleep(intervalMs);
|
|
144
|
+
}
|
|
145
|
+
} finally {
|
|
146
|
+
waitingFor(null);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function releaseBuildSlot(handle) {
|
|
150
|
+
if (!handle || handle.unlimited) return false;
|
|
151
|
+
stopDeclaringSpawnsOn(handle.claim);
|
|
152
|
+
return (0, ownership_claim_exports.releaseClaim)(handle.claim);
|
|
153
|
+
}
|
|
154
|
+
function listBuildSlots() {
|
|
155
|
+
const dir = buildSlotsDir();
|
|
156
|
+
let names;
|
|
157
|
+
try {
|
|
158
|
+
names = readdirSync(dir);
|
|
159
|
+
} catch {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
const slots = [];
|
|
163
|
+
for (const name of names) {
|
|
164
|
+
if (!name.startsWith(SLOT_PREFIX)) continue;
|
|
165
|
+
const path = join(dir, name);
|
|
166
|
+
try {
|
|
167
|
+
if (!statSync(path).isDirectory()) continue;
|
|
168
|
+
} catch {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const survey = (0, ownership_claim_exports.readClaimSet)(path);
|
|
172
|
+
const holder = survey.live[0] ?? survey.dead[0];
|
|
173
|
+
const info = holder ? toRecord(holder) : null;
|
|
174
|
+
const index = Number(name.slice(5));
|
|
175
|
+
slots.push({
|
|
176
|
+
path,
|
|
177
|
+
name,
|
|
178
|
+
index: Number.isFinite(index) ? index : null,
|
|
179
|
+
pid: info?.pid ?? null,
|
|
180
|
+
projectRoot: info?.projectRoot ?? null,
|
|
181
|
+
startedAt: info?.startedAt ?? null,
|
|
182
|
+
logFile: info?.logFile ?? null,
|
|
183
|
+
alive: survey.live.length > 0,
|
|
184
|
+
unresolved: survey.unresolved.length > 0
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return slots;
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
23
190
|
//#region src/devices/agent-device-cleanup.ts
|
|
24
191
|
function parseAgentDeviceSessions(output) {
|
|
25
192
|
const result = JSON.parse(output);
|
|
@@ -392,7 +559,7 @@ function teardownOwnedIosSim(udid, { del = false, label, park, workspace, shutdo
|
|
|
392
559
|
}
|
|
393
560
|
}
|
|
394
561
|
function assertAvdReferences(avdName, owner) {
|
|
395
|
-
const config = loadConfig();
|
|
562
|
+
const config = loadConfig$1();
|
|
396
563
|
if (!config) throw new Error("Cannot verify AVD references without a Stim config; the data was kept.");
|
|
397
564
|
if (owner && "projectPath" in owner && owner.expectedRecord && !isDeepStrictEqual(deviceSlotPlatforms(config.projects[owner.projectPath], owner.slot)?.android, owner.expectedRecord)) throw new Error(`AVD ${avdName} has a changed workspace record; its data was kept.`);
|
|
398
565
|
for (const [projectPath, project] of Object.entries(config.projects)) for (const { slot, platforms } of projectDeviceSlots(project)) {
|
|
@@ -405,7 +572,7 @@ function removeOrphanedAvdDirectory(candidate, owner) {
|
|
|
405
572
|
const surveyed = listOrphanedAvdDirectories(candidate.name).find((entry) => entry.directory === candidate.directory);
|
|
406
573
|
if (!surveyed || surveyed.name !== candidate.name || surveyed.dev !== candidate.dev || surveyed.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
407
574
|
assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
|
|
408
|
-
const detached = withConfigLock(() => {
|
|
575
|
+
const detached = withConfigLock$1(() => {
|
|
409
576
|
const current = lstatSync(candidate.directory);
|
|
410
577
|
if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
411
578
|
assertAvdReferences(candidate.name, owner);
|
|
@@ -481,7 +648,7 @@ function serialFree(serial) {
|
|
|
481
648
|
function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, owner, workspace, orphanedDirectory, onlyIfMissing = false, onWipeStart, waitForShutdown = waitForAndroidEmulatorShutdown, assertStopped = assertOwnedAvdStopped, resolveAvd = resolveOwnedAvdSerial }) {
|
|
482
649
|
let parkFallback;
|
|
483
650
|
try {
|
|
484
|
-
if (del || wipe) withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
651
|
+
if (del || wipe) withConfigLock$1(() => assertAvdReferences(avdName, owner));
|
|
485
652
|
const resolved = resolveAvd(avdName);
|
|
486
653
|
if (resolved.notOwned) return {
|
|
487
654
|
status: "skipped",
|
|
@@ -547,7 +714,7 @@ function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, o
|
|
|
547
714
|
if (current.notOwned || current.missing) throw new Error(`AVD ${avdName} changed before its data was wiped.`);
|
|
548
715
|
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before its data was wiped.`);
|
|
549
716
|
assertStopped(avdName);
|
|
550
|
-
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
717
|
+
withConfigLock$1(() => assertAvdReferences(avdName, owner));
|
|
551
718
|
const directory = ownedAvdDirectory(avdName);
|
|
552
719
|
if (!directory) throw new Error(`The data directory of AVD ${avdName} could not be resolved.`);
|
|
553
720
|
onWipeStart?.();
|
|
@@ -563,7 +730,7 @@ function teardownClaimedAvd(avdName, claim, { del = false, wipe = false, park, o
|
|
|
563
730
|
if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
|
|
564
731
|
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
|
|
565
732
|
assertStopped(avdName);
|
|
566
|
-
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
733
|
+
withConfigLock$1(() => assertAvdReferences(avdName, owner));
|
|
567
734
|
if (park && park.max > 0) try {
|
|
568
735
|
const systemImage = ownedAvdSystemImage(avdName);
|
|
569
736
|
if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
|
|
@@ -720,7 +887,7 @@ async function teardownBrowserHeld(root, { deleteProfile = false } = {}) {
|
|
|
720
887
|
}
|
|
721
888
|
if (existsSync(profile)) removeSingletonFiles(profile);
|
|
722
889
|
if (deleteProfile && existsSync(profile)) {
|
|
723
|
-
if (!readCreatedDevices().web.has(profile)) return {
|
|
890
|
+
if (!readCreatedDevices$1().web.has(profile)) return {
|
|
724
891
|
status: "skipped",
|
|
725
892
|
kind: "not-owned",
|
|
726
893
|
reason: `${profile} is not in Stim's ledger; it was kept`
|
|
@@ -1301,4 +1468,391 @@ function numberOrNull(v) {
|
|
|
1301
1468
|
return typeof v === "number" && Number.isSafeInteger(v) && v > 0 ? v : null;
|
|
1302
1469
|
}
|
|
1303
1470
|
//#endregion
|
|
1304
|
-
|
|
1471
|
+
//#region src/workspace/in-use.ts
|
|
1472
|
+
const NATIVE_RUN = "native-run";
|
|
1473
|
+
const NATIVE_RUN_HELD = "a stim ios, android or stop run holds its native-run.lock";
|
|
1474
|
+
function workspaceInUse(root, { supervisor = true, managedLocks = true, hosted = true, nativeRun = true } = {}) {
|
|
1475
|
+
const reasons = [];
|
|
1476
|
+
if (supervisor) {
|
|
1477
|
+
const project = getProject(root);
|
|
1478
|
+
const target = resolveSupervisorTarget({
|
|
1479
|
+
state: readWorkspaceState$1(root)?.supervisor,
|
|
1480
|
+
record: project?.supervisor,
|
|
1481
|
+
reservedPort: project?.metroPort
|
|
1482
|
+
});
|
|
1483
|
+
if (target.status === "ours") reasons.push(`its dev server supervisor (pid ${target.pid}) is running`);
|
|
1484
|
+
else if (target.status === "unverified") reasons.push(`its dev server supervisor cannot be verified: ${target.reason ?? "unknown identity"}`);
|
|
1485
|
+
const macos = macosAppState(readMacosRecord(root));
|
|
1486
|
+
if (macos?.host) reasons.push(`its macOS app runs on ${macos.host.machine}`);
|
|
1487
|
+
else if (macos?.state === "running" || macos?.state === "orphaned" || macos?.build.state === "running") reasons.push("its macOS app or build is running");
|
|
1488
|
+
else if (macos?.state === "unverified" || !macos && readWorkspaceState$1(root)?.macos !== void 0) reasons.push("its macOS process owner cannot be verified");
|
|
1489
|
+
const runtime = (0, ownership_claim_exports.readClaimSet)(macosRuntimeClaim(root));
|
|
1490
|
+
if (runtime.live.length) reasons.push("its macOS runtime claim is held");
|
|
1491
|
+
else if (runtime.unresolved[0]) reasons.push(`its macOS runtime cannot be verified: ${runtime.unresolved[0].reason}`);
|
|
1492
|
+
const browser = webFacts(readWebRecord(root));
|
|
1493
|
+
if (browser?.status === "running" || browser?.status === "orphaned") reasons.push(`its owned Chrome (pid ${browser.record.chromeProcess?.pid}) is running`);
|
|
1494
|
+
else if (browser?.status === "unverified") reasons.push("its owned Chrome cannot be verified");
|
|
1495
|
+
}
|
|
1496
|
+
if (nativeRun) {
|
|
1497
|
+
const claims = (0, ownership_claim_exports.readClaimSet)(workspaceProcessLockPath(workspaceDir(root), NATIVE_RUN, true));
|
|
1498
|
+
if (claims.live.length) reasons.push(NATIVE_RUN_HELD);
|
|
1499
|
+
else if (claims.unresolved[0]) reasons.push(`its native-run.lock cannot be resolved: ${claims.unresolved[0].reason}`);
|
|
1500
|
+
}
|
|
1501
|
+
for (const platform of ["ios", "android"]) for (const [slot, record] of Object.entries(hosted ? hostedNativeRecords(readWorkspaceState$1(root), platform) : {})) {
|
|
1502
|
+
const placement = parseHostedNativePlacement(record, platform);
|
|
1503
|
+
reasons.push(placement ? `its ${platform === "ios" ? "iOS simulator" : "Android emulator"} runs on ${placement.machine}` : unreadableHostedNative(slot, platform));
|
|
1504
|
+
}
|
|
1505
|
+
const self = canonicalPath(root);
|
|
1506
|
+
for (const [kind, entries] of [["build lock", listBuildLocks()], ["build slot", listBuildSlots()]]) for (const entry of entries) {
|
|
1507
|
+
if (!entry.alive && !entry.unresolved) continue;
|
|
1508
|
+
if (entry.projectRoot !== null && canonicalPath(entry.projectRoot) === self) reasons.push(`a ${entry.alive ? "live" : "unresolvable"} ${kind} at ${entry.path} names it`);
|
|
1509
|
+
}
|
|
1510
|
+
if (managedLocks) reasons.push(...managedLockHolders(root));
|
|
1511
|
+
return reasons;
|
|
1512
|
+
}
|
|
1513
|
+
function emptyWorkspaceDir(dir) {
|
|
1514
|
+
if (lstatSync(dir).isSymbolicLink()) {
|
|
1515
|
+
unlinkSync(dir);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
for (const name of readdirSync(dir)) if (name !== `${NATIVE_RUN}.lock`) rmSync(join(dir, name), {
|
|
1519
|
+
recursive: true,
|
|
1520
|
+
force: true
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
async function withIdleWorkspace(root, fn, { purpose, ...checks }) {
|
|
1524
|
+
try {
|
|
1525
|
+
return await withWorkspaceProcessLock(workspaceDir(root), NATIVE_RUN, async () => {
|
|
1526
|
+
const reasons = workspaceInUse(root, {
|
|
1527
|
+
...checks,
|
|
1528
|
+
nativeRun: false
|
|
1529
|
+
});
|
|
1530
|
+
if (reasons.length) return {
|
|
1531
|
+
ran: false,
|
|
1532
|
+
reasons
|
|
1533
|
+
};
|
|
1534
|
+
return {
|
|
1535
|
+
ran: true,
|
|
1536
|
+
value: await fn()
|
|
1537
|
+
};
|
|
1538
|
+
}, {
|
|
1539
|
+
external: true,
|
|
1540
|
+
waitMs: 0,
|
|
1541
|
+
ownerPurpose: purpose
|
|
1542
|
+
});
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
if (workspaceProcessLockError(error)) return {
|
|
1545
|
+
ran: false,
|
|
1546
|
+
reasons: [NATIVE_RUN_HELD]
|
|
1547
|
+
};
|
|
1548
|
+
if ((0, ownership_claim_exports.isClaimRefusal)(error) || (0, ownership_claim_exports.isClaimUnavailable)(error)) return {
|
|
1549
|
+
ran: false,
|
|
1550
|
+
reasons: [`its native-run.lock cannot be taken: ${error.reason}`]
|
|
1551
|
+
};
|
|
1552
|
+
throw error;
|
|
1553
|
+
} finally {
|
|
1554
|
+
try {
|
|
1555
|
+
const dir = workspaceDir(root);
|
|
1556
|
+
if (!lstatSync(dir).isSymbolicLink()) rmdirSync(dir);
|
|
1557
|
+
} catch {}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
//#endregion
|
|
1561
|
+
//#region src/commands/gc/workspaces.ts
|
|
1562
|
+
function workspacesRoot() {
|
|
1563
|
+
return join$1(getConfigDir(), "workspaces");
|
|
1564
|
+
}
|
|
1565
|
+
function isInsideWorkspaces(dir) {
|
|
1566
|
+
const rel = relative$1(canonicalPath(workspacesRoot()), canonicalPath(dir));
|
|
1567
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute$1(rel);
|
|
1568
|
+
}
|
|
1569
|
+
function readRecordedRoot(dir, name) {
|
|
1570
|
+
let parsed;
|
|
1571
|
+
try {
|
|
1572
|
+
parsed = readJsonFile(join$1(dir, "workspace.json"));
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
return {
|
|
1575
|
+
projectRoot: null,
|
|
1576
|
+
problem: error?.code === "ENOENT" ? "it has no workspace.json" : "its workspace.json does not parse"
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
const projectRoot = isJsonObject(parsed) ? parsed.projectRoot : void 0;
|
|
1580
|
+
if (typeof projectRoot !== "string" || !isAbsolute$1(projectRoot)) return {
|
|
1581
|
+
projectRoot: null,
|
|
1582
|
+
problem: "its workspace.json records no absolute project root"
|
|
1583
|
+
};
|
|
1584
|
+
if (workspaceName(projectRoot) !== name) return {
|
|
1585
|
+
projectRoot: null,
|
|
1586
|
+
problem: `its workspace.json records ${projectRoot}, whose workspace directory has another name`
|
|
1587
|
+
};
|
|
1588
|
+
return {
|
|
1589
|
+
projectRoot,
|
|
1590
|
+
problem: null
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
function listWorkspaceDirs() {
|
|
1594
|
+
const root = workspacesRoot();
|
|
1595
|
+
let names;
|
|
1596
|
+
try {
|
|
1597
|
+
names = readdirSync$1(root).toSorted();
|
|
1598
|
+
} catch {
|
|
1599
|
+
return [];
|
|
1600
|
+
}
|
|
1601
|
+
const entries = [];
|
|
1602
|
+
for (const name of names) {
|
|
1603
|
+
const dir = join$1(root, name);
|
|
1604
|
+
try {
|
|
1605
|
+
if (!statSync$1(dir).isDirectory()) continue;
|
|
1606
|
+
} catch {
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
entries.push({
|
|
1610
|
+
dir,
|
|
1611
|
+
...readRecordedRoot(dir, name)
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
return entries;
|
|
1615
|
+
}
|
|
1616
|
+
function classifyWorkspaceDirs(entries, { registryKeys, exists, isMounted, inUse }) {
|
|
1617
|
+
const orphaned = [];
|
|
1618
|
+
const skipped = [];
|
|
1619
|
+
for (const { dir, projectRoot, problem } of entries) {
|
|
1620
|
+
if (projectRoot === null) {
|
|
1621
|
+
skipped.push({
|
|
1622
|
+
dir,
|
|
1623
|
+
reason: `workspace directory not resolved: ${problem ?? "unknown project root"}`
|
|
1624
|
+
});
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
const present = exists(projectRoot);
|
|
1628
|
+
if (present === null) {
|
|
1629
|
+
skipped.push({
|
|
1630
|
+
dir,
|
|
1631
|
+
reason: `cannot tell whether its project root ${projectRoot} still exists`
|
|
1632
|
+
});
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
if (present) continue;
|
|
1636
|
+
if (registryKeys.some((key) => isPathPrefix(projectRoot, key))) continue;
|
|
1637
|
+
if (!isMounted(projectRoot)) {
|
|
1638
|
+
skipped.push({
|
|
1639
|
+
dir,
|
|
1640
|
+
reason: `the volume of its project root ${projectRoot} is not mounted`
|
|
1641
|
+
});
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
const reasons = inUse(projectRoot);
|
|
1645
|
+
if (reasons.length) {
|
|
1646
|
+
skipped.push({
|
|
1647
|
+
dir,
|
|
1648
|
+
reason: `its project root ${projectRoot} is gone, but ${reasons.join("; ")}`
|
|
1649
|
+
});
|
|
1650
|
+
continue;
|
|
1651
|
+
}
|
|
1652
|
+
orphaned.push({
|
|
1653
|
+
dir,
|
|
1654
|
+
projectRoot
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
return {
|
|
1658
|
+
orphaned,
|
|
1659
|
+
skipped
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
function rootPresence(path) {
|
|
1663
|
+
try {
|
|
1664
|
+
lstatSync$1(path);
|
|
1665
|
+
return true;
|
|
1666
|
+
} catch (error) {
|
|
1667
|
+
const code = error?.code;
|
|
1668
|
+
return code === "ENOENT" || code === "ENOTDIR" ? false : null;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function collectOrphanedWorkspaces(registryKeys, mountedVolumes, { measure = true } = {}) {
|
|
1672
|
+
const classified = classifyWorkspaceDirs(listWorkspaceDirs(), {
|
|
1673
|
+
registryKeys,
|
|
1674
|
+
exists: rootPresence,
|
|
1675
|
+
isMounted: (path) => isOnMountedVolume(path, mountedVolumes),
|
|
1676
|
+
inUse: (root) => workspaceInUse(root)
|
|
1677
|
+
});
|
|
1678
|
+
return {
|
|
1679
|
+
orphaned: measure ? classified.orphaned.map((entry) => Object.assign({}, entry, { bytes: sizeOf(entry.dir) })) : classified.orphaned,
|
|
1680
|
+
skipped: classified.skipped
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
const REBUILD_COST = "The next build of an unchanged app installs from the shared build cache; after a native change the compilation cache speeds the rebuild, but on React Native 0.86 Swift does not use it (explicit modules are off), so that build recompiles Swift. The next stim macos in a cleared workspace is a full Swift build.";
|
|
1684
|
+
const WORKSPACE_OUTPUT_DIRS = [
|
|
1685
|
+
"derived-data",
|
|
1686
|
+
"gradle-build",
|
|
1687
|
+
"android-cas",
|
|
1688
|
+
"cache-provider"
|
|
1689
|
+
];
|
|
1690
|
+
const DAY_MS = 864e5;
|
|
1691
|
+
function planWorkspaceOutputs(entries, { olderThan, now }) {
|
|
1692
|
+
return entries.map(({ dir, projectRoot, problem, bytes, lastUsed, inUse }) => {
|
|
1693
|
+
const idleDays = Number.isFinite(lastUsed) ? Math.max(0, Math.floor((now - lastUsed) / DAY_MS)) : null;
|
|
1694
|
+
const [keptCode, keptReason] = projectRoot === null ? ["unresolved", `workspace directory not resolved: ${problem ?? "unknown project root"}`] : inUse.length ? ["in-use", `in use: ${inUse.join("; ")}`] : olderThan === null ? [null, null] : idleDays === null ? ["last-use-unknown", "its last use is unknown"] : idleDays < olderThan ? ["recently-used", `used ${idleDays}d ago, within --older-than ${olderThan}`] : [null, null];
|
|
1695
|
+
return {
|
|
1696
|
+
dir,
|
|
1697
|
+
projectRoot,
|
|
1698
|
+
bytes,
|
|
1699
|
+
idleDays,
|
|
1700
|
+
willClear: keptCode === null,
|
|
1701
|
+
keptCode,
|
|
1702
|
+
keptReason
|
|
1703
|
+
};
|
|
1704
|
+
});
|
|
1705
|
+
}
|
|
1706
|
+
const SIZE_TIMEOUT_MS = 6e4;
|
|
1707
|
+
function sizeOf(dir, timeoutMs = SIZE_TIMEOUT_MS) {
|
|
1708
|
+
return measuredDirectorySize(dir, { timeoutMs });
|
|
1709
|
+
}
|
|
1710
|
+
function outputPaths(dir) {
|
|
1711
|
+
const paths = WORKSPACE_OUTPUT_DIRS.map((name) => join$1(dir, name)).filter((path) => existsSync$1(path));
|
|
1712
|
+
const macos = join$1(dir, "macos");
|
|
1713
|
+
try {
|
|
1714
|
+
if (!lstatSync$1(macos).isDirectory()) return paths;
|
|
1715
|
+
for (const entry of readdirSync$1(macos, { withFileTypes: true })) if (entry.name === "build" || entry.name.endsWith(".app") || entry.name.startsWith("staging-") && entry.isDirectory()) paths.push(join$1(macos, entry.name));
|
|
1716
|
+
} catch {}
|
|
1717
|
+
return paths;
|
|
1718
|
+
}
|
|
1719
|
+
function outputBytes(paths, timeoutMs) {
|
|
1720
|
+
let total = 0;
|
|
1721
|
+
for (const path of paths) {
|
|
1722
|
+
const size = sizeOf(path, timeoutMs);
|
|
1723
|
+
if (size === null) return null;
|
|
1724
|
+
total += size;
|
|
1725
|
+
}
|
|
1726
|
+
return total;
|
|
1727
|
+
}
|
|
1728
|
+
function collectWorkspaceOutputs({ olderThan, now, exclude = [], measure = true, sizeTimeoutMs = SIZE_TIMEOUT_MS }) {
|
|
1729
|
+
const mountedVolumes = listMountedVolumes();
|
|
1730
|
+
const entries = listWorkspaceDirs().filter((entry) => !exclude.includes(entry.dir)).filter((entry) => entry.projectRoot === null || isOnMountedVolume(entry.projectRoot, mountedVolumes)).map((entry) => Object.assign({}, entry, { paths: outputPaths(entry.dir) })).filter((entry) => entry.paths.length > 0).map(({ paths, ...entry }) => Object.assign({}, entry, { bytes: measure ? outputBytes(paths, sizeTimeoutMs) : null })).map((entry) => Object.assign({}, entry, {
|
|
1731
|
+
lastUsed: entry.projectRoot === null ? NaN : workspaceLastUsed(entry.projectRoot),
|
|
1732
|
+
inUse: entry.projectRoot === null ? [] : workspaceInUse(entry.projectRoot)
|
|
1733
|
+
}));
|
|
1734
|
+
return {
|
|
1735
|
+
root: workspacesRoot(),
|
|
1736
|
+
workspaces: planWorkspaceOutputs(entries, {
|
|
1737
|
+
olderThan,
|
|
1738
|
+
now
|
|
1739
|
+
})
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
async function clearWorkspaceOutputs(report, { olderThan, now = Date.now() }) {
|
|
1743
|
+
let failures = 0;
|
|
1744
|
+
let cleared = 0;
|
|
1745
|
+
const clearedRoots = [];
|
|
1746
|
+
for (const entry of report.workspaces) {
|
|
1747
|
+
const root = entry.projectRoot;
|
|
1748
|
+
if (!entry.willClear || root === null) {
|
|
1749
|
+
if (entry.keptReason) {
|
|
1750
|
+
console.log(chalk.dim(`Kept the build outputs of ${root ?? entry.dir}: ${entry.keptReason}`));
|
|
1751
|
+
recordGcResult("workspaceOutputs", "kept", root ?? entry.dir, {
|
|
1752
|
+
bytes: entry.bytes,
|
|
1753
|
+
detail: entry.keptReason
|
|
1754
|
+
});
|
|
1755
|
+
}
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
let run;
|
|
1759
|
+
try {
|
|
1760
|
+
run = await withIdleWorkspace(root, () => {
|
|
1761
|
+
const [again] = planWorkspaceOutputs([{
|
|
1762
|
+
...entry,
|
|
1763
|
+
problem: null,
|
|
1764
|
+
lastUsed: workspaceLastUsed(root),
|
|
1765
|
+
inUse: []
|
|
1766
|
+
}], {
|
|
1767
|
+
olderThan,
|
|
1768
|
+
now
|
|
1769
|
+
});
|
|
1770
|
+
if (again?.keptReason) return again.keptReason;
|
|
1771
|
+
for (const path of outputPaths(entry.dir)) rmSync$1(path, {
|
|
1772
|
+
recursive: true,
|
|
1773
|
+
force: true
|
|
1774
|
+
});
|
|
1775
|
+
return null;
|
|
1776
|
+
}, { purpose: "gc" });
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
failures++;
|
|
1779
|
+
console.log(chalk.red(`Could not clear the build outputs of ${root}: ${error?.message || String(error)}`));
|
|
1780
|
+
recordGcResult("workspaceOutputs", "failed", root, {
|
|
1781
|
+
bytes: entry.bytes,
|
|
1782
|
+
detail: error?.message || String(error)
|
|
1783
|
+
});
|
|
1784
|
+
continue;
|
|
1785
|
+
}
|
|
1786
|
+
const kept = run.ran ? run.value : `in use: ${run.reasons.join("; ")}`;
|
|
1787
|
+
if (kept) {
|
|
1788
|
+
console.log(chalk.yellow(`Kept the build outputs of ${root}: ${kept}`));
|
|
1789
|
+
recordGcResult("workspaceOutputs", "kept", root, {
|
|
1790
|
+
bytes: entry.bytes,
|
|
1791
|
+
detail: kept
|
|
1792
|
+
});
|
|
1793
|
+
continue;
|
|
1794
|
+
}
|
|
1795
|
+
cleared += entry.bytes ?? 0;
|
|
1796
|
+
clearedRoots.push(root);
|
|
1797
|
+
console.log(chalk.green(`Cleared the build outputs of ${root} (${sizeText(entry.bytes)})`));
|
|
1798
|
+
recordGcResult("workspaceOutputs", "done", root, { bytes: entry.bytes });
|
|
1799
|
+
}
|
|
1800
|
+
if (cleared) console.log(chalk.dim(`Cleared ${formatBytes(cleared)} of workspace build outputs. ${REBUILD_COST}`));
|
|
1801
|
+
return {
|
|
1802
|
+
failures,
|
|
1803
|
+
cleared: clearedRoots
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
function stillOrphaned({ dir, projectRoot }) {
|
|
1807
|
+
if (readRecordedRoot(dir, basename$1(dir)).projectRoot !== projectRoot || rootPresence(projectRoot) !== false || !isOnMountedVolume(projectRoot)) return false;
|
|
1808
|
+
return !Object.keys(loadConfig$1()?.projects ?? {}).some((key) => isPathPrefix(projectRoot, key));
|
|
1809
|
+
}
|
|
1810
|
+
async function deleteOrphanedWorkspaces(orphaned) {
|
|
1811
|
+
let failures = 0;
|
|
1812
|
+
for (const entry of orphaned) {
|
|
1813
|
+
if (!existsSync$1(entry.dir)) continue;
|
|
1814
|
+
let run;
|
|
1815
|
+
try {
|
|
1816
|
+
run = await withIdleWorkspace(entry.projectRoot, async () => {
|
|
1817
|
+
if (!stillOrphaned(entry)) return false;
|
|
1818
|
+
const browser = await teardownOwnedBrowser(entry.projectRoot, { deleteProfile: true });
|
|
1819
|
+
if (browser.status === "failed" || browser.status === "skipped") throw new Error(`its owned Chrome profile was kept: ${browser.reason}`);
|
|
1820
|
+
emptyWorkspaceDir(entry.dir);
|
|
1821
|
+
return true;
|
|
1822
|
+
}, { purpose: "gc" });
|
|
1823
|
+
} catch (error) {
|
|
1824
|
+
failures++;
|
|
1825
|
+
console.log(chalk.red(`Could not remove ${entry.dir}: ${error?.message || error}`));
|
|
1826
|
+
recordGcResult("workspaceDirectory", "failed", entry.dir, {
|
|
1827
|
+
bytes: entry.bytes ?? null,
|
|
1828
|
+
detail: error?.message || String(error)
|
|
1829
|
+
});
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
if (!run.ran) {
|
|
1833
|
+
console.log(chalk.yellow(`Kept ${entry.dir}: ${run.reasons.join("; ")}`));
|
|
1834
|
+
recordGcResult("workspaceDirectory", "kept", entry.dir, {
|
|
1835
|
+
bytes: entry.bytes ?? null,
|
|
1836
|
+
detail: run.reasons.join("; ")
|
|
1837
|
+
});
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
if (!run.value) {
|
|
1841
|
+
console.log(chalk.yellow(`Kept ${entry.dir}: it can no longer be confirmed orphaned.`));
|
|
1842
|
+
recordGcResult("workspaceDirectory", "kept", entry.dir, {
|
|
1843
|
+
bytes: entry.bytes ?? null,
|
|
1844
|
+
detail: "it can no longer be confirmed orphaned"
|
|
1845
|
+
});
|
|
1846
|
+
continue;
|
|
1847
|
+
}
|
|
1848
|
+
const size = entry.bytes === void 0 ? "" : ` (${sizeText(entry.bytes)})`;
|
|
1849
|
+
console.log(chalk.green(`Removed the orphaned workspace directory ${entry.dir}${size}`));
|
|
1850
|
+
recordGcResult("workspaceDirectory", "done", entry.dir, { bytes: entry.bytes ?? null });
|
|
1851
|
+
}
|
|
1852
|
+
return failures;
|
|
1853
|
+
}
|
|
1854
|
+
function sizeText(bytes) {
|
|
1855
|
+
return bytes === null ? "size unknown" : formatBytes(bytes);
|
|
1856
|
+
}
|
|
1857
|
+
//#endregion
|
|
1858
|
+
export { teardownParkedIosSim as A, eraseParkedAvd as C, teardownOwnedBrowser as D, teardownOwnedAvd as E, takeGcResults as F, canonicalPath as I, listBuildSlots as M, releaseBuildSlot as N, teardownOwnedIosSim as O, recordGcResult as P, probePublicHttp as S, teardownBrowserHeld as T, terminateChild as _, collectWorkspaceOutputs as a, withManagedTunnelLock as b, listWorkspaceDirs as c, emptyWorkspaceDir as d, withIdleWorkspace as f, stopTunnel as g, startTunnelSequence as h, collectOrphanedWorkspaces as i, acquireBuildSlot as j, teardownParkedAvd as k, rootPresence as l, resolveSupervisorTarget as m, WORKSPACE_OUTPUT_DIRS as n, deleteOrphanedWorkspaces as o, workspaceInUse as p, clearWorkspaceOutputs as r, isInsideWorkspaces as s, REBUILD_COST as t, sizeText as u, withManagedRemoteWorktreeLock as v, eraseParkedIosSim as w, withManagedTunnelRemovalLock as x, withManagedRemoteWorktreeRemovalLock as y };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-
|
|
1
|
+
import { a as porcelainPath, c as registerWarm, d as removalRemedy, f as removeWorktreeTarget, i as matchWorktreeEntry, l as removalBlockers, m as worktreeCommand, n as excludePodChurn, o as reclaimKeys, p as warmedWorkspace, r as excludeWatchmanCookies, s as registerRemove, t as dependencyInstallCommand, u as removalPath } from "./worktree-BSYlofkq.mjs";
|
|
2
2
|
export { worktreeCommand as default, dependencyInstallCommand, excludePodChurn, excludeWatchmanCookies, matchWorktreeEntry, porcelainPath, reclaimKeys, registerRemove, registerWarm, removalBlockers, removalPath, removalRemedy, removeWorktreeTarget, warmedWorkspace };
|