stim 1.17.0 → 1.17.2

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.
Files changed (47) hide show
  1. package/dist/{android--GorydsK.mjs → android-B9yaNKwa.mjs} +15 -15
  2. package/dist/{budget-DM984mnd.mjs → budget-DfcgFdQB.mjs} +33 -12
  3. package/dist/{build-plan-CmQCoyT-.mjs → build-plan-BDsSi09V.mjs} +14 -14
  4. package/dist/{idle-B2m-Ovod.mjs → build-progress-D0WkjCPd.mjs} +56 -183
  5. package/dist/{cli-Daxug5-K.mjs → cli-CYXb29oE.mjs} +13 -13
  6. package/dist/cli.mjs +1 -1
  7. package/dist/{machines-C2XiNwh9.mjs → client-SvBdgObD.mjs} +348 -309
  8. package/dist/{deps-DNWaQs4V.mjs → deps-iKw0eD4P.mjs} +1 -1
  9. package/dist/{device-capacity-D0GWHnTM.mjs → device-capacity-ZC4XSZ4R.mjs} +2 -2
  10. package/dist/device-host-worker.mjs +3 -3
  11. package/dist/{device-ios-Bc7vbGwl.mjs → device-ios-C2Um-XUR.mjs} +1 -1
  12. package/dist/{doctor-Cnk9d7Hm.mjs → doctor-CFv1fCrF.mjs} +14 -13
  13. package/dist/{gc-DxCL2A46.mjs → gc-DEmkg3Xh.mjs} +9 -8
  14. package/dist/{gradle-D7-L2Th3.mjs → gradle-dJpre3Yn.mjs} +1 -1
  15. package/dist/{guide-DjrTQGik.mjs → guide-CSmhMTf8.mjs} +156 -127
  16. package/dist/{hosted-android-DwLS4Mse.mjs → hosted-android-E1Heoqnv.mjs} +3 -3
  17. package/dist/{hosted-client-wk1W_CNW.mjs → hosted-client-Bp4knSwu.mjs} +4 -4
  18. package/dist/{hosted-ios-aMo7Cljf.mjs → hosted-ios-BnbeYOUD.mjs} +1 -1
  19. package/dist/{hosted-logs-DqYmWtXc.mjs → hosted-logs-OcgIBvCT.mjs} +2 -2
  20. package/dist/{hosted-macos-dlHXEeF5.mjs → hosted-macos-DcxKjtfH.mjs} +2 -2
  21. package/dist/{hosted-native-C9xJ9rpA.mjs → hosted-native-1Ebbig4w.mjs} +3 -3
  22. package/dist/idle-BXG__1BA.mjs +176 -0
  23. package/dist/{idle-shutdown-_3oOV1V_.mjs → idle-shutdown-IGyNV8Cr.mjs} +1 -1
  24. package/dist/{ios-DE6duQoz.mjs → ios-BJ4XUSe1.mjs} +18 -18
  25. package/dist/{logs-DUoKlDoS.mjs → logs-BAaS7gS2.mjs} +3 -3
  26. package/dist/{macos-32po3kUq.mjs → macos-BIRQS90f.mjs} +66 -25
  27. package/dist/maintenance-run.mjs +2 -2
  28. package/dist/{metro-gateway-DmslUM30.mjs → metro-gateway-C-ijGI2F.mjs} +1 -1
  29. package/dist/{native-runtime-DhJI3IVQ.mjs → native-runtime-BEK171xQ.mjs} +1 -1
  30. package/dist/offload-worker.mjs +5 -5
  31. package/dist/{preview-CxPRIEht.mjs → preview-B-g9d7kV.mjs} +1 -1
  32. package/dist/{reload-qZei6iWn.mjs → reload-DcRxj3qG.mjs} +2 -2
  33. package/dist/settings.schema.json +86 -68
  34. package/dist/{start-BopZcr4n.mjs → start-AlfCPRVU.mjs} +1 -1
  35. package/dist/{start-uee1wWjY.mjs → start-DUz3mYdb.mjs} +1 -1
  36. package/dist/{status-dXX2JX1C.mjs → status-BA2pehwf.mjs} +9 -9
  37. package/dist/{stop-Cr1d8DSE.mjs → stop-BIiM49EY.mjs} +1 -1
  38. package/dist/{stop-BjizrQwv.mjs → stop-DQIasgKp.mjs} +3 -3
  39. package/dist/{stop-BCwvvs7F.mjs → stop-zF1y04f2.mjs} +1 -1
  40. package/dist/supervisor-run.mjs +4 -4
  41. package/dist/{support-BJPgYCu-.mjs → support-CsJNVfOc.mjs} +4 -4
  42. package/dist/{support-F9-sr0Oi.mjs → support-WvD__tSV.mjs} +2 -2
  43. package/dist/{toolchain-CNIBTIOv.mjs → toolchain-DNyR3NPq.mjs} +10 -6
  44. package/dist/{web-exQtGkoc.mjs → web-Dl0KSRHf.mjs} +2 -2
  45. package/dist/{worktree-ZpZR3S1k.mjs → worktree-Be_7NLKy.mjs} +6 -6
  46. package/dist/{worktree-Dc98cE6_.mjs → worktree-j3IcFAI5.mjs} +1 -1
  47. package/package.json +5 -5
@@ -7,38 +7,38 @@ import { B as settingsLayers, C as metroWarmupUrlSetting, F as settingFile, G as
7
7
  import { d as projectShortcut, n as appProjectProblem, r as detectIsExpo, s as findProjectRoot$1, t as NO_PROJECT_REFUSAL } from "./project-D47Rh0ly.mjs";
8
8
  import { l as resolveProjectMetro, o as pidExists, u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
9
9
  import { c as writeWorkspaceState, g as workspaceAgentDeviceDir, i as recordWorkspaceUse, l as emulatorLogFile, r as readWorkspaceState$1, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-DqcCbpE7.mjs";
10
- import { t as budgetGate } from "./budget-DM984mnd.mjs";
10
+ import { t as budgetGate } from "./budget-DfcgFdQB.mjs";
11
11
  import { A as providerDownloadPath, B as captureAssetManifest, D as fingerprintProject, E as fingerprintDiffRecord, F as storedAssetManifest, H as readAssetManifest, L as untrackedMissLine, M as refingerprintAfterMutation, N as resolveBuild, O as inputsChangedDuringBuild, P as storeBuild, R as untrackedNativeFiles, S as configInputsChanged, T as filesystemBuildCapability, V as compareAssetManifests, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as providerUploadOutcome, k as prepareProviderDownloadDir, m as acquireBuildLock, v as waitForSharedBuild, x as changedDuringBuildLine, z as assetDiffReason } from "./device-lease-DpoS36_u.mjs";
12
12
  import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-41v_d2x9.mjs";
13
13
  import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-BKa8wNN5.mjs";
14
14
  import { $ as trimAndroidCaches, A as listAvds, B as ownedAvdSystemImage, D as hostSystemImageArch, F as ownedAvdDeviceProfile, G as probeEmulatorSerial, I as ownedAvdDirectory, J as resolveOwnedAvdSerial, K as profileNeedsFoldFeature, O as listAdbDevices, Q as systemImageSupportsFold, T as findBuildTool, U as physicalDeviceModel, W as pickDefaultSystemImage, Y as resolvePhysicalDevice, a as androidDeviceAbi, ft as parkedMaxSetting, i as androidDataFreeBytes, j as listInstalledSystemImages, k as listAvdDeviceProfiles, q as resetAdoptedAvd, r as androidBuildToolName, rt as configuredAndroidEmulatorApp, t as DEFAULT_AVD_DEVICE_PROFILE, tt as waitForBoot, u as androidToolCwd } from "./android-B_YNZy61.mjs";
15
15
  import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
16
16
  import { m as teardownOwnedAvd } from "./ownership-BMLqyBgJ.mjs";
17
- import { C as recordRunStats, _ as tapBuildLog, g as startBuildProgress, h as recordFinishedBuild, l as NO_BUILD_PROGRESS, v as createRunRecorder, w as statsProjectKey$1, x as recordCapacityRefusal, y as readRunEstimates } from "./idle-B2m-Ovod.mjs";
17
+ import { _ as statsProjectKey$1, c as recordFinishedBuild, d as createRunRecorder, f as readRunEstimates, g as recordRunStats, l as startBuildProgress, m as recordCapacityRefusal, n as NO_BUILD_PROGRESS, u as tapBuildLog } from "./build-progress-D0WkjCPd.mjs";
18
18
  import { r as createNdjsonWriter } from "./ndjson-PclOIwVY.mjs";
19
- import { E as ccacheActivityLine, T as CCACHE_UNAVAILABLE, b as tailLines, k as resolveCcache, n as androidToolchain, t as androidRequirements, u as HEARTBEAT_INTERVAL_MS, w as CCACHE_NOT_RUN, y as startBuildHeartbeat } from "./toolchain-CNIBTIOv.mjs";
19
+ import { E as ccacheActivityLine, T as CCACHE_UNAVAILABLE, b as tailLines, k as resolveCcache, n as androidToolchain, t as androidRequirements, u as HEARTBEAT_INTERVAL_MS, w as CCACHE_NOT_RUN, y as startBuildHeartbeat } from "./toolchain-DNyR3NPq.mjs";
20
20
  import { t as cleanLine } from "./server-expo-CHTyXD0G.mjs";
21
- import { _ as resolveBuildPlacement, a as chooseBuildMachine, d as remotePhaseText, h as parseBuildMachineOption, i as buildPlacementCandidates, l as offloadPlacement, m as namedBuildMachine, o as closeOffload, p as OffloadRefusal, s as offloadBuild, u as placementLoad } from "./machines-C2XiNwh9.mjs";
22
- import { r as hostedMetroSettings } from "./metro-gateway-DmslUM30.mjs";
21
+ import { a as offloadBuild, c as placementLoad, d as OffloadRefusal, f as namedBuildMachine, h as resolveBuildPlacement, i as closeOffload, l as remotePhaseText, n as buildPlacementCandidates, p as parseBuildMachineOption, r as chooseBuildMachine, s as offloadPlacement } from "./client-SvBdgObD.mjs";
22
+ import { r as hostedMetroSettings } from "./metro-gateway-C-ijGI2F.mjs";
23
23
  import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-DyRQru0q.mjs";
24
- import { n as DeviceAdmissionRefusal, r as checkDeviceCapacity, t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-D0GWHnTM.mjs";
24
+ import { n as DeviceAdmissionRefusal, r as checkDeviceCapacity, t as DEFAULT_DEVICE_SLOT_WAIT_MS } from "./device-capacity-ZC4XSZ4R.mjs";
25
25
  import { S as restartedAppNote, b as launchAndroidReleaseApp, c as androidDevClientUrl, g as installConflictKind, h as installAndroidApp, r as DEFAULT_METRO_PORT, s as androidAppProcess, t as ADB_INSTALL_TIMEOUT_MS, y as launchAndroidApp } from "./app-install-VPkI5WEg.mjs";
26
- import { C as resolveSystemImage, S as resolveDeviceProfile, T as systemImageRefusal, _ as isReleaseVariant, a as PLATFORM, b as pooledAndroidDevice, c as androidSystemImageSetting, d as apkPackage, f as deviceProfileRefusal, g as foldableImageRefusal, h as findAapt, i as NO_FINGERPRINT, l as androidVariantSetting, m as dumpApkManifest, n as LAUNCH_FAILED, o as androidBuildOptions, p as displayPath, r as NO_DEVICE, s as androidDevClientScheme, t as INSTALL_FAILED, u as apkDevClientFacts, v as noDeviceDiagnostic, w as resolveVariant, x as remoteAvdFlagRefusal, y as parseXmltree } from "./support-F9-sr0Oi.mjs";
26
+ import { C as resolveSystemImage, S as resolveDeviceProfile, T as systemImageRefusal, _ as isReleaseVariant, a as PLATFORM, b as pooledAndroidDevice, c as androidSystemImageSetting, d as apkPackage, f as deviceProfileRefusal, g as foldableImageRefusal, h as findAapt, i as NO_FINGERPRINT, l as androidVariantSetting, m as dumpApkManifest, n as LAUNCH_FAILED, o as androidBuildOptions, p as displayPath, r as NO_DEVICE, s as androidDevClientScheme, t as INSTALL_FAILED, u as apkDevClientFacts, v as noDeviceDiagnostic, w as resolveVariant, x as remoteAvdFlagRefusal, y as parseXmltree } from "./support-WvD__tSV.mjs";
27
27
  import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
28
28
  import { i as staleNativeDirRefusal, n as recordPrebuild, r as runPrebuild, t as planPrebuild } from "./prebuild-D7RUMkwN.mjs";
29
- import { c as formatDiagnostic, i as buildAndroid, o as productFlavorRefusal, s as readProductFlavors } from "./gradle-D7-L2Th3.mjs";
29
+ import { c as formatDiagnostic, i as buildAndroid, o as productFlavorRefusal, s as readProductFlavors } from "./gradle-dJpre3Yn.mjs";
30
30
  import { a as VERIFY_TIMEOUT_MS, d as verifyAndroidReleaseLaunch, f as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unattributedLaunchLines, n as LAUNCH_FATAL, r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING, u as unverifiedLaunchLines } from "./launch-verify-lTnWZikR.mjs";
31
31
  import { a as acquireRunLease, c as lostRefusal, d as runLease, f as waitFlagConflict, l as parseDeviceWait, o as leaseExpiryText, s as lostLine, t as DEBUG_VERIFY_STEP_MS, u as releaseLeaseOnSignal } from "./device-lease-run-B8YltIH_.mjs";
32
32
  import { a as writeHostedAndroid, i as writeDevicePlacement, t as readHostedAndroid } from "./ios-state-8L3lgum6.mjs";
33
- import { _ as AvdRecoveryError, a as refusePlan, b as devicePlacementLine, c as skippedMissReason, d as refreshUpdatesManifestFile, g as AvdBootError, h as ensureOwnedDevice, i as printPlan, l as UPDATES_MANIFEST_NAME, m as ensureBooted, n as planFlagRefusal, o as explainBuildMiss, p as didSetUpDevice, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as detectEntryFile, v as warmMetro, y as automaticDevicePlacement } from "./build-plan-CmQCoyT-.mjs";
34
- import { n as prepareHostedAndroid, t as placeHostedAndroid } from "./hosted-android-DwLS4Mse.mjs";
33
+ import { _ as AvdRecoveryError, a as refusePlan, b as devicePlacementLine, c as skippedMissReason, d as refreshUpdatesManifestFile, g as AvdBootError, h as ensureOwnedDevice, i as printPlan, l as UPDATES_MANIFEST_NAME, m as ensureBooted, n as planFlagRefusal, o as explainBuildMiss, p as didSetUpDevice, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as detectEntryFile, v as warmMetro, y as automaticDevicePlacement } from "./build-plan-BDsSi09V.mjs";
34
+ import { n as prepareHostedAndroid, t as placeHostedAndroid } from "./hosted-android-E1Heoqnv.mjs";
35
35
  import { n as nativeRunCommand, r as siblingPlatformSlots, t as launchSlotScope } from "./slot-launch-DmjBmpQV.mjs";
36
36
  import { a as easAuthNote, c as loadProjectProvider, f as resolveEasCliBin, i as checkEasAuth, m as uploadRemote, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as resolveRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS } from "./remote-cache-Ci4DQYYj.mjs";
37
37
  import { a as ensureMetroReachable, c as remoteAndroidDeps, n as binOnPath, o as ensureRemoteBootOwned, u as resolveRemoteContext, w as ownedSessionName } from "./device-remote-hFSkpfQu.mjs";
38
38
  import { d as runCancellationSignal, f as withNativeBuildRun, r as cancelledFailure, u as runCancellation } from "./native-run-D1Q56rAD.mjs";
39
39
  import { a as isEasBuildFailure, o as planEasDevelopmentBuild, s as resolveEasDevelopmentBuild } from "./simslim-BWNrc3M3.mjs";
40
- import { c as startDevServer, m as detectAppIds, p as detectAndroidPackage } from "./start-uee1wWjY.mjs";
41
- import { i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-DhJI3IVQ.mjs";
40
+ import { c as startDevServer, m as detectAppIds, p as detectAndroidPackage } from "./start-DUz3mYdb.mjs";
41
+ import { i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-BEK171xQ.mjs";
42
42
  import { t as selectFromPool } from "./device-pool-3o7s5lo4.mjs";
43
43
  import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-C-NMnhrk.mjs";
44
44
  import { n as resolveAndroidCas, r as resolveAndroidCompilerCache } from "./android-cas-ZFpjJBL_.mjs";
@@ -806,7 +806,7 @@ function fail$1(code, message, remedy, extra = {}) {
806
806
  async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo, device, physical, hostedAbi, remote: remoteTarget, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { deviceAbi, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, acquireSlot, releaseSlot, planPrebuildFor, prebuild, build, ccacheFor, swapApk, readState, now }) {
807
807
  const { phase, out, estimates, stats, step, miss, hit: lateHit, place, waitingOn, waitingFor } = progress;
808
808
  let fallbackMachine = null;
809
- let hereReason = "no build machine is paired";
809
+ let hereReason = "no remote Mac is paired";
810
810
  let slotWaitMs;
811
811
  const buildMachine = record.buildMachine ?? "auto";
812
812
  const fallBack = (reason, line = reason) => {
@@ -2584,7 +2584,7 @@ function androidCommand(program) {
2584
2584
  registerAndroid(program);
2585
2585
  }
2586
2586
  function registerAndroid(program) {
2587
- program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--build-machine <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device-profile <id>", "Hardware profile to create this workspace's owned AVD with, as an `avdmanager list device -c` id (e.g. \"pixel_fold\", \"pixel_tablet\"). Overrides the android.deviceProfile setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the available ids.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. Stim never creates, boots, or deletes a physical device.").option("--remote <target>", "Run on eas, proxy, or a named approved Mac from hosting.machines; auto places on an approved Mac when this Mac is full or busy", (value) => {
2587
+ program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--remote-build <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device-profile <id>", "Hardware profile to create this workspace's owned AVD with, as an `avdmanager list device -c` id (e.g. \"pixel_fold\", \"pixel_tablet\"). Overrides the android.deviceProfile setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the available ids.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. Stim never creates, boots, or deletes a physical device.").option("--remote <target>", "Run on eas, proxy, or a named approved Mac from remote.machines; auto places on an approved Mac when this Mac is full or busy", (value) => {
2588
2588
  if (!parseMachine(value)) throw new InvalidArgumentError("expected eas, proxy, auto, or a tailnet machine name");
2589
2589
  return value;
2590
2590
  }).option("--wait <seconds>", "How long to wait for another workspace to release the device it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once). Without --device, wait for an owned-device slot (default 600 seconds; --no-wait refuses immediately).").option("--no-wait", "Install on a device another workspace leases instead of waiting: this run takes no lease and, when both workspaces build the same app id, the install terminates the holder's running app. Without --device, refuse a full device cap or existing slot queue immediately.").action(async (opts) => {
@@ -2610,7 +2610,7 @@ function registerAndroid(program) {
2610
2610
  try {
2611
2611
  return await runAndroid({
2612
2612
  root,
2613
- buildMachine: opts.buildMachine,
2613
+ buildMachine: opts.remoteBuild,
2614
2614
  slot: opts.slot,
2615
2615
  easProfile: opts.easProfile,
2616
2616
  json: Boolean(opts.json),
@@ -16,7 +16,7 @@ import { A as listAvds, I as ownedAvdDirectory, at as isStimOwnedSim, ct as drop
16
16
  import { _ as parseRuntimeVersion, f as listIosDeviceTypes, u as listAllIosSims } from "./ios-DSfnPfse.mjs";
17
17
  import { _ as teardownParkedAvd, d as eraseParkedAvd, f as eraseParkedIosSim, g as teardownOwnedIosSim, m as teardownOwnedAvd, t as resolveSupervisorTarget, v as teardownParkedIosSim } from "./ownership-BMLqyBgJ.mjs";
18
18
  import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
19
- import { i as idleShutdownCandidates, n as collectOwnedDeviceActivity, o as shutDownIdleDevices, s as workspaceBuildInProgress, t as collectIdleDevices } from "./idle-B2m-Ovod.mjs";
19
+ import { i as idleShutdownCandidates, n as collectOwnedDeviceActivity, o as shutDownIdleDevices, s as workspaceBuildInProgress, t as collectIdleDevices } from "./idle-BXG__1BA.mjs";
20
20
  import { a as collectWorkspaceOutputs, r as clearWorkspaceOutputs } from "./workspaces-Bcib97-6.mjs";
21
21
  import { n as supervisorError } from "./errors-B6W7FkxQ.mjs";
22
22
  import { l as withdrawDevServerStopRequest, s as requestDevServerStop } from "./stop-cause-rhmGfwvt.mjs";
@@ -490,7 +490,11 @@ function attributeMachineUsage({ processes, footprints, environments, roots, sim
490
490
  claim(pid, `metro:${env.path}`, workspaceOwner("metro", env, port ? `Metro :${port}` : "Metro", port ? String(port) : null));
491
491
  }
492
492
  if (root.build && present.has(root.build.pid)) {
493
- const label = root.build.platform === "ios" ? "iOS build" : "Android build";
493
+ const label = {
494
+ ios: "iOS build",
495
+ android: "Android build",
496
+ macos: "macOS build"
497
+ }[root.build.platform];
494
498
  claim(root.build.pid, `build:${env.path}`, workspaceOwner("build", env, label, root.build.platform));
495
499
  }
496
500
  for (const pid of root.macosPids ?? []) if (present.has(pid)) claim(pid, `macos:${env.path}`, workspaceOwner("macos", env, env.macos?.product ?? "macOS app", null));
@@ -1418,6 +1422,28 @@ async function inspectWatchmanMemory() {
1418
1422
  }));
1419
1423
  }
1420
1424
  //#endregion
1425
+ //#region src/commands/gc/archive-selector.ts
1426
+ const KIND_SELECTORS = {
1427
+ "archived-logs": "logs",
1428
+ "archived-recordings": "recordings",
1429
+ "archived-agent": "agentActions"
1430
+ };
1431
+ function parseArchiveSelector(scope) {
1432
+ const trimmed = scope.trim();
1433
+ const colon = trimmed.indexOf(":");
1434
+ const name = (colon === -1 ? trimmed : trimmed.slice(0, colon)).toLowerCase();
1435
+ const id = colon === -1 ? null : trimmed.slice(colon + 1);
1436
+ if (name === "archived") return {
1437
+ kind: null,
1438
+ id
1439
+ };
1440
+ const kind = KIND_SELECTORS[name];
1441
+ return kind ? {
1442
+ kind,
1443
+ id
1444
+ } : null;
1445
+ }
1446
+ //#endregion
1421
1447
  //#region src/commands/gc/caches.ts
1422
1448
  const DAY_MS$1 = 864e5;
1423
1449
  function cacheSweepIsScoped() {
@@ -1440,12 +1466,7 @@ const WORKSPACE_OUTPUTS = "workspaces";
1440
1466
  const RECORDINGS = "recordings";
1441
1467
  const PARKED_DEVICES = "parked";
1442
1468
  function includesArchives(name) {
1443
- const wanted = name?.trim().toLowerCase();
1444
- return Boolean(wanted && (wanted === "archived" || wanted.startsWith("archived:") || [
1445
- "archived-logs",
1446
- "archived-recordings",
1447
- "archived-agent"
1448
- ].includes(wanted)));
1469
+ return name ? parseArchiveSelector(name) !== null : false;
1449
1470
  }
1450
1471
  function includesParkedDevices(name) {
1451
1472
  return name?.trim().toLowerCase() === PARKED_DEVICES;
@@ -2534,7 +2555,7 @@ function describeShortfall(budget, measure, short) {
2534
2555
  return [
2535
2556
  ...short.disk.map((v) => `${formatSpace(v.freeMb)} free on ${v.volume}, below the ${formatSpace(floor)} floor`),
2536
2557
  ...short.memory && measure.memory ? [`roughly ${formatSpace(measure.memory.committedMb)} of memory committed, over the ${formatSpace(budget.maxCommittedMemoryMb)} budget`] : [],
2537
- ...short.workspaces && measure.memory ? [`${measure.memory.liveWorkspaces} live workspaces, over the limit of ${budget.maxLiveWorkspaces}`] : []
2558
+ ...short.workspaces && measure.memory ? [`${measure.memory.liveWorkspaces} active workspaces, over the limit of ${budget.maxLiveWorkspaces}`] : []
2538
2559
  ];
2539
2560
  }
2540
2561
  async function enforceBudget({ root, note, dryRun = false, budget: resolved }, overrides = {}) {
@@ -2656,12 +2677,12 @@ function budgetFindings(budget, measure, short, plan) {
2656
2677
  }
2657
2678
  if (short.memory || short.workspaces) findings.push({
2658
2679
  level: "note",
2659
- title: "Live environments are over the memory budget",
2680
+ title: "Active environments are over the memory budget",
2660
2681
  detail: `${describeShortfall(budget, measure, {
2661
2682
  ...short,
2662
2683
  disk: []
2663
2684
  }).join("; ")}. The next ios, android or start shuts down idle owned devices and stops idle dev servers in other workspaces first.`,
2664
- fix: "Run `stim status` to see what is live, and `stim stop` in workspaces you own that you no longer need."
2685
+ fix: "Run `stim status` to see what is active, and `stim stop` in workspaces you own that you no longer need."
2665
2686
  });
2666
2687
  return findings;
2667
2688
  }
@@ -2713,4 +2734,4 @@ function budgetLine(report) {
2713
2734
  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"}`;
2714
2735
  }
2715
2736
  //#endregion
2716
- export { includesWorkspaceOutputs as A, inspectWatchmanMemory as B, findStaleProjectDevices as C, includesArchives as D, emptyCaches as E, selectsBeyondCaches as F, memoryWorkPending as G, memoryLines as H, trimCaches as I, phase as J, reclaimMemory as K, GRADLE_DAEMONS_KIND as L, planCacheEmptying as M, previewScopedEmptying as N, includesParkedDevices as O, selectCaches as P, sizeCaches as Q, WATCHMAN_KIND as R, findStaleDeviceRecords as S, withAndroidAvdSizes as T, memoryScope as U, memoryCacheKind as V, memorySweepIsScoped as W, readFootprints as X, attributeMachineUsage as Y, discoverCaches as Z, describeParkedSims as _, machineNumber as a, eraseParkedDevices as b, resolveBudget as c, collectDeviceLeases as d, collectParkedAvds as f, deleteProjectDevices as g, deleteParkedSims as h, inspectBudget as i, isWorkspacesScope as j, includesRecordings as k, stopOwnedMetroForReset as l, deleteParkedAvds as m, budgetLine as n, peekBudget as o, collectParkedSims as p, scopedMemoryReport as q, enforceBudget as r, readVolumeSpace as s, budgetGate as t, DEVICE_LIST_TIMEOUT_MS$1 as u, describeUnverifiableDevices as v, unverifiedDeviceCommand as w, findOrphanedDevices as x, deviceSweepIsScoped as y, collectMemoryReport as z };
2737
+ export { sizeCaches as $, includesWorkspaceOutputs as A, collectMemoryReport as B, findStaleProjectDevices as C, includesArchives as D, emptyCaches as E, selectsBeyondCaches as F, memorySweepIsScoped as G, memoryCacheKind as H, trimCaches as I, scopedMemoryReport as J, memoryWorkPending as K, parseArchiveSelector as L, planCacheEmptying as M, previewScopedEmptying as N, includesParkedDevices as O, selectCaches as P, discoverCaches as Q, GRADLE_DAEMONS_KIND as R, findStaleDeviceRecords as S, withAndroidAvdSizes as T, memoryLines as U, inspectWatchmanMemory as V, memoryScope as W, attributeMachineUsage as X, phase as Y, readFootprints as Z, describeParkedSims as _, machineNumber as a, eraseParkedDevices as b, resolveBudget as c, collectDeviceLeases as d, collectParkedAvds as f, deleteProjectDevices as g, deleteParkedSims as h, inspectBudget as i, isWorkspacesScope as j, includesRecordings as k, stopOwnedMetroForReset as l, deleteParkedAvds as m, budgetLine as n, peekBudget as o, collectParkedSims as p, reclaimMemory as q, enforceBudget as r, readVolumeSpace as s, budgetGate as t, DEVICE_LIST_TIMEOUT_MS$1 as u, describeUnverifiableDevices as v, unverifiedDeviceCommand as w, findOrphanedDevices as x, deviceSweepIsScoped as y, WATCHMAN_KIND as z };
@@ -7,22 +7,22 @@ import { Tt as removeTemporaryEntry, a as androidAvdConfigSetting, at as gitComm
7
7
  import { u as ownedDeviceLabel } from "./project-D47Rh0ly.mjs";
8
8
  import { o as pidExists } from "./metro-g8NqiJp-.mjs";
9
9
  import { d as sharedBuildCache } from "./workspace-state-DqcCbpE7.mjs";
10
- import { o as peekBudget } from "./budget-DM984mnd.mjs";
10
+ import { o as peekBudget } from "./budget-DfcgFdQB.mjs";
11
11
  import { C as diffFingerprintSources, I as storedSources, w as entryDir, y as artifactIn } from "./device-lease-DpoS36_u.mjs";
12
12
  import { A as listAvds, B as ownedAvdSystemImage, E as getAvdNameForSerial, F as ownedAvdDeviceProfile, J as resolveOwnedAvdSerial, L as ownedAvdMatchesConfiguration, O as listAdbDevices, P as nextConsolePort, R as ownedAvdName, W as pickDefaultSystemImage, b as createOwnedAvd, f as assertOwnedAvdStopped, ft as parkedMaxSetting, g as avdPoolConfiguration, j as listInstalledSystemImages, n as OWNED_AVD_CONFIG_DEFAULTS, pt as readParked, st as adoptParked, t as DEFAULT_AVD_DEVICE_PROFILE, tt as waitForBoot, ut as isLegacyDeletionClaim, v as bootAndroidEmulator, y as configureNewOwnedAvd } from "./android-B_YNZy61.mjs";
13
13
  import { j as readHostMemoryPressure, u as listAllIosSims } from "./ios-DSfnPfse.mjs";
14
14
  import { _ as teardownParkedAvd, m as teardownOwnedAvd } from "./ownership-BMLqyBgJ.mjs";
15
- import { b as readStats$1, p as estimateBuild } from "./idle-B2m-Ovod.mjs";
16
- import { b as tailLines, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-CNIBTIOv.mjs";
15
+ import { o as estimateBuild, p as readStats$1 } from "./build-progress-D0WkjCPd.mjs";
16
+ import { b as tailLines, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-DNyR3NPq.mjs";
17
17
  import { t as cleanLine } from "./server-expo-CHTyXD0G.mjs";
18
- import { g as resolveBuildMachine, m as namedBuildMachine, t as configuredMachines } from "./machines-C2XiNwh9.mjs";
19
- import { a as call, o as connectHost } from "./hosted-client-wk1W_CNW.mjs";
20
- import { t as clearDeviceIdleShutdown } from "./idle-shutdown-_3oOV1V_.mjs";
21
- import { i as countLiveOwnedDevices, n as DeviceAdmissionRefusal, p as withDeviceBootAdmission, s as peekDeviceSlots } from "./device-capacity-D0GWHnTM.mjs";
18
+ import { f as namedBuildMachine, m as resolveBuildMachine, v as hostingMachines } from "./client-SvBdgObD.mjs";
19
+ import { a as call, o as connectHost } from "./hosted-client-Bp4knSwu.mjs";
20
+ import { t as clearDeviceIdleShutdown } from "./idle-shutdown-IGyNV8Cr.mjs";
21
+ import { i as countLiveOwnedDevices, n as DeviceAdmissionRefusal, p as withDeviceBootAdmission, s as peekDeviceSlots } from "./device-capacity-ZC4XSZ4R.mjs";
22
22
  import { i as staleNativeDirRefusal } from "./prebuild-D7RUMkwN.mjs";
23
- import { i as ensureOwnedIosDevice, r as ensureIosBooted } from "./device-ios-Bc7vbGwl.mjs";
23
+ import { i as ensureOwnedIosDevice, r as ensureIosBooted } from "./device-ios-C2Um-XUR.mjs";
24
24
  import { r as readHostedNative, s as writeHostedNative } from "./ios-state-8L3lgum6.mjs";
25
- import { n as prepareHostedNative } from "./hosted-native-C9xJ9rpA.mjs";
25
+ import { n as prepareHostedNative } from "./hosted-native-1Ebbig4w.mjs";
26
26
  import { a as easAuthNote } from "./remote-cache-Ci4DQYYj.mjs";
27
27
  import { t as reconcileSimSlim } from "./simslim-BWNrc3M3.mjs";
28
28
  import { randomUUID } from "node:crypto";
@@ -69,7 +69,7 @@ function decideDevicePlacement(inputs) {
69
69
  const cannotTake = !(max === 0 || count !== null && count < max) || queued > 0;
70
70
  const usage = max > 0 ? `${count} of ${max} devices in use` : `${count} devices in use, no device cap`;
71
71
  const localReason = count === null ? "cannot tell how many devices run here; local boot admission decides" : cannotTake ? `${usage}${queued ? `, ${queued} runs queued ahead` : ""}` : here.budgetRefusal ?? (here.memoryPressure !== "normal" ? `host memory pressure ${here.memoryPressure ?? "unknown"} here` : `load ${here.loadPerCore.toFixed(1)}/core here, ${usage}`);
72
- if (!offers.length) return local$1("no hosting machines configured; " + localReason);
72
+ if (!offers.length) return local$1("no remote Macs configured; " + localReason);
73
73
  if (count === null) return local$1(localReason);
74
74
  if (!cannotTake && here.memoryPressure === "normal" && !here.budgetRefusal && here.loadPerCore < here.maxLoadPerCore) return local$1(localReason);
75
75
  const skipped = [];
@@ -99,7 +99,7 @@ function decideDevicePlacement(inputs) {
99
99
  if (!admitted.length) return local$1(`${localReason}; no host admits${cannotTake && !noWait ? "; waiting locally if needed" : ""}`, skipped);
100
100
  const machines = admitted.map(({ machine, offer }) => ({
101
101
  machine,
102
- reason: `${localReason}; ${machine}${machine === buildMachine ? " is the explicit build machine," : ""} load ${offer.resources.loadPerCore === null ? "unknown" : offer.resources.loadPerCore.toFixed(1) + "/core"}`
102
+ reason: `${localReason}; ${machine}${machine === buildMachine ? " is the explicit remote Mac," : ""} load ${offer.resources.loadPerCore === null ? "unknown" : offer.resources.loadPerCore.toFixed(1) + "/core"}`
103
103
  }));
104
104
  return {
105
105
  kind: "host",
@@ -185,7 +185,7 @@ function local(reason, skipped = []) {
185
185
  skipped
186
186
  };
187
187
  }
188
- async function automaticDevicePlacement({ root, slot, platform, selectors, buildMachine, noWait }, { machines = configuredMachines, read = readHostedNative, write = writeHostedNative, resume = prepareHostedNative, peek = () => peekDeviceSlots({
188
+ async function automaticDevicePlacement({ root, slot, platform, selectors, buildMachine, noWait }, { machines = hostingMachines, read = readHostedNative, write = writeHostedNative, resume = prepareHostedNative, peek = () => peekDeviceSlots({
189
189
  platform,
190
190
  project: getProject(root),
191
191
  slot
@@ -211,8 +211,8 @@ async function automaticDevicePlacement({ root, slot, platform, selectors, build
211
211
  sticky: true
212
212
  };
213
213
  const entries = machines();
214
- if (entries === null) throw Object.assign(/* @__PURE__ */ new Error("hosting.machines is invalid. Run stim guide settings and correct it."), { code: "STIM_HOSTING_REFUSED" });
215
- const preference = resolveBuildMachine(buildMachine, process.env.STIM_OFFLOAD_MACHINE, loadConfig$1()?.offload?.machine);
214
+ if (entries === null) throw Object.assign(/* @__PURE__ */ new Error("remote.machines is invalid. Run stim guide settings and correct it."), { code: "STIM_HOSTING_REFUSED" });
215
+ const preference = resolveBuildMachine(buildMachine, process.env.STIM_REMOTE_BUILD, loadConfig$1()?.remote?.build);
216
216
  buildMachine = namedBuildMachine(preference) ? preference : void 0;
217
217
  const load = capacity();
218
218
  const here = {
@@ -1,15 +1,10 @@
1
- import { D as withConfigLock$1, H as projectDeviceSlots } from "./config-D0DbpZtM.mjs";
1
+ import { D as withConfigLock$1 } from "./config-D0DbpZtM.mjs";
2
2
  import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
3
- import { a as formatElapsed, o as formatLongDuration, u as plural } from "./command-output-CDAIFD-8.mjs";
4
- import { a as updateWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey } from "./workspace-state-DqcCbpE7.mjs";
5
- import { i as recordGcResult } from "./in-use-CvGOUn-x.mjs";
6
- import { o as idleForMs, r as createActivityReader } from "./activity-IRvJY_ru.mjs";
7
- import { z as ownedAvdSerialResolver } from "./android-B_YNZy61.mjs";
8
- import { g as teardownOwnedIosSim, m as teardownOwnedAvd } from "./ownership-BMLqyBgJ.mjs";
3
+ import { a as formatElapsed, u as plural } from "./command-output-CDAIFD-8.mjs";
4
+ import { a as updateWorkspaceState, t as clearWorkspaceStateKey } from "./workspace-state-DqcCbpE7.mjs";
9
5
  import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
10
6
  import { dirname } from "node:path";
11
7
  import { BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, LAST_BUILD_KEYS, STATS_VERSION, decodeStats, isJsonObject, parseMissReason, readRunEstimates, readStats as readStats$1, statsFile, statsProjectKey as statsProjectKey$1, trimCapacityRefusals, trimCapacityWaits, trimSamples, wholePhases, workspaceBuildDetailFile } from "@stim-cli/core/state";
12
- import chalk from "chalk";
13
8
  //#region src/engine/stats.ts
14
9
  const PLACEMENT_MAX_AGE_MS = 6048e5;
15
10
  function emptyStats() {
@@ -351,6 +346,13 @@ const GRADLE_TASK = /^> Task (:\S+)/;
351
346
  */
352
347
  const XCODE_TARGET_DONE = /^(Touch|RegisterExecutionPolicyException|CodeSign)$/;
353
348
  const GRADLE_CONFIGURE = /^> Configure project /;
349
+ /**
350
+ * SwiftPM prints `[done / total] name` once it plans the build (with U+2009 thin spaces around the slash in Swift 6.4
351
+ * output), `[done/total] Compiling ...` in older toolchains; Swift 6.4 names the target being worked on, and
352
+ * `<product>-product` is the link of a product.
353
+ */
354
+ const SWIFTPM_PROGRESS = /^\[(\d+)\s*\/\s*(\d+)\](?:\s+(.*))?$/;
355
+ const SWIFTPM_CONFIGURE = /^(Fetching|Fetched|Computing version|Computed|Creating working copy|Working copy of)\b|^\[(Pre-planning|Planning|Using on-disk description)/;
354
356
  const XCODE_STEPS = [
355
357
  [/^(CpResource|CopyPNGFile|CopyStringsFile|CompileAssetCatalog\w*|CompileStoryboard|CompileXIB|LinkStoryboards|ProcessInfoPlistFile)$/, "resources"],
356
358
  [/^(Compile\w*|Swift\w*|ScanDependencies|Precompile\w*)$/, "compile"],
@@ -388,8 +390,23 @@ function shortXcodeAction(action, args, target) {
388
390
  const subject = action === "PhaseScriptExecution" ? unescape(tokens[0] ?? "") : baseName(unescape(tokens.findLast((token) => token.startsWith("/")) ?? ""));
389
391
  return clip(`${action}${subject ? ` ${subject}` : ""} (${target})`);
390
392
  }
391
- /** What one line of xcodebuild or Gradle output says about the build's progress, or null for any other line. */
393
+ function swiftpmStep(text) {
394
+ return /^Linking\b|-product$/.test(text) ? "link" : "compile";
395
+ }
396
+ /** What one line of xcodebuild, Gradle or SwiftPM output says about the build's progress, or null for any other line. */
392
397
  function parseBuildToolLine(msg) {
398
+ const counted = SWIFTPM_PROGRESS.exec(msg);
399
+ if (counted) {
400
+ const text = counted[3]?.trim() ?? "";
401
+ return {
402
+ kind: "count",
403
+ done: Number(counted[1]),
404
+ total: Number(counted[2]),
405
+ step: swiftpmStep(text),
406
+ line: text ? clip(text) : null
407
+ };
408
+ }
409
+ if (SWIFTPM_CONFIGURE.test(msg)) return { kind: "configure" };
393
410
  const graph = TARGET_GRAPH.exec(msg);
394
411
  if (graph) return {
395
412
  kind: "total",
@@ -426,7 +443,8 @@ function parseBuildToolLine(msg) {
426
443
  }
427
444
  /**
428
445
  * Accumulates a build's tool output into its detail: xcodebuild counts the distinct targets it finished against the
429
- * total its dependency graph note gives; Gradle counts the task lines it printed and has no total.
446
+ * total its dependency graph note gives; Gradle counts the task lines it printed and has no total; SwiftPM reports
447
+ * its own `[done / total]` counts, which the parser passes through.
430
448
  */
431
449
  function createBuildDetailParser() {
432
450
  let seen = false;
@@ -435,6 +453,7 @@ function createBuildDetailParser() {
435
453
  let total = null;
436
454
  let line = null;
437
455
  let tasks = 0;
456
+ let counted = null;
438
457
  const targets = /* @__PURE__ */ new Set();
439
458
  return {
440
459
  push(msg) {
@@ -450,6 +469,16 @@ function createBuildDetailParser() {
450
469
  step = "configure";
451
470
  return true;
452
471
  }
472
+ if (parsed.kind === "count") {
473
+ unit = "steps";
474
+ counted = {
475
+ done: parsed.done,
476
+ total: parsed.total
477
+ };
478
+ step = parsed.step;
479
+ if (parsed.line) line = parsed.line;
480
+ return true;
481
+ }
453
482
  unit = parsed.unit;
454
483
  if (parsed.unit === "tasks") tasks += 1;
455
484
  else if (parsed.finished) targets.add(parsed.id);
@@ -459,6 +488,14 @@ function createBuildDetailParser() {
459
488
  },
460
489
  detail(updatedAt) {
461
490
  if (!seen) return null;
491
+ if (unit === "steps" && counted) return {
492
+ step,
493
+ unit,
494
+ done: Math.min(counted.done, counted.total),
495
+ total: counted.total,
496
+ line,
497
+ updatedAt
498
+ };
462
499
  const done = unit === "tasks" ? tasks : unit === "targets" ? targets.size : null;
463
500
  return {
464
501
  step,
@@ -591,7 +628,7 @@ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note
591
628
  };
592
629
  const settle = (outcome) => {
593
630
  record.outcome = outcome;
594
- if (projectKey) record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
631
+ if (projectKey && platform !== "macos") record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
595
632
  };
596
633
  const waits = /* @__PURE__ */ new Map();
597
634
  return {
@@ -605,11 +642,12 @@ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note
605
642
  startedAt: at
606
643
  });
607
644
  if (phase !== "wait") delete record.waitingOn;
608
- const outcome = record.outcome ? null : settledOutcome(phase, record.phases);
645
+ const outcome = record.outcome || platform === "macos" ? null : settledOutcome(phase, record.phases);
609
646
  if (outcome) settle(outcome);
610
647
  write();
611
648
  },
612
649
  estimate(key) {
650
+ if (platform === "macos") return;
613
651
  projectKey = key;
614
652
  record.estimate = estimateBuild(projectHistory(key), platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
615
653
  write();
@@ -758,7 +796,7 @@ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now
758
796
  const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
759
797
  const savedSlot = isJsonObject(slots[slot]) ? slots[slot] : {};
760
798
  const savedDevice = slot === "default" ? state[platform] : savedSlot[platform];
761
- if (record.devicePlacement || isJsonObject(savedDevice)) {
799
+ if (platform !== "macos" && (record.devicePlacement || isJsonObject(savedDevice))) {
762
800
  const device = isJsonObject(savedDevice) ? { ...savedDevice } : {};
763
801
  if (record.devicePlacement) device.devicePlacement = record.devicePlacement;
764
802
  else delete device.devicePlacement;
@@ -776,6 +814,7 @@ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now
776
814
  }
777
815
  };
778
816
  }
817
+ if (platform === "macos") return withHistoryEntry(state, platform, entry);
779
818
  return withHistoryEntry({
780
819
  ...state,
781
820
  lastBuild: record,
@@ -786,7 +825,7 @@ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now
786
825
  function withInterruptedBuild(state) {
787
826
  const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
788
827
  if (!left) return state;
789
- const last = state[LAST_BUILD_KEYS[left.platform]];
828
+ const last = left.platform === "macos" ? state[BUILD_HISTORY_KEY]?.macos?.[0] : state[LAST_BUILD_KEYS[left.platform]];
790
829
  if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
791
830
  return withHistoryEntry(state, left.platform, {
792
831
  platform: left.platform,
@@ -810,7 +849,7 @@ function parseActiveBuild(value) {
810
849
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
811
850
  const record = value;
812
851
  const claim = record.claim;
813
- if (record.platform !== "ios" && record.platform !== "android") return null;
852
+ if (record.platform !== "ios" && record.platform !== "android" && record.platform !== "macos") return null;
814
853
  if (!isPhase(record.phase)) return null;
815
854
  if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
816
855
  if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
@@ -906,7 +945,7 @@ function median(values) {
906
945
  return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
907
946
  }
908
947
  function estimateBuild(history, platform, known, deviceSetup) {
909
- const lists = history?.[platform];
948
+ const lists = platform === "macos" ? void 0 : history?.[platform];
910
949
  const outcome = known ?? latestOutcome(lists);
911
950
  const samples = matchDeviceSetup(outcome && lists?.[outcome] || [], deviceSetup);
912
951
  const phaseMs = {};
@@ -994,170 +1033,4 @@ function buildStatusLine(report, now) {
994
1033
  return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
995
1034
  }
996
1035
  //#endregion
997
- //#region src/commands/gc/idle.ts
998
- function findOwnedDeviceActivity({ config, sims, androidSerial, readActivity, deadProjects = [] }) {
999
- const booted = new Map(sims.filter((sim) => sim.state === "Booted").map((sim) => [sim.udid, sim.name]));
1000
- const dead = new Set(deadProjects);
1001
- const found = [];
1002
- for (const [project, record] of Object.entries(config?.projects ?? {})) {
1003
- if (dead.has(project)) continue;
1004
- for (const { slot, platforms } of projectDeviceSlots(record)) {
1005
- const ios = platforms.ios;
1006
- if (ios?.owned && ios.deviceUdid && booted.has(ios.deviceUdid)) found.push({
1007
- kind: "ios",
1008
- id: ios.deviceUdid,
1009
- name: booted.get(ios.deviceUdid) ?? ios.deviceUdid,
1010
- project,
1011
- slot,
1012
- activity: readActivity({
1013
- platform: "ios",
1014
- id: ios.deviceUdid,
1015
- slot,
1016
- workspace: project
1017
- })
1018
- });
1019
- const android = platforms.android;
1020
- const serial = android?.owned && android.avdName ? androidSerial(android.avdName) : null;
1021
- if (android?.avdName && serial) found.push({
1022
- kind: "android",
1023
- id: android.avdName,
1024
- name: android.avdName,
1025
- project,
1026
- slot,
1027
- activity: readActivity({
1028
- platform: "android",
1029
- id: serial,
1030
- slot,
1031
- workspace: project
1032
- })
1033
- });
1034
- }
1035
- }
1036
- return found;
1037
- }
1038
- function findIdleDevices({ buildInProgress, now, ...inputs }) {
1039
- return findOwnedDeviceActivity(inputs).filter((device) => device.activity.state === "idle").map(({ kind, id, name, project, slot, activity }) => ({
1040
- kind,
1041
- id,
1042
- name,
1043
- project,
1044
- slot,
1045
- lastActivityAt: activity.lastActivityAt ?? null,
1046
- idleForMs: idleForMs(activity, now),
1047
- buildInProgress: buildInProgress(project)
1048
- }));
1049
- }
1050
- function idleShutdownCandidates(devices, idleMs) {
1051
- return devices.filter((d) => !d.buildInProgress && d.idleForMs !== null && d.idleForMs >= idleMs);
1052
- }
1053
- function parseIdleDuration(value) {
1054
- const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value.trim());
1055
- if (!match) return null;
1056
- const unit = {
1057
- m: 6e4,
1058
- h: 36e5,
1059
- d: 864e5
1060
- }[match[2]];
1061
- return Number(match[1]) * unit;
1062
- }
1063
- function workspaceBuildInProgress(project) {
1064
- const record = parseActiveBuild(readWorkspaceState$1(project)?.[ACTIVE_BUILD_KEY]);
1065
- if (!record) return false;
1066
- try {
1067
- return activeBuildState(record.claim) !== "stale";
1068
- } catch {
1069
- return true;
1070
- }
1071
- }
1072
- function deviceActivityInputs(config, sims, now) {
1073
- const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
1074
- return {
1075
- config,
1076
- sims,
1077
- readActivity: createActivityReader({ now }),
1078
- androidSerial: (avdName) => {
1079
- try {
1080
- return resolve(avdName).serial ?? null;
1081
- } catch {
1082
- return null;
1083
- }
1084
- }
1085
- };
1086
- }
1087
- function collectOwnedDeviceActivity(config, sims, now = Date.now()) {
1088
- return findOwnedDeviceActivity(deviceActivityInputs(config, sims, now));
1089
- }
1090
- function collectIdleDevices(config, sims, deadProjects, now = Date.now()) {
1091
- return findIdleDevices({
1092
- ...deviceActivityInputs(config, sims, now),
1093
- deadProjects,
1094
- now,
1095
- buildInProgress: workspaceBuildInProgress
1096
- });
1097
- }
1098
- function idleDeviceLines(devices) {
1099
- if (devices.length === 0) return [];
1100
- return [`Idle owned devices (${devices.length}) - booted with no driver, claim, or recent activity:`, ...devices.map((d) => {
1101
- const slot = d.slot === "default" ? "" : ` [${d.slot}]`;
1102
- const idle = d.idleForMs === null ? "idle for an unknown time" : `idle ${formatLongDuration(d.idleForMs)}`;
1103
- const build = d.buildInProgress ? ", build in progress" : "";
1104
- return ` ${d.kind}${slot} ${d.name} (${d.project}) -- ${idle}${build}`;
1105
- })];
1106
- }
1107
- function shutDownIdleDevices(devices, idleMs, recollect) {
1108
- const candidates = idleShutdownCandidates(devices, idleMs);
1109
- const shutDown = [];
1110
- if (candidates.length === 0) {
1111
- console.log(chalk.dim(`No owned device has been idle for ${formatLongDuration(idleMs)} or more.`));
1112
- return {
1113
- failures: 0,
1114
- shutDown
1115
- };
1116
- }
1117
- const fresh = idleShutdownCandidates(recollect(), idleMs);
1118
- let failures = 0;
1119
- for (const device of candidates) {
1120
- const what = `${device.kind} ${device.name}`;
1121
- const current = fresh.find((d) => d.kind === device.kind && d.id === device.id && d.project === device.project && d.slot === device.slot);
1122
- if (!current) {
1123
- console.log(chalk.dim(`Kept ${what}: it is no longer idle for ${formatLongDuration(idleMs)}.`));
1124
- recordGcResult("idleDevice", "kept", device.name, {
1125
- id: device.id,
1126
- detail: `it is no longer idle for ${formatLongDuration(idleMs)}`
1127
- });
1128
- continue;
1129
- }
1130
- const outcome = device.kind === "ios" ? teardownOwnedIosSim(device.id, { label: device.name }) : teardownOwnedAvd(device.id, { owner: {
1131
- projectPath: device.project,
1132
- slot: device.slot
1133
- } });
1134
- if (outcome.status === "torn-down") {
1135
- shutDown.push(device);
1136
- console.log(chalk.green(`Shut down ${what}, idle ${formatLongDuration(current.idleForMs)}`));
1137
- recordGcResult("idleDevice", "done", device.name, {
1138
- id: device.id,
1139
- detail: `idle ${formatLongDuration(current.idleForMs)}`
1140
- });
1141
- } else if (outcome.status === "missing") console.log(chalk.dim(`${what} is already gone; nothing to shut down.`));
1142
- else if (outcome.status === "skipped") {
1143
- console.log(chalk.yellow(`Skipped ${what}: ${outcome.reason}`));
1144
- recordGcResult("idleDevice", "kept", device.name, {
1145
- id: device.id,
1146
- detail: outcome.reason
1147
- });
1148
- } else {
1149
- failures++;
1150
- console.log(chalk.red(`Failed to shut down ${what}: ${outcome.reason}`));
1151
- recordGcResult("idleDevice", "failed", device.name, {
1152
- id: device.id,
1153
- detail: outcome.reason
1154
- });
1155
- }
1156
- }
1157
- return {
1158
- failures,
1159
- shutDown
1160
- };
1161
- }
1162
- //#endregion
1163
- export { recordRunStats as C, recordCapacityWait as S, tapBuildLog as _, parseIdleDuration as a, readStats$1 as b, ACTIVE_BUILD_KEY as c, buildReport as d, buildStatusLine as f, startBuildProgress as g, recordFinishedBuild as h, idleShutdownCandidates as i, NO_BUILD_PROGRESS as l, parseActiveBuild as m, collectOwnedDeviceActivity as n, shutDownIdleDevices as o, estimateBuild as p, idleDeviceLines as r, workspaceBuildInProgress as s, collectIdleDevices as t, activeBuildState as u, createRunRecorder as v, statsProjectKey$1 as w, recordCapacityRefusal as x, readRunEstimates as y };
1036
+ export { statsProjectKey$1 as _, buildStatusLine as a, recordFinishedBuild as c, createRunRecorder as d, readRunEstimates as f, recordRunStats as g, recordCapacityWait as h, buildReport as i, startBuildProgress as l, recordCapacityRefusal as m, NO_BUILD_PROGRESS as n, estimateBuild as o, readStats$1 as p, activeBuildState as r, parseActiveBuild as s, ACTIVE_BUILD_KEY as t, tapBuildLog as u };