stim 1.20.2 → 1.22.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 +141 -8
- package/dist/acquire-artifact-Co2k4f7O.mjs +171 -0
- package/dist/act-DsuqEkiM.mjs +2801 -0
- package/dist/activity-CMLmzp7o.mjs +1397 -0
- package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-DUFaTMdd.mjs} +23 -67
- package/dist/{android-DCKZrNvV.mjs → android-ByRMUoiJ.mjs} +157 -93
- package/dist/{android-Mz_Inn3w.mjs → android-C7sVmyI9.mjs} +299 -116
- package/dist/{android-Dlzxshgp.mjs → android-DGkNqa_c.mjs} +5 -5
- package/dist/{android-HqP1_vB_.mjs → android-DR5lZ2Az.mjs} +2 -2
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-ngferVq2.mjs} +7 -6
- package/dist/android-project-BCAAmMwz.mjs +12 -0
- package/dist/android-project-DVWyCbWU.d.mts +391 -0
- package/dist/api.d.mts +810 -64
- package/dist/api.mjs +782 -1
- package/dist/{artifact-HSwkIWEQ.mjs → artifact-8EY8SAPw.mjs} +240 -213
- package/dist/{artifact-D3czlUvT.mjs → artifact-DJPy518Y.mjs} +203 -164
- package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
- package/dist/{browser-web-CA-F1GQo.mjs → browser-web-Bcv99PBM.mjs} +194 -64
- package/dist/budget-Cvwn54qV.mjs +9285 -0
- package/dist/{build-DYDbfkk5.mjs → build-CabC3G23.mjs} +153 -98
- package/dist/build-cache-Dv7RN200.mjs +602 -0
- package/dist/build-plan-DUC8Ka9y.mjs +248 -0
- package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DSeQjt-Q.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-zdKiYQ3E.mjs → ccache-Btwc36-I.mjs} +10 -9
- package/dist/{cdp-Dq_ypAlJ.mjs → cdp-3fwICjzi.mjs} +18 -5
- package/dist/{chrome-BnzZMqsR.mjs → chrome-Bbw689-6.mjs} +7 -4
- package/dist/{cli-CLP3diBm.mjs → cli-CHZa9Lvk.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/client-OyRoEuSr.mjs +1577 -0
- package/dist/collector-run.d.mts +4 -40
- package/dist/collector-run.mjs +9 -8
- package/dist/{command-output-BTy8hZ0F.mjs → command-output-gwpm28fu.mjs} +1 -1
- package/dist/config-DlrsduwG.mjs +955 -0
- package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-x9rN6bhs.mjs} +14 -4
- package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-1I9KZT1Y.mjs} +20 -5
- package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
- package/dist/{dev-client-DAWVIGBu.mjs → dev-client-BSDR5h3F.mjs} +2 -2
- package/dist/{device-BECOiufl.mjs → device-B-L3Fbxy.mjs} +91 -34
- package/dist/device-DklWZLqb.mjs +1068 -0
- package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-DK5_EwRS.mjs} +42 -13
- package/dist/device-host-worker.mjs +76 -79
- package/dist/{device-ios-COSi6oS1.mjs → device-ios-DoB6KFCO.mjs} +77 -51
- package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-xJPQ_QQG.mjs} +14 -26
- package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-BMkdsefq.mjs} +5 -5
- package/dist/{doctor-kfMBnUw6.mjs → doctor-Bo7BXLux.mjs} +271 -320
- package/dist/{doctor-CB8oZKCk.mjs → doctor-D5_EzwfA.mjs} +186 -91
- package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
- package/dist/doctor-fingerprint.mjs +19 -0
- package/dist/doctor-thjWAV0z.mjs +2 -0
- package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-N2wDotwQ.mjs} +40 -21
- package/dist/{eas-build-JyfqyHfC.mjs → eas-build-CwknaQYj.mjs} +53 -20
- package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-CSgAulr5.mjs} +41 -214
- package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-DlY_serQ.mjs} +230 -11
- package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-DBWO2rxE.mjs} +172 -82
- package/dist/exec-DEoAhcze.mjs +858 -0
- package/dist/exec-DnYc4HGH.d.mts +78 -0
- package/dist/{gc-qWOMdnER.mjs → gc-CXxN-4SE.mjs} +1091 -1029
- package/dist/gc-DnNDQyaP.mjs +3 -0
- package/dist/{guide-G9cAbVAc.mjs → guide-Br0LEfKy.mjs} +1165 -297
- package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-B-9f-jkd.mjs} +10 -8
- package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DZAPrcro.mjs} +34 -19
- package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CsCS21hn.mjs} +1 -1
- package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-FIRx9X2f.mjs} +77 -43
- package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-_awYSpfv.mjs} +35 -22
- package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-BdzE668-.mjs} +49 -27
- package/dist/idle-C4cZ757K.d.mts +24 -0
- package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DDg3SdvY.mjs} +11 -10
- package/dist/ios-CDvlmUs7.d.mts +24 -0
- package/dist/{ios-BwVCF7oA.mjs → ios-Ds1clbIt.mjs} +8 -8
- package/dist/{ios-device-D7pi2Sca.mjs → ios-device--h_-8ENa.mjs} +51 -26
- package/dist/{ios-device-B5veSDDQ.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
- package/dist/{ios-RkW4pnQf.mjs → ios-hcBpnEGk.mjs} +200 -93
- package/dist/{ios-Ce7bc7br.mjs → ios-pm4nL6By.mjs} +160 -108
- package/dist/{ios-project-K9hY_Jab.mjs → ios-project-CZhKODF3.mjs} +13 -13
- package/dist/ios-signing-BtAffm0A.mjs +489 -0
- package/dist/{ios-state-CBLe1xYw.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
- package/dist/{ios-nOLJGVdy.mjs → ios-xtlRHaeB.mjs} +1 -1
- package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Bwhh4S7V.mjs} +30 -25
- package/dist/{launch-C3qJ6Agb.mjs → launch-BjxemNpK.mjs} +85 -543
- package/dist/{launch-F4sOqAhB.mjs → launch-CCzXlc8r.mjs} +91 -90
- package/dist/logs-BfwwadsZ.mjs +479 -0
- package/dist/logs-jTS_lHSo.mjs +248 -0
- package/dist/{macos-D7uDvO-z.mjs → macos-DVlSSyUg.mjs} +1 -1
- package/dist/macos-NfV2D7dO.mjs +694 -0
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +123 -248
- package/dist/{metro-DnCEjCxs.mjs → metro-DiXtA3Ty.mjs} +107 -30
- package/dist/metro-gateway-CKZqKqx7.mjs +209 -0
- package/dist/{named-ports-4WopRPg-.mjs → named-ports-DkEzOfzO.mjs} +42 -90
- package/dist/native-android-CqgnOgsT.mjs +645 -0
- package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
- package/dist/native-gradle-inputs-Dnh84Zbd.mjs +211 -0
- package/dist/native-inputs-TRTTTRxt.mjs +91 -0
- package/dist/native-run-NwUuxbkg.mjs +276 -0
- package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-B7KIafpM.mjs} +11 -9
- package/dist/native-source-Y0yLhFyQ.mjs +133 -0
- package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-D_VOfFL7.mjs} +26 -18
- package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-BYDOHWLN.mjs} +104 -60
- package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
- package/dist/offload-worker.d.mts +59 -41
- package/dist/offload-worker.mjs +478 -115
- package/dist/operation-exec-BW0em61G.mjs +171 -0
- package/dist/{ownership-DCtw_2IA.mjs → ownership-C5fo5Edb.mjs} +3 -3
- package/dist/{page-DRHy329N.mjs → page-DBL2PiUU.mjs} +12 -5
- package/dist/paths-BsJMoPP2.mjs +12 -0
- package/dist/paths-DQtTgsBf.mjs +42 -0
- package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BnGgJRRZ.mjs} +5 -5
- package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-DIsMtN-d.mjs} +15 -11
- package/dist/{ports-DdSUicVo.mjs → ports-Cy1RkmuQ.mjs} +3 -3
- package/dist/prebuild-D4JoEAEs.mjs +484 -0
- package/dist/{project-_phNIJfs.mjs → project-wM_XFTvE.mjs} +65 -37
- package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-W1IuLXDt.mjs} +102 -20
- package/dist/pull-request-eODyIqZF.d.mts +124 -0
- package/dist/pull-requests.d.mts +2 -120
- package/dist/pull-requests.mjs +2 -2
- package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-6OZ7MSM7.mjs} +121 -72
- package/dist/{gradle-DSrXb6lG.mjs → react-native-build-Dvd8hC21.mjs} +292 -15
- package/dist/react-native-doctor-DsoSF1Y9.mjs +234 -0
- package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-4u1Rn-GR.mjs} +71 -39
- package/dist/{recordings-D0d5aQt0.mjs → recordings-CQmfzAh7.mjs} +12 -9
- package/dist/registration-BcRgF6Ox.mjs +51 -0
- package/dist/{reload-C8JhxjSh.mjs → reload-BzkYabB-.mjs} +94 -47
- package/dist/reload-D7AVlb8N.mjs +2 -0
- package/dist/{remote-BiR6aYjy.mjs → remote-DjGDmlTZ.mjs} +26 -18
- package/dist/result-D2Ykz_iD.mjs +435 -0
- package/dist/{run-BtPgpKks.mjs → run-DidHghD1.mjs} +5 -5
- package/dist/selection-DSMbWEX2.mjs +620 -0
- package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CafzuyFB.mjs} +3 -4
- package/dist/{server-command-CTtCkmcQ.mjs → server-command-C6QjeupS.mjs} +14 -7
- package/dist/{server-expo-DsguMGUF.mjs → server-expo-CrjB29pq.mjs} +54 -11
- package/dist/server-expo-D58c9L0M.mjs +2 -0
- package/dist/{settings-B717odTD.mjs → settings-C7O8A6ZI.mjs} +309 -119
- package/dist/settings-DpR-1Wnn.mjs +114 -0
- package/dist/settings-write-CzD60rOD.mjs +360 -0
- package/dist/settings.schema.json +176 -16
- package/dist/{simslim-CCr3rE-A.mjs → simslim-BNckWpXi.mjs} +14 -12
- package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-CbfmNgM6.mjs} +15 -20
- package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
- package/dist/stage-Bps5oius.mjs +200 -0
- package/dist/{start-TXeMmmO2.mjs → start-Br-oxqMD.mjs} +1 -1
- package/dist/start-EojN4WFz.mjs +1364 -0
- package/dist/{state-D1Icyjlu.mjs → state--smjFSTL.mjs} +55 -13
- package/dist/{state-CG_OFoaA.mjs → state-08I3hw3_.mjs} +3 -2
- package/dist/{stats-BoY5sEPU.mjs → stats-D3GerlFW.mjs} +7 -13
- package/dist/stats-report-BzaPrRm6.mjs +16 -0
- package/dist/{status-BTA7kKiQ.mjs → status-BRROykC8.mjs} +7 -5
- package/dist/status-EvrK72L2.mjs +2 -0
- package/dist/{status-WgFbkRzj.mjs → status-WBDajew2.mjs} +554 -452
- package/dist/{status-watch-C23ILtf9.mjs → status-watch-Bg_u-pwR.mjs} +222 -25
- package/dist/status-worker.d.mts +1 -0
- package/dist/status-worker.mjs +19 -0
- package/dist/stim-desktop-D5OGpYZM.mjs +112 -0
- package/dist/{stop-DR6VoDIk.mjs → stop-DTZ9uTw3.mjs} +2 -2
- package/dist/{stop-DPEhunlw.mjs → stop-Dky10AEJ.mjs} +33 -23
- package/dist/{stop-BNmBMi1F.mjs → stop-Mv6W9FAk.mjs} +137 -98
- package/dist/supervisor-run.d.mts +8 -17
- package/dist/supervisor-run.mjs +56 -28
- package/dist/{support-CwjbFs9H.mjs → support-CNioewsd.mjs} +14 -14
- package/dist/{support-DMTqj3Hm.mjs → support-yUiOjnVY.mjs} +20 -13
- package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
- package/dist/swiftpm-macos-BIak-Rxv.mjs +532 -0
- package/dist/toolchain-BY8X8HXx.mjs +2 -0
- package/dist/toolchain-DpJMHq0n.mjs +876 -0
- package/dist/{trigger-CigAYjeL.mjs → trigger-Cbyc41d_.mjs} +21 -6
- package/dist/trigger-yb_nFzPF.mjs +2 -0
- package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-CA3TgT3-.mjs} +263 -156
- package/dist/web-CZ07gd77.mjs +2 -0
- package/dist/{web-BDBMxDpx.mjs → web-DKx6yoFA.mjs} +20 -14
- package/dist/web-run.mjs +13 -12
- package/dist/windows-report.d.mts +1 -0
- package/dist/windows-report.mjs +18 -0
- package/dist/windows-report.ps1 +43 -0
- package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-U08dEzhG.mjs} +62 -58
- package/dist/{workspaces-C36s2jb9.mjs → workspaces-CpANmBlq.mjs} +1723 -1286
- package/dist/{worktree-CgvJYJ-Q.mjs → worktree-CHecZ4Oq.mjs} +1097 -547
- package/dist/worktree-ZqZVjD9K.mjs +2 -0
- package/dist/xcode-BXn9-xYx.mjs +896 -0
- package/package.json +7 -5
- package/shim/android-audio/Main.java +24 -0
- package/shim/android-audio/README.md +17 -0
- package/shim/android-audio.jar +0 -0
- package/shim/android-optimizations.gradle +7 -5
- package/dist/activity-BSV745Kz.mjs +0 -629
- package/dist/api-qvOzWyfO.mjs +0 -154
- package/dist/api-run.mjs +0 -294
- package/dist/app-install-BIKtMfPq.mjs +0 -896
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
- package/dist/budget-f7516Zk0.mjs +0 -4106
- package/dist/build-facts-DcLv2HSd.d.mts +0 -111
- package/dist/cancellation-C_22VQTH.mjs +0 -24
- package/dist/client-qQAaXSUs.mjs +0 -1771
- package/dist/config-BYDxlMY3.mjs +0 -562
- package/dist/device-DuiPJQSn.mjs +0 -290
- package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
- package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
- package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
- package/dist/exec-DqKo9GKJ.mjs +0 -268
- package/dist/git-DDfFzkMm.mjs +0 -45
- package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
- package/dist/logs-BGrEUaEs.mjs +0 -383
- package/dist/macos-Ch5VJmcS.mjs +0 -584
- package/dist/metro-gateway-CX9Xlkq2.mjs +0 -103
- package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
- package/dist/native-android-D5qc3-_v.mjs +0 -226
- package/dist/native-gradle-inputs-BsLRrl7u.mjs +0 -349
- package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
- package/dist/plan-C4TjdPsR.mjs +0 -260
- package/dist/prebuild-DYbucPXy.mjs +0 -212
- package/dist/preview-78a9kR_-.mjs +0 -1011
- package/dist/react-native-build-CtCccJtb.mjs +0 -239
- package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
- package/dist/remote-cache-OyOyVIS3.mjs +0 -526
- package/dist/result-CaJg5Iat.mjs +0 -186
- package/dist/server-expo-Bigriskl.mjs +0 -2
- package/dist/settings-BORNaaCO.mjs +0 -402
- package/dist/settings-vk3mJGSm.d.mts +0 -13
- package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
- package/dist/stage-KNTQopqv.mjs +0 -157
- package/dist/start-BWqzODpb.mjs +0 -1116
- package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
- package/dist/swiftpm-macos-DRNVJWlb.mjs +0 -119
- package/dist/tailnet-Dh-qiYzG.mjs +0 -265
- package/dist/toolchain-BFkAcstd.mjs +0 -2
- package/dist/toolchain-DxSsNssu.mjs +0 -1657
- package/dist/trigger-9_USgmxz.mjs +0 -2
- package/dist/web-Dq-i3wzJ.mjs +0 -2
- package/dist/worktree-DpLdCHga.mjs +0 -2
- package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
- package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
|
@@ -1,41 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { b as parseSimctlList, f as listAllIosSimsAsync } from "./ios-
|
|
18
|
-
import {
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import "./
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { n as
|
|
27
|
-
import { a as watchStatusSources, i as watchPayload, n as WATCH_LIGHT_INTERVAL_MS, r as createRefreshScheduler, t as WATCH_FALLBACK_MS } from "./status-watch-C23ILtf9.mjs";
|
|
1
|
+
import { g as process_identity_exports, t as getExecutor } from "./exec-DEoAhcze.mjs";
|
|
2
|
+
import { m as workspaceLogsDir$1, p as workspaceLogErrorIndex } from "./paths-DQtTgsBf.mjs";
|
|
3
|
+
import { G as projectDeviceSlots, P as formatBytes, R as volumeRootFor, U as parseDeviceSlotKey, V as deviceSlotKey, _ as loadConfig$1, d as getConfigDir } from "./config-DlrsduwG.mjs";
|
|
4
|
+
import { a as formatElapsed, i as formatDuration, r as clockTime, u as plural } from "./command-output-gwpm28fu.mjs";
|
|
5
|
+
import { s as gitAsync } from "./operation-exec-BW0em61G.mjs";
|
|
6
|
+
import { r as readWorkspaceState$1 } from "./workspace-state-U08dEzhG.mjs";
|
|
7
|
+
import { Mt as repoRoot, Y as resolveSettings, _t as gitCommonDir, ot as workspaceHiddenSetting, wt as linkedWorktreesOnDisk, yt as gitCommonDirOnDisk } from "./settings-C7O8A6ZI.mjs";
|
|
8
|
+
import { I as readWorkspaceLaunches, M as readMetroTunnel, P as readRemoteSession, S as readAppJson, a as findServerWorkspace, l as projectShortcut, u as detectPlatforms, v as detectIsExpo, y as detectTutorial } from "./project-wM_XFTvE.mjs";
|
|
9
|
+
import { a as parseNdjsonLine } from "./ndjson-CgE_o3Dl.mjs";
|
|
10
|
+
import { c as pidExists, d as resolveProjectMetro, h as isMetroRunning, i as listeningPids, l as processCwd, o as listeningPidsByPort, u as processCwds } from "./metro-DiXtA3Ty.mjs";
|
|
11
|
+
import { a as readWebPage, o as readWebRecord, u as webFacts } from "./state--smjFSTL.mjs";
|
|
12
|
+
import { A as remoteDeviceState, C as environmentState, D as parseDfFree, E as metroReverseTargets, M as tightVolumes, N as unprovisionedWorktrees, O as poolLine, P as withWebFacts, S as diskLine, T as gitSummaryText, _ as addReverseMissingIssue, b as deviceLeaseLines, g as activityLabel, j as statusActivity, k as remoteDeviceLine, r as readEasSessionLedger$1, v as applyMachineMemory, x as deviceLeaseStates, y as capacity } from "./eas-session-ledger-DlY_serQ.mjs";
|
|
13
|
+
import { F as buildStatusLine, G as readStats$1, I as bundlingActivity, N as activeBuildState, P as buildReport, R as parseActiveBuild, Y as statsProjectKey$1, h as describeMetroLastStop, j as ACTIVE_BUILD_KEY, o as machineNumber, vn as hasMetroReverse, vr as attributeMachineUsage, y as metroLastStop, yr as readFootprints } from "./budget-Cvwn54qV.mjs";
|
|
14
|
+
import { h as resolveSupervisorTarget } from "./workspaces-CpANmBlq.mjs";
|
|
15
|
+
import { a as createDeviceProcessTables, b as leaseIsExpired, h as tailLines, m as readWebActivity, r as createActivityReader, w as parseWorkspaceLeases, x as listLeaseFiles } from "./activity-CMLmzp7o.mjs";
|
|
16
|
+
import { A as listAdbDevices, B as ownedAvdDeviceProfile, W as ownedAvdSerialResolver, _t as parkedMaxSetting, dt as POOL_SETTING_REMEDY, vt as readParked } from "./android-C7sVmyI9.mjs";
|
|
17
|
+
import { b as parseSimctlList, f as listAllIosSimsAsync } from "./ios-hcBpnEGk.mjs";
|
|
18
|
+
import { f as probeHostedSession } from "./hosted-client-DZAPrcro.mjs";
|
|
19
|
+
import "./hosted-macos-_awYSpfv.mjs";
|
|
20
|
+
import { i as readSupervisorState } from "./stop-Mv6W9FAk.mjs";
|
|
21
|
+
import { n as maintenanceLines, r as maintenanceStatus } from "./status-BRROykC8.mjs";
|
|
22
|
+
import { f as mergeState, i as createStatusMeasurer, n as workspacePhase, r as applyStatusMeasures } from "./warm-progress-CA3TgT3-.mjs";
|
|
23
|
+
import { r as workspaceRecordingEnabled } from "./recordings-CQmfzAh7.mjs";
|
|
24
|
+
import { d as readIosDevices, s as isReachable } from "./ios-device--h_-8ENa.mjs";
|
|
25
|
+
import { t as triggerMaintenance } from "./trigger-Cbyc41d_.mjs";
|
|
26
|
+
import { a as createRefreshScheduler, c as watchStatusSources, n as WATCH_LIGHT_INTERVAL_MS, o as watchChangeKey, r as WATCH_MACHINE_INTERVAL_MS, s as watchPayload, t as WATCH_FALLBACK_MS } from "./status-watch-Bg_u-pwR.mjs";
|
|
28
27
|
import { t as watchStdoutReader } from "./stdout-reader-C8yjre1x.mjs";
|
|
29
|
-
import {
|
|
28
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
30
29
|
import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
31
30
|
import { join, posix, resolve } from "node:path";
|
|
32
|
-
import { basename as basename$1, dirname as dirname$1, join as join$1 } from "path";
|
|
33
|
-
import { DEVICE_RECLAIM_REASON, ERROR_SOURCES, archiveRoot, archivedUsage, bundleMarkerPlatform, countErrorEntries, gitMergeCacheDir, hostedAndroidPlacements, hostedAndroidRecords, hostedAndroidStatus, hostedIosPlacements, hostedIosRecords, hostedIosStatus, linkReplacedArchives, logFiles, macosAppState, parseHostedAndroidPlacement, parseHostedIosPlacement, queryLogs, readArchives, readBuildDetail, readBuildHistory, readDeviceIdleShutdowns, readDevicePlacement, readIdleStop, readLastBuilds, readMacosRecord, recordMatches, sortByTs, unreadableHostedAndroid, unreadableHostedIos, withDerivedFacts, withGitChip, withStateReadCache } from "@stim-cli/core/state";
|
|
34
|
-
import { closeSync as closeSync$1, existsSync as existsSync$1, fstatSync as fstatSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
35
31
|
import { rotatedLogPath } from "@stim-cli/core";
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
32
|
+
import { DEVICE_RECLAIM_REASON, ERROR_SOURCES, archiveRoot, archivedUsage, bundleMarkerPlatform, countErrorEntries, gitMergeCacheDir, hostedAndroidPlacements, hostedAndroidRecords, hostedAndroidStatus, hostedIosPlacements, hostedIosRecords, hostedIosStatus, linkReplacedArchives, logFiles, macosAppState, parseHostedAndroidPlacement, parseHostedIosPlacement, queryLogs, readArchives, readBuildDetail, readBuildHistory, readDeviceIdleShutdowns, readDevicePlacement, readIdleStop, readLastBuilds, readMacosRecord, recordMatches, sortByTs, unreadableHostedAndroid, unreadableHostedIos, withDerivedFacts, withGitChip, withStateReadCache } from "@stim-cli/core/state";
|
|
33
|
+
import { basename as basename$1, dirname as dirname$1, join as join$1 } from "path";
|
|
38
34
|
import chalk from "chalk";
|
|
35
|
+
import { closeSync as closeSync$1, existsSync as existsSync$1, fstatSync as fstatSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
36
|
+
import { homedir, totalmem, userInfo } from "os";
|
|
39
37
|
//#region src/device-host/hosted-native-status.ts
|
|
40
38
|
function hostedNativeProbe(placement, probe, slot, platform) {
|
|
41
39
|
const label = platform === "ios" ? "iOS" : "Android";
|
|
@@ -502,7 +500,8 @@ function gitFilesStamp(worktree, refs) {
|
|
|
502
500
|
* default-branch commit stands in, because a merged branch stays merged. A judgement that timed out is not retried
|
|
503
501
|
* for the same HEAD and target for five minutes. With `maxAgeMs`, a summary made that recently in this process is
|
|
504
502
|
* reused while the git files it depends on are unchanged, so a change that is not staged can take up to `maxAgeMs`
|
|
505
|
-
* to show; so is the null of a worktree whose directory is gone.
|
|
503
|
+
* to show; so is the null of a worktree whose directory is gone. Deferred merge verdicts are retried independently
|
|
504
|
+
* of the cached counts without renewing their age.
|
|
506
505
|
*/
|
|
507
506
|
async function readWorktreeGit(worktrees, { skip, maxAgeMs = 0 }) {
|
|
508
507
|
const now = Date.now();
|
|
@@ -520,7 +519,7 @@ async function readWorktreeGit(worktrees, { skip, maxAgeMs = 0 }) {
|
|
|
520
519
|
const files = maxAgeMs > 0 ? gitFilesStamp(worktree, refs) : null;
|
|
521
520
|
if (memo && memo.files !== null && memo.files === files?.stamp && now - memo.at < maxAgeMs) return {
|
|
522
521
|
path: worktree.path,
|
|
523
|
-
memo
|
|
522
|
+
memo
|
|
524
523
|
};
|
|
525
524
|
const repository = worktree.repository;
|
|
526
525
|
if (repository && !targets.has(repository)) targets.set(repository, defaultBranchOf(repository));
|
|
@@ -543,7 +542,16 @@ async function readWorktreeGit(worktrees, { skip, maxAgeMs = 0 }) {
|
|
|
543
542
|
const summaries = /* @__PURE__ */ new Map();
|
|
544
543
|
for (const read of reads) {
|
|
545
544
|
if ("memo" in read) {
|
|
546
|
-
|
|
545
|
+
const memo = read.memo;
|
|
546
|
+
if (memo?.git && memo.pendingMerge) {
|
|
547
|
+
const merge = mergedInto(read.path, memo.pendingMerge.head, memo.pendingMerge.target, budget);
|
|
548
|
+
memo.git = {
|
|
549
|
+
...memo.git,
|
|
550
|
+
mergedInto: merge.into
|
|
551
|
+
};
|
|
552
|
+
if (!merge.deferred) delete memo.pendingMerge;
|
|
553
|
+
}
|
|
554
|
+
summaries.set(read.path, memo?.git ?? null);
|
|
547
555
|
continue;
|
|
548
556
|
}
|
|
549
557
|
if (!read.status) {
|
|
@@ -566,12 +574,16 @@ async function readWorktreeGit(worktrees, { skip, maxAgeMs = 0 }) {
|
|
|
566
574
|
upstream: counts.upstream,
|
|
567
575
|
target: read.target?.ref ?? null
|
|
568
576
|
};
|
|
569
|
-
const settled =
|
|
577
|
+
const settled = refs.upstream === read.refs.upstream && refs.target === read.refs.target;
|
|
570
578
|
recent.set(read.path, {
|
|
571
579
|
at: read.at,
|
|
572
580
|
files: settled ? read.files?.stamp ?? null : null,
|
|
573
581
|
refs,
|
|
574
|
-
git: summary
|
|
582
|
+
git: summary,
|
|
583
|
+
...merge?.deferred && head && read.target ? { pendingMerge: {
|
|
584
|
+
head,
|
|
585
|
+
target: read.target
|
|
586
|
+
} } : {}
|
|
575
587
|
});
|
|
576
588
|
summaries.set(read.path, summary);
|
|
577
589
|
}
|
|
@@ -778,31 +790,11 @@ function physicalDeviceLine(device, now) {
|
|
|
778
790
|
return `${device.platform}${slot}: ${name} (physical${model}) ${device.connection} -- leased until ${clockTime(device.lease.expiresAt)} (${remaining} left)`;
|
|
779
791
|
}
|
|
780
792
|
//#endregion
|
|
781
|
-
//#region src/
|
|
782
|
-
const WATCH_GIT_MAX_AGE_MS = 6e4;
|
|
793
|
+
//#region src/status-read.ts
|
|
783
794
|
function iosStatusName(ios) {
|
|
784
795
|
const host = ios.host;
|
|
785
796
|
return host && !ios.udid ? `${host.device?.name ?? "iOS simulator"} (${host.device ? `iOS ${host.device.runtime.replace(/^iOS /, "")}` : "runtime pending"}) on ${host.machine}${host.selected === "auto" && host.reason ? ` (auto: ${host.reason})` : ""}` : ios.name ?? ios.udid;
|
|
786
797
|
}
|
|
787
|
-
function iosStatusLines(record, slotLabel) {
|
|
788
|
-
const out = [];
|
|
789
|
-
const host = record?.udid ? record.host : void 0;
|
|
790
|
-
const iosDevices = [record, ...host ? [{
|
|
791
|
-
host,
|
|
792
|
-
name: host.device?.name ?? null,
|
|
793
|
-
udid: "",
|
|
794
|
-
owned: false,
|
|
795
|
-
state: host.state ?? "unverified"
|
|
796
|
-
}] : []];
|
|
797
|
-
for (const ios of iosDevices) {
|
|
798
|
-
if (!ios) continue;
|
|
799
|
-
const booted = ios.state === "Booted" ? chalk.green("booted") : chalk.dim(ios.state.toLowerCase());
|
|
800
|
-
const owned = ios.owned ? chalk.dim(" (owned)") : "";
|
|
801
|
-
out.push(` ios${slotLabel}: ${chalk.cyan(iosStatusName(ios))} ${booted}${owned}${activitySuffix(ios.activity)}${appSuffix(ios.app)}${idleShutdownSuffix(ios.idleShutdown)}`);
|
|
802
|
-
if (!ios.udid && ios.host?.agent.driver === "agent-device") out.push(chalk.dim(` agent: ${ios.host.agent.command}`));
|
|
803
|
-
}
|
|
804
|
-
return out;
|
|
805
|
-
}
|
|
806
798
|
function applyHostedAndroidStates(state, saved, factsBySlot) {
|
|
807
799
|
for (const [slot, record] of Object.entries(hostedAndroidRecords(saved))) if (!parseHostedAndroidPlacement(record)) state.warnings.push(unreadableHostedAndroid(slot));
|
|
808
800
|
for (const [slot, facts] of Object.entries(factsBySlot)) {
|
|
@@ -828,23 +820,6 @@ function applyHostedAndroidStates(state, saved, factsBySlot) {
|
|
|
828
820
|
state.live ||= facts.android.state === "ready";
|
|
829
821
|
}
|
|
830
822
|
}
|
|
831
|
-
function androidStatusLines(record, slotLabel) {
|
|
832
|
-
const out = [];
|
|
833
|
-
if (record?.host && !record.serial) {
|
|
834
|
-
const host = record.host;
|
|
835
|
-
out.push(` android${slotLabel}: ${chalk.cyan(`${host.device?.name ?? "Android emulator"} on ${host.machine}${host.selected === "auto" && host.reason ? ` (auto: ${host.reason})` : ""}`)} ${host.state ?? "unverified"}`);
|
|
836
|
-
} else if (record) {
|
|
837
|
-
const kind = record.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
|
|
838
|
-
const observed = record.state ? ` ${record.state}${record.serial ? ` (${record.serial})` : ""}` : "";
|
|
839
|
-
out.push(` android${slotLabel}: ${chalk.cyan(record.name)} ${kind}${observed}${record.owned ? chalk.dim(" (owned)") : ""}${activitySuffix(record.activity)}${appSuffix(record.app)}${idleShutdownSuffix(record.idleShutdown)}`);
|
|
840
|
-
if (record.host) {
|
|
841
|
-
const host = record.host;
|
|
842
|
-
out.push(` android${slotLabel}: ${chalk.cyan(`${host.device?.name ?? "Android emulator"} on ${host.machine}${host.selected === "auto" && host.reason ? ` (auto: ${host.reason})` : ""}`)} ${host.state ?? "unverified"}`);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
if (record?.host?.agent.driver === "agent-device") out.push(chalk.dim(` agent: ${record.host.agent.command}`));
|
|
846
|
-
return out;
|
|
847
|
-
}
|
|
848
823
|
function doctorRunTimes(proj) {
|
|
849
824
|
const runs = {};
|
|
850
825
|
for (const platform of ["ios", "android"]) {
|
|
@@ -853,48 +828,55 @@ function doctorRunTimes(proj) {
|
|
|
853
828
|
}
|
|
854
829
|
return Object.keys(runs).length ? runs : void 0;
|
|
855
830
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
831
|
+
/**
|
|
832
|
+
* Probes that read everything when asked. `simctlListing`, when given, answers `simulators` without running simctl,
|
|
833
|
+
* `gitMaxAgeMs` reuses git summaries read that recently, and `archives` answers `archives` without reading them.
|
|
834
|
+
*/
|
|
835
|
+
function liveProbes({ simctlListing = null, gitMaxAgeMs = 0, archives } = {}) {
|
|
836
|
+
return {
|
|
837
|
+
simulators: () => simctlListing === null ? listAllIosSimsAsync() : Promise.resolve().then(() => parseSimctlList(simctlListing)),
|
|
838
|
+
metro: readMetroFacts,
|
|
839
|
+
hostedIos: readHostedIosStatus,
|
|
840
|
+
hostedAndroid: readHostedAndroidStatus,
|
|
841
|
+
hostedMacos: readHostedMacosStatus,
|
|
842
|
+
git: (worktrees, skip) => readWorktreeGit(worktrees, {
|
|
843
|
+
maxAgeMs: gitMaxAgeMs,
|
|
844
|
+
skip
|
|
845
|
+
}),
|
|
846
|
+
androidRuntime: androidRuntimeReader(),
|
|
847
|
+
physicalDevice: physicalDeviceReader(),
|
|
848
|
+
deviceTables: createDeviceProcessTables,
|
|
849
|
+
metroReverses: (serial) => getExecutor().runFileQuiet("adb", [
|
|
850
|
+
"-s",
|
|
851
|
+
serial,
|
|
852
|
+
"reverse",
|
|
853
|
+
"--list"
|
|
854
|
+
], { timeoutMs: 5e3 }),
|
|
855
|
+
footprints: readFootprints,
|
|
856
|
+
archives: () => archives ?? readArchives()
|
|
857
|
+
};
|
|
865
858
|
}
|
|
866
|
-
|
|
867
|
-
|
|
859
|
+
/**
|
|
860
|
+
* Reads the status of every environment. With `git: 'all'` it reads the git summary of every worktree before
|
|
861
|
+
* composing; with `'live'` only those of live environments, after composing; with `'none'` no git summary.
|
|
862
|
+
*/
|
|
863
|
+
function readStatus({ probes = liveProbes(), git = "live", cwd = process.cwd() } = {}) {
|
|
864
|
+
return withStateReadCache(() => readStatusFacts(probes, git, cwd));
|
|
868
865
|
}
|
|
869
|
-
async function readStatusFacts(
|
|
866
|
+
async function readStatusFacts(probes, gitScope, cwd) {
|
|
870
867
|
const cfg = loadConfig$1();
|
|
871
868
|
const projects = Object.entries(cfg?.projects || {});
|
|
872
|
-
const iosReads = projects.map(([path]) =>
|
|
873
|
-
const androidReads = projects.map(([path]) =>
|
|
874
|
-
const macosReads = projects.map(([path]) =>
|
|
875
|
-
const cwdRoot = findServerWorkspace(
|
|
876
|
-
const worktrees = linkedWorktrees([
|
|
869
|
+
const iosReads = projects.map(([path]) => probes.hostedIos(hostedIosPlacements(readWorkspaceState$1(path))));
|
|
870
|
+
const androidReads = projects.map(([path]) => probes.hostedAndroid(hostedAndroidPlacements(readWorkspaceState$1(path))));
|
|
871
|
+
const macosReads = projects.map(([path]) => probes.hostedMacos(readMacosRecord(path)));
|
|
872
|
+
const cwdRoot = findServerWorkspace(cwd)?.root ?? null;
|
|
873
|
+
const { worktrees, commonDirs } = linkedWorktrees([cwd, ...projects.map(([path]) => path)]);
|
|
877
874
|
const orphanWorktrees = unprovisionedWorktrees(worktrees, projects.map(([p]) => p));
|
|
878
|
-
const simsRead =
|
|
875
|
+
const simsRead = probes.simulators();
|
|
879
876
|
simsRead.catch(() => {});
|
|
880
|
-
const
|
|
881
|
-
const processes = Promise.all(projects.map(async ([path, proj]) => {
|
|
882
|
-
const metro = proj.metroPort ? await resolveOnPort(proj.metroPort, path, ports) : null;
|
|
883
|
-
return {
|
|
884
|
-
metro,
|
|
885
|
-
supervisor: await supervisorFacts(path, proj, metro, ports)
|
|
886
|
-
};
|
|
887
|
-
}));
|
|
877
|
+
const processes = probes.metro(projects);
|
|
888
878
|
processes.catch(() => {});
|
|
889
|
-
const
|
|
890
|
-
const gitRead = watching ? readGitInto(worktrees, orphanWorktrees, gitMaxAgeMs) : null;
|
|
891
|
-
const androidRuntimeOf = androidRuntimeReader();
|
|
892
|
-
const devices = projects.map(([, proj]) => ({
|
|
893
|
-
androidRuntimes: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? androidRuntimeOf(platforms.android.avdName) : null])),
|
|
894
|
-
androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? androidRuntimeOf(proj.platforms.android.avdName) : null,
|
|
895
|
-
androidDeviceProfiles: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? ownedAvdDeviceProfile(platforms.android.avdName) : null])),
|
|
896
|
-
androidDeviceProfile: proj.platforms?.android?.owned && proj.platforms.android.avdName ? ownedAvdDeviceProfile(proj.platforms.android.avdName) : null
|
|
897
|
-
}));
|
|
879
|
+
const gitRead = gitScope === "all" ? readGitInto(probes, worktrees, orphanWorktrees) : null;
|
|
898
880
|
const logs = projects.map(([path]) => logFacts(path));
|
|
899
881
|
const simsByUdid = {};
|
|
900
882
|
let simsAvailable = true;
|
|
@@ -906,6 +888,12 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
|
|
|
906
888
|
simctlError = String(e?.message || e).split("\n")[0] ?? "";
|
|
907
889
|
}
|
|
908
890
|
const running = await processes;
|
|
891
|
+
const devices = projects.map(([, proj]) => ({
|
|
892
|
+
androidRuntimes: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? probes.androidRuntime(platforms.android.avdName) : null])),
|
|
893
|
+
androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? probes.androidRuntime(proj.platforms.android.avdName) : null,
|
|
894
|
+
androidDeviceProfiles: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? ownedAvdDeviceProfile(platforms.android.avdName) : null])),
|
|
895
|
+
androidDeviceProfile: proj.platforms?.android?.owned && proj.platforms.android.avdName ? ownedAvdDeviceProfile(proj.platforms.android.avdName) : null
|
|
896
|
+
}));
|
|
909
897
|
await gitRead;
|
|
910
898
|
const history = readStats$1().record?.history;
|
|
911
899
|
const states = [];
|
|
@@ -919,7 +907,6 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
|
|
|
919
907
|
now: leaseNow
|
|
920
908
|
});
|
|
921
909
|
const roots = [];
|
|
922
|
-
const readPhysicalDevice = physicalDeviceReader();
|
|
923
910
|
const simulatorUdids = new Set([...Object.keys(simsByUdid), ...projects.flatMap(([, proj]) => projectDeviceSlots(proj).flatMap(({ platforms }) => platforms.ios?.deviceUdid ?? []))].map((udid) => udid.toUpperCase()));
|
|
924
911
|
for (const [i, [path, proj]] of projects.entries()) {
|
|
925
912
|
const { metro, supervisor } = running[i];
|
|
@@ -1024,20 +1011,20 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
|
|
|
1024
1011
|
root: path,
|
|
1025
1012
|
now: leaseNow,
|
|
1026
1013
|
simulatorUdids,
|
|
1027
|
-
read:
|
|
1014
|
+
read: (platform, id) => probes.physicalDevice(platform, id)
|
|
1028
1015
|
});
|
|
1029
1016
|
if (state && physicalDevices.length) state.physicalDevices = physicalDevices;
|
|
1030
1017
|
labelOnlyRoots.push(Boolean(proj.worktreeRoot && !proj.bundleId && !state?.metro && !state?.ios && !state?.android && !state?.web && !state?.macos));
|
|
1031
1018
|
}
|
|
1032
|
-
if (
|
|
1019
|
+
if (gitScope === "live") await readGitInto(probes, worktrees, orphanWorktrees, new Set(states.flatMap((state) => state.live && state.worktree ? [state.worktree.path] : [])));
|
|
1033
1020
|
applyStatusMeasures(states, worktrees);
|
|
1034
1021
|
readLogDerivedFacts(states);
|
|
1035
|
-
const tables =
|
|
1022
|
+
const tables = probes.deviceTables();
|
|
1036
1023
|
readDeviceProcesses(states, tables, {
|
|
1037
1024
|
projects,
|
|
1038
1025
|
launchesByState
|
|
1039
1026
|
});
|
|
1040
|
-
readMetroReverses(states, launchesByState);
|
|
1027
|
+
readMetroReverses(states, launchesByState, probes);
|
|
1041
1028
|
const sims = Object.values(simsByUdid);
|
|
1042
1029
|
const simNames = Object.fromEntries(sims.map((sim) => [sim.udid.toUpperCase(), sim.name]));
|
|
1043
1030
|
const machine = await readMachineUsage({
|
|
@@ -1045,9 +1032,10 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
|
|
|
1045
1032
|
roots,
|
|
1046
1033
|
simNames,
|
|
1047
1034
|
tables,
|
|
1048
|
-
busy: sims.some((sim) => sim.state === "Booted")
|
|
1035
|
+
busy: sims.some((sim) => sim.state === "Booted"),
|
|
1036
|
+
probes
|
|
1049
1037
|
});
|
|
1050
|
-
const archives =
|
|
1038
|
+
const archives = probes.archives();
|
|
1051
1039
|
const maxCount = machineNumber("archive.maxCount", cfg, process.env);
|
|
1052
1040
|
return {
|
|
1053
1041
|
archived: linkReplacedArchives(archives.slice(0, maxCount.value ?? 200), states.map((state) => state.path)),
|
|
@@ -1065,7 +1053,9 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
|
|
|
1065
1053
|
tables,
|
|
1066
1054
|
machine,
|
|
1067
1055
|
roots,
|
|
1068
|
-
simNames
|
|
1056
|
+
simNames,
|
|
1057
|
+
probes,
|
|
1058
|
+
gitCommonDirs: commonDirs
|
|
1069
1059
|
};
|
|
1070
1060
|
}
|
|
1071
1061
|
/** Sets the facts status derives from workspace logs, the running build's record and its detail file. */
|
|
@@ -1120,11 +1110,6 @@ function readLogDerivedFacts(states) {
|
|
|
1120
1110
|
}
|
|
1121
1111
|
}
|
|
1122
1112
|
}
|
|
1123
|
-
function phaseMarker({ phase, live, warmStep }) {
|
|
1124
|
-
if (phase === "warming") return chalk.cyan(` [warming: ${warmStep}]`);
|
|
1125
|
-
if (phase === "ready") return chalk.green(" [ready]");
|
|
1126
|
-
return live ? "" : chalk.dim(" [idle]");
|
|
1127
|
-
}
|
|
1128
1113
|
function browserPids(web) {
|
|
1129
1114
|
if (!web) return [];
|
|
1130
1115
|
const chrome = web.record.chromeProcess?.pid;
|
|
@@ -1136,10 +1121,10 @@ function browserPids(web) {
|
|
|
1136
1121
|
* `memoryMb` from them. Reads both only when a simulator is booted, a workspace is live or a build runs, so an idle
|
|
1137
1122
|
* machine runs no `ps` and keeps the estimate.
|
|
1138
1123
|
*/
|
|
1139
|
-
async function readMachineUsage({ states, roots, simNames, tables, busy }) {
|
|
1124
|
+
async function readMachineUsage({ states, roots, simNames, tables, busy, probes }) {
|
|
1140
1125
|
const processes = busy || states.some((state) => state.live || state.build?.state === "running") ? tables.host() : null;
|
|
1141
1126
|
if (!processes) return null;
|
|
1142
|
-
const footprints = await
|
|
1127
|
+
const footprints = await probes.footprints();
|
|
1143
1128
|
const machine = attributeMachineUsage({
|
|
1144
1129
|
processes,
|
|
1145
1130
|
footprints,
|
|
@@ -1151,338 +1136,112 @@ async function readMachineUsage({ states, roots, simNames, tables, busy }) {
|
|
|
1151
1136
|
return machine;
|
|
1152
1137
|
}
|
|
1153
1138
|
/**
|
|
1154
|
-
* Rereads
|
|
1155
|
-
*
|
|
1139
|
+
* Rereads the log-derived facts and the cached measures. With `tables` it also rereads the process tables and the
|
|
1140
|
+
* device activity they show; with `machine` as well, and when the snapshot measured machine usage, the host process
|
|
1141
|
+
* table and machine usage. It reuses every other subprocess fact of the full read.
|
|
1156
1142
|
*/
|
|
1157
|
-
async function refreshLightFacts(snapshot, machine) {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1143
|
+
async function refreshLightFacts(snapshot, { tables, machine }) {
|
|
1144
|
+
if (tables) {
|
|
1145
|
+
const fresh = snapshot.probes.deviceTables();
|
|
1146
|
+
snapshot.tables = {
|
|
1147
|
+
host: machine && snapshot.machine ? fresh.host : snapshot.tables.host,
|
|
1148
|
+
android: snapshot.tables.android,
|
|
1149
|
+
tcpConnections: fresh.tcpConnections,
|
|
1150
|
+
clients: fresh.host
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1165
1153
|
withStateReadCache(() => {
|
|
1166
1154
|
for (const state of snapshot.states) state.logs = logFacts(state.path);
|
|
1167
1155
|
applyStatusMeasures(snapshot.states, snapshot.worktrees);
|
|
1168
1156
|
readLogDerivedFacts(snapshot.states);
|
|
1169
|
-
readDeviceProcesses(snapshot.states, snapshot.tables, null);
|
|
1157
|
+
if (tables) readDeviceProcesses(snapshot.states, snapshot.tables, null);
|
|
1170
1158
|
});
|
|
1171
1159
|
if (machine && snapshot.machine) snapshot.machine = await readMachineUsage({
|
|
1172
1160
|
...snapshot,
|
|
1173
1161
|
busy: true
|
|
1174
1162
|
});
|
|
1175
1163
|
}
|
|
1176
|
-
function
|
|
1177
|
-
const
|
|
1178
|
-
const
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
});
|
|
1191
|
-
const maintenance = maintenanceStatus();
|
|
1192
|
-
if (json) {
|
|
1193
|
-
const payload = {
|
|
1194
|
-
environments: states.map((state, i) => withDerivedFacts(labelOnlyRoots[i] ? {
|
|
1195
|
-
...state,
|
|
1196
|
-
labelOnly: true
|
|
1197
|
-
} : state)),
|
|
1198
|
-
archived,
|
|
1199
|
-
archivedUsage: usage,
|
|
1200
|
-
capacity: cap,
|
|
1201
|
-
deviceLeases: leases,
|
|
1202
|
-
unprovisionedWorktrees: orphanWorktrees.map(withGitChip),
|
|
1203
|
-
simctlAvailable: simsAvailable,
|
|
1204
|
-
machine,
|
|
1205
|
-
maintenance
|
|
1164
|
+
async function readGitInto(probes, worktrees, orphans, only) {
|
|
1165
|
+
const home = homedir();
|
|
1166
|
+
const byPath = await probes.git(worktrees, (w) => only !== void 0 && !only.has(w.path) || process.platform === "darwin" && orphans.includes(w) && inPrivacyProtectedFolder(w.path, home));
|
|
1167
|
+
for (const worktree of worktrees) worktree.git = byPath.get(worktree.path) ?? null;
|
|
1168
|
+
}
|
|
1169
|
+
function readDeviceProcesses(states, tables, apps) {
|
|
1170
|
+
const readActivity = createActivityReader({ tables });
|
|
1171
|
+
const readAppProcess = createAppProcessReader(tables);
|
|
1172
|
+
for (const [i, state] of states.entries()) {
|
|
1173
|
+
const appIdOn = (platform, slot, deviceId) => {
|
|
1174
|
+
if (!apps) return void 0;
|
|
1175
|
+
const project = apps.projects[i][1];
|
|
1176
|
+
const launch = apps.launchesByState[i][deviceSlotKey(platform, slot)];
|
|
1177
|
+
return launch?.deviceId === deviceId ? launch.appId : platform === "ios" ? project.bundleId : project.androidPackage;
|
|
1206
1178
|
};
|
|
1207
|
-
|
|
1208
|
-
return out;
|
|
1209
|
-
}
|
|
1210
|
-
out.push(...maintenanceLines(maintenance).map((line) => chalk.dim(line)));
|
|
1211
|
-
if (usage.count) out.push(`Archived: ${plural(usage.count, "workspace")}, ${formatBytes(usage.bytes)}`);
|
|
1212
|
-
if (projects.length === 0 && orphanWorktrees.length === 0) {
|
|
1213
|
-
out.push(chalk.dim("No projects registered."));
|
|
1214
|
-
for (const pool of pools) {
|
|
1215
|
-
if (pool.error) out.push(chalk.yellow(`${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
1216
|
-
if (pool.line) out.push(chalk.dim(pool.line));
|
|
1217
|
-
}
|
|
1218
|
-
for (const line of deviceLeaseLines(leases, leaseNow)) out.push(line);
|
|
1219
|
-
return out;
|
|
1220
|
-
}
|
|
1221
|
-
if (!simsAvailable) out.push(chalk.yellow(`simctl could not be read (${simctlError}), so no iOS sim below could be checked.`));
|
|
1222
|
-
for (const [i, [path, proj]] of projects.entries()) {
|
|
1223
|
-
const state = states[i];
|
|
1224
|
-
if (!state) continue;
|
|
1225
|
-
const shortcut = projectShortcut(path, proj);
|
|
1226
|
-
const marker = path === cwdRoot ? chalk.bold.cyan(`* ${shortcut}`) : shortcut;
|
|
1227
|
-
const idle = phaseMarker(state);
|
|
1228
|
-
out.push(`\n${marker}${idle} ${chalk.dim(`(${path})`)}`);
|
|
1229
|
-
out.push(labelOnlyRoots[i] ? chalk.dim(" worktree root (holds the label; the app registers its own entry)") : chalk.dim(` app: ${proj.bundleId ?? "?"} (${proj.isExpo ?? detectIsExpo(path) ? "expo" : "bare"})`));
|
|
1230
|
-
if (state.metro) {
|
|
1231
|
-
const label = state.metro.running ? chalk.green(`running (pid ${state.metro.pid})`) : state.metro.idleStop ? chalk.dim(`stopped (idle) after ${state.metro.idleStop.idleMinutes}m; \`stim start\`, \`ios\` or \`android\` restarts it`) : state.metro.lastStop ? chalk.dim(`not running${state.metro.lastStop.reason === "vanished" ? "" : ` since ${state.metro.lastStop.at}`}; ${describeMetroLastStop(state.metro.lastStop)}`) : chalk.dim("not running");
|
|
1232
|
-
out.push(` metro: port ${state.metro.port} ${label}`);
|
|
1233
|
-
if (state.metro.tunnel) {
|
|
1234
|
-
const { provider, url } = state.metro.tunnel;
|
|
1235
|
-
out.push(` tunnel: ${provider}${provider === "tailscale" ? " (tailnet-only)" : ""} ${url}`);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
if (state.supervisor) {
|
|
1239
|
-
const health = state.supervisor.healthy ? chalk.green("healthy") : chalk.yellow("not answering");
|
|
1240
|
-
const mode = state.supervisor.mode ? chalk.dim(` (${state.supervisor.mode})`) : "";
|
|
1241
|
-
out.push(` supervisor: pid ${state.supervisor.pid}${mode} ${health}`);
|
|
1242
|
-
}
|
|
1243
|
-
if (state.build) {
|
|
1244
|
-
const line = ` ${buildStatusLine(state.build, Date.now())}`;
|
|
1245
|
-
out.push(state.build.state === "running" ? line : chalk.yellow(line));
|
|
1246
|
-
}
|
|
1247
|
-
out.push(...lastBuildsLines(state.lastBuilds));
|
|
1248
|
-
if (state.worktree?.git) out.push(chalk.dim(` git: ${gitSummaryText(state.worktree.git)}`));
|
|
1249
|
-
for (const agent of state.agents ?? []) out.push(chalk.dim(` agent: ${agentLine(agent)}`));
|
|
1250
|
-
if (state.logs) {
|
|
1251
|
-
const n = state.logs.errorsSinceMarker;
|
|
1252
|
-
const errs = n > 0 ? chalk.yellow(` (${n} error${n === 1 ? "" : "s"} since the last marker)`) : "";
|
|
1253
|
-
out.push(chalk.dim(` logs: ${state.logs.dir}`) + errs);
|
|
1254
|
-
}
|
|
1255
|
-
for (const deviceState of [{
|
|
1179
|
+
for (const device of [{
|
|
1256
1180
|
slot: "default",
|
|
1257
1181
|
ios: state.ios,
|
|
1258
1182
|
android: state.android
|
|
1259
1183
|
}, ...state.slots ?? []]) {
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1184
|
+
const base = {
|
|
1185
|
+
slot: device.slot,
|
|
1186
|
+
workspace: state.path
|
|
1187
|
+
};
|
|
1188
|
+
if (device.ios?.state === "Booted") {
|
|
1189
|
+
const id = device.ios.udid;
|
|
1190
|
+
device.ios.activity = statusActivity(readActivity({
|
|
1191
|
+
...base,
|
|
1192
|
+
platform: "ios",
|
|
1193
|
+
id
|
|
1194
|
+
}));
|
|
1195
|
+
const appId = device.ios.owned ? appIdOn("ios", device.slot, id) : void 0;
|
|
1196
|
+
if (appId) device.ios.app = readAppProcess({
|
|
1197
|
+
platform: "ios",
|
|
1198
|
+
id,
|
|
1199
|
+
appId
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
if (device.android && !device.android.physical && device.android.serial) {
|
|
1203
|
+
const id = device.android.serial;
|
|
1204
|
+
device.android.activity = statusActivity(readActivity({
|
|
1205
|
+
...base,
|
|
1206
|
+
platform: "android",
|
|
1207
|
+
id
|
|
1208
|
+
}));
|
|
1209
|
+
const appId = device.android.owned ? appIdOn("android", device.slot, id) : void 0;
|
|
1210
|
+
if (appId) device.android.app = readAppProcess({
|
|
1211
|
+
platform: "android",
|
|
1212
|
+
id,
|
|
1213
|
+
appId
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1271
1216
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1217
|
+
const web = state.web;
|
|
1218
|
+
const port = web?.cdpEndpoint ? Number(new URL(web.cdpEndpoint).port) : null;
|
|
1219
|
+
if (web?.running && port) {
|
|
1220
|
+
web.page = readWebPage(state.path);
|
|
1221
|
+
const ownPids = [web.pid, web.supervisorPid].filter((pid) => pid !== null);
|
|
1222
|
+
web.activity = statusActivity(readWebActivity({
|
|
1223
|
+
port,
|
|
1224
|
+
ownPids,
|
|
1225
|
+
workspace: state.path
|
|
1226
|
+
}, tables));
|
|
1277
1227
|
}
|
|
1278
|
-
for (const device of state.physicalDevices ?? []) out.push(` ${physicalDeviceLine(device, leaseNow)}`);
|
|
1279
|
-
for (const remote of state.remoteDevices ?? []) out.push(` ${remoteDeviceLine(remote)}`);
|
|
1280
|
-
for (const w of state.warnings) out.push(chalk.yellow(` ! ${w}`));
|
|
1281
|
-
for (const note of state.issues.filter((issue) => issue.severity === "info")) out.push(chalk.dim(` - ${note.message}`));
|
|
1282
|
-
}
|
|
1283
|
-
for (const pool of pools) {
|
|
1284
|
-
if (pool.error) out.push(chalk.yellow(`\n${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
1285
|
-
if (pool.line) out.push(chalk.dim(`\n${pool.line}`));
|
|
1286
|
-
}
|
|
1287
|
-
const leaseLines = deviceLeaseLines(leases, leaseNow);
|
|
1288
|
-
if (leaseLines.length) {
|
|
1289
|
-
out.push("");
|
|
1290
|
-
for (const line of leaseLines) out.push(line);
|
|
1291
1228
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1229
|
+
}
|
|
1230
|
+
function readMetroReverses(states, launchesByState, probes) {
|
|
1231
|
+
for (const [i, state] of states.entries()) for (const target of metroReverseTargets(state, launchesByState[i])) {
|
|
1232
|
+
const listing = probes.metroReverses(target.serial);
|
|
1233
|
+
if (listing !== null && !hasMetroReverse(listing, target.metroPort)) addReverseMissingIssue(state, target);
|
|
1295
1234
|
}
|
|
1296
|
-
out.push(chalk.dim(machine?.memorySource === "footprint" ? `\n${cap.liveCount} active environment(s) use ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)}.` : `\n${cap.liveCount} active environment(s), roughly ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)} committed.`));
|
|
1297
|
-
const volumes = readVolumes(cwdRoot || process.cwd());
|
|
1298
|
-
const line = diskLine(volumes);
|
|
1299
|
-
if (line) {
|
|
1300
|
-
const tight = tightVolumes(volumes);
|
|
1301
|
-
if (tight.length) {
|
|
1302
|
-
const which = tight.map((v) => v.volume).join(" and ");
|
|
1303
|
-
out.push(chalk.yellow(`${line} A single iOS build can exhaust ${which} -- run \`stim gc\` before starting another environment.`));
|
|
1304
|
-
} else out.push(chalk.dim(line));
|
|
1305
|
-
}
|
|
1306
|
-
if (cap.overCapacity) out.push(chalk.yellow("Over comfortable capacity. A machine that swaps is slower than one working in sequence -- release one before starting another."));
|
|
1307
|
-
return out;
|
|
1308
|
-
}
|
|
1309
|
-
async function watchStatus(json) {
|
|
1310
|
-
let last = null;
|
|
1311
|
-
let lastPayload = null;
|
|
1312
|
-
let archiveStamp = null;
|
|
1313
|
-
let archives;
|
|
1314
|
-
let snapshot = null;
|
|
1315
|
-
let sources = null;
|
|
1316
|
-
const measurer = createStatusMeasurer({ updated: () => scheduler.trigger("light") });
|
|
1317
|
-
const scheduler = createRefreshScheduler({
|
|
1318
|
-
debounceMs: 250,
|
|
1319
|
-
lightIntervalMs: WATCH_LIGHT_INTERVAL_MS,
|
|
1320
|
-
run: async (kind) => {
|
|
1321
|
-
triggerMaintenance("status-watch");
|
|
1322
|
-
let text;
|
|
1323
|
-
let payload = null;
|
|
1324
|
-
try {
|
|
1325
|
-
if (kind === "light" && snapshot) await refreshLightFacts(snapshot, json);
|
|
1326
|
-
else {
|
|
1327
|
-
let stamp = null;
|
|
1328
|
-
try {
|
|
1329
|
-
stamp = statSync$1(archiveRoot()).mtimeMs;
|
|
1330
|
-
} catch {}
|
|
1331
|
-
if (archives === void 0 || stamp !== archiveStamp) {
|
|
1332
|
-
archives = readArchives();
|
|
1333
|
-
archiveStamp = stamp;
|
|
1334
|
-
}
|
|
1335
|
-
snapshot = await readStatus(WATCH_GIT_MAX_AGE_MS, sources?.simulatorListing(), archives);
|
|
1336
|
-
}
|
|
1337
|
-
measurer.schedule(snapshot.states, snapshot.worktrees);
|
|
1338
|
-
text = renderStatus(snapshot, json, (full) => payload = watchPayload(lastPayload, full)).join("\n");
|
|
1339
|
-
} catch (error) {
|
|
1340
|
-
console.error(chalk.red(String(error?.message || error)));
|
|
1341
|
-
return;
|
|
1342
|
-
} finally {
|
|
1343
|
-
sources?.reconcile();
|
|
1344
|
-
}
|
|
1345
|
-
if (text === last) return;
|
|
1346
|
-
last = text;
|
|
1347
|
-
lastPayload = payload;
|
|
1348
|
-
process.stdout.write(`${!json && process.stdout.isTTY ? "\x1B[2J\x1B[H" : ""}${text}\n`);
|
|
1349
|
-
}
|
|
1350
|
-
});
|
|
1351
|
-
const fallback = setInterval(() => scheduler.trigger("full"), WATCH_FALLBACK_MS);
|
|
1352
|
-
const machine = setInterval(() => json && snapshot?.machine && scheduler.trigger("light"), WATCH_LIGHT_INTERVAL_MS);
|
|
1353
|
-
const finish = () => {
|
|
1354
|
-
clearInterval(fallback);
|
|
1355
|
-
clearInterval(machine);
|
|
1356
|
-
stopReader();
|
|
1357
|
-
scheduler.stop();
|
|
1358
|
-
sources?.stop();
|
|
1359
|
-
process.exit(0);
|
|
1360
|
-
};
|
|
1361
|
-
const stopReader = watchStdoutReader(finish);
|
|
1362
|
-
process.on("SIGINT", finish);
|
|
1363
|
-
process.on("SIGTERM", finish);
|
|
1364
|
-
sources = watchStatusSources({
|
|
1365
|
-
home: getConfigDir(),
|
|
1366
|
-
onChange: (kind) => scheduler.trigger(kind)
|
|
1367
|
-
});
|
|
1368
|
-
scheduler.trigger("full", 0);
|
|
1369
|
-
await new Promise(() => {});
|
|
1370
|
-
}
|
|
1371
|
-
async function readGitInto(worktrees, orphans, maxAgeMs, only) {
|
|
1372
|
-
const home = homedir();
|
|
1373
|
-
const byPath = await readWorktreeGit(worktrees, {
|
|
1374
|
-
maxAgeMs,
|
|
1375
|
-
skip: (w) => only !== void 0 && !only.has(w.path) || process.platform === "darwin" && orphans.includes(w) && inPrivacyProtectedFolder(w.path, home)
|
|
1376
|
-
});
|
|
1377
|
-
for (const worktree of worktrees) worktree.git = byPath.get(worktree.path) ?? null;
|
|
1378
|
-
}
|
|
1379
|
-
function agentLine({ tool, title, sessionId, lastActiveAt }) {
|
|
1380
|
-
const at = lastActiveAt ? `, active ${lastActiveAt}` : "";
|
|
1381
|
-
return `${tool === "codex" ? "Codex" : "Claude Code"} ${title ? `"${title}"` : sessionId}${at}`;
|
|
1382
|
-
}
|
|
1383
|
-
function orphanWorktreeLine(w) {
|
|
1384
|
-
return `${w.path}${w.branch ? ` [${w.branch}]` : ""}${w.git ? ` -- ${gitSummaryText(w.git)}` : ""}`;
|
|
1385
|
-
}
|
|
1386
|
-
function lastBuildsLines(reports) {
|
|
1387
|
-
const texts = Object.values(reports ?? {}).map(lastBuildText);
|
|
1388
|
-
return texts.length ? [chalk.dim(` last build: ${texts.join(", ")}`)] : [];
|
|
1389
|
-
}
|
|
1390
|
-
function lastBuildText(report) {
|
|
1391
|
-
const source = report.cacheHit ? `${report.cacheHit} cache` : report.status === "ok" ? "compiled" : "no cache hit";
|
|
1392
|
-
const took = report.durationMs === null ? "" : ` in ${formatDuration(report.durationMs)}`;
|
|
1393
|
-
const placement = report.buildMachine === void 0 ? "" : `; build placement ${report.buildMachine}, built on ${report.builtOn ?? (report.cacheHit ? "none (cache)" : "none")}`;
|
|
1394
|
-
return `${report.platform} ${report.status === "ok" ? source : `failed (${report.errorCode ?? "error"}), ${source}`}${took}${placement}`;
|
|
1395
|
-
}
|
|
1396
|
-
function idleShutdownSuffix(record) {
|
|
1397
|
-
return record ? chalk.dim(` -- shut down after ${record.idleMinutes}m idle at ${record.at} (${record.reason === DEVICE_RECLAIM_REASON ? "reclaimed for a waiting run; devices.reclaimIdleMinutes" : "devices.idleShutdownMinutes"})`) : "";
|
|
1398
|
-
}
|
|
1399
|
-
function activitySuffix(activity) {
|
|
1400
|
-
const label = activityLabel(activity, Date.now());
|
|
1401
|
-
return label ? ` -- ${activity?.state === "driven" ? chalk.magenta(label) : chalk.dim(label)}` : "";
|
|
1402
|
-
}
|
|
1403
|
-
function readDeviceProcesses(states, tables, apps) {
|
|
1404
|
-
const readActivity = createActivityReader({ tables });
|
|
1405
|
-
const readAppProcess = createAppProcessReader(tables);
|
|
1406
|
-
for (const [i, state] of states.entries()) {
|
|
1407
|
-
const appIdOn = (platform, slot, deviceId) => {
|
|
1408
|
-
if (!apps) return void 0;
|
|
1409
|
-
const project = apps.projects[i][1];
|
|
1410
|
-
const launch = apps.launchesByState[i][deviceSlotKey(platform, slot)];
|
|
1411
|
-
return launch?.deviceId === deviceId ? launch.appId : platform === "ios" ? project.bundleId : project.androidPackage;
|
|
1412
|
-
};
|
|
1413
|
-
for (const device of [{
|
|
1414
|
-
slot: "default",
|
|
1415
|
-
ios: state.ios,
|
|
1416
|
-
android: state.android
|
|
1417
|
-
}, ...state.slots ?? []]) {
|
|
1418
|
-
const base = {
|
|
1419
|
-
slot: device.slot,
|
|
1420
|
-
workspace: state.path
|
|
1421
|
-
};
|
|
1422
|
-
if (device.ios?.state === "Booted") {
|
|
1423
|
-
const id = device.ios.udid;
|
|
1424
|
-
device.ios.activity = statusActivity(readActivity({
|
|
1425
|
-
...base,
|
|
1426
|
-
platform: "ios",
|
|
1427
|
-
id
|
|
1428
|
-
}));
|
|
1429
|
-
const appId = device.ios.owned ? appIdOn("ios", device.slot, id) : void 0;
|
|
1430
|
-
if (appId) device.ios.app = readAppProcess({
|
|
1431
|
-
platform: "ios",
|
|
1432
|
-
id,
|
|
1433
|
-
appId
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
if (device.android && !device.android.physical && device.android.serial) {
|
|
1437
|
-
const id = device.android.serial;
|
|
1438
|
-
device.android.activity = statusActivity(readActivity({
|
|
1439
|
-
...base,
|
|
1440
|
-
platform: "android",
|
|
1441
|
-
id
|
|
1442
|
-
}));
|
|
1443
|
-
const appId = device.android.owned ? appIdOn("android", device.slot, id) : void 0;
|
|
1444
|
-
if (appId) device.android.app = readAppProcess({
|
|
1445
|
-
platform: "android",
|
|
1446
|
-
id,
|
|
1447
|
-
appId
|
|
1448
|
-
});
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
const web = state.web;
|
|
1452
|
-
const port = web?.cdpEndpoint ? Number(new URL(web.cdpEndpoint).port) : null;
|
|
1453
|
-
if (web?.running && port) {
|
|
1454
|
-
web.page = readWebPage(state.path);
|
|
1455
|
-
const ownPids = [web.pid, web.supervisorPid].filter((pid) => pid !== null);
|
|
1456
|
-
web.activity = statusActivity(readWebActivity({
|
|
1457
|
-
port,
|
|
1458
|
-
ownPids,
|
|
1459
|
-
workspace: state.path
|
|
1460
|
-
}, tables));
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
function readMetroReverses(states, launchesByState) {
|
|
1465
|
-
for (const [i, state] of states.entries()) for (const target of metroReverseTargets(state, launchesByState[i])) {
|
|
1466
|
-
const listing = getExecutor().runFileQuiet("adb", [
|
|
1467
|
-
"-s",
|
|
1468
|
-
target.serial,
|
|
1469
|
-
"reverse",
|
|
1470
|
-
"--list"
|
|
1471
|
-
], { timeoutMs: 5e3 });
|
|
1472
|
-
if (listing !== null && !hasMetroReverse(listing, target.metroPort)) addReverseMissingIssue(state, target);
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
function appSuffix(app) {
|
|
1476
|
-
if (!app) return "";
|
|
1477
|
-
if (app.state === "running") return chalk.dim(` -- ${app.id} running`);
|
|
1478
|
-
if (app.state === "stopped") return ` -- ${chalk.yellow(`${app.id} not running`)}`;
|
|
1479
|
-
return chalk.dim(` -- ${app.id} process unknown`);
|
|
1480
1235
|
}
|
|
1481
1236
|
function linkedWorktrees(paths) {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1237
|
+
const commonDirs = [...new Set(paths.flatMap((path) => gitCommonDirOnDisk(path) ?? []))];
|
|
1238
|
+
return {
|
|
1239
|
+
worktrees: commonDirs.flatMap((common) => {
|
|
1240
|
+
const repository = basename$1(common) === ".git" ? dirname$1(common) : common;
|
|
1241
|
+
return linkedWorktreesOnDisk(common).map((entry) => Object.assign(entry, { repository }));
|
|
1242
|
+
}),
|
|
1243
|
+
commonDirs
|
|
1244
|
+
};
|
|
1486
1245
|
}
|
|
1487
1246
|
function workspaceBuilds(path, saved, history) {
|
|
1488
1247
|
const lastBuilds = readLastBuilds(saved);
|
|
@@ -1551,21 +1310,15 @@ function readAndroidRuntime(resolveSerial) {
|
|
|
1551
1310
|
};
|
|
1552
1311
|
}
|
|
1553
1312
|
}
|
|
1554
|
-
function
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
if (disk) volumes.push({
|
|
1564
|
-
volume,
|
|
1565
|
-
disk
|
|
1566
|
-
});
|
|
1567
|
-
}
|
|
1568
|
-
return volumes;
|
|
1313
|
+
async function readMetroFacts(projects) {
|
|
1314
|
+
const ports = await portLookup(projects.flatMap(([, proj]) => proj.metroPort ? [proj.metroPort] : []));
|
|
1315
|
+
return Promise.all(projects.map(async ([path, proj]) => {
|
|
1316
|
+
const metro = proj.metroPort ? await resolveOnPort(proj.metroPort, path, ports) : null;
|
|
1317
|
+
return {
|
|
1318
|
+
metro,
|
|
1319
|
+
supervisor: await supervisorFacts(path, proj, metro, ports)
|
|
1320
|
+
};
|
|
1321
|
+
}));
|
|
1569
1322
|
}
|
|
1570
1323
|
async function portLookup(metroPorts) {
|
|
1571
1324
|
const ports = [...new Set(metroPorts)];
|
|
@@ -1626,4 +1379,353 @@ function logFacts(path) {
|
|
|
1626
1379
|
}
|
|
1627
1380
|
}
|
|
1628
1381
|
//#endregion
|
|
1629
|
-
|
|
1382
|
+
//#region src/commands/status.ts
|
|
1383
|
+
function iosStatusLines(record, slotLabel) {
|
|
1384
|
+
const out = [];
|
|
1385
|
+
const host = record?.udid ? record.host : void 0;
|
|
1386
|
+
const iosDevices = [record, ...host ? [{
|
|
1387
|
+
host,
|
|
1388
|
+
name: host.device?.name ?? null,
|
|
1389
|
+
udid: "",
|
|
1390
|
+
owned: false,
|
|
1391
|
+
state: host.state ?? "unverified"
|
|
1392
|
+
}] : []];
|
|
1393
|
+
for (const ios of iosDevices) {
|
|
1394
|
+
if (!ios) continue;
|
|
1395
|
+
const booted = ios.state === "Booted" ? chalk.green("booted") : chalk.dim(ios.state.toLowerCase());
|
|
1396
|
+
const owned = ios.owned ? chalk.dim(" (owned)") : "";
|
|
1397
|
+
out.push(` ios${slotLabel}: ${chalk.cyan(iosStatusName(ios))} ${booted}${owned}${activitySuffix(ios.activity)}${appSuffix(ios.app)}${idleShutdownSuffix(ios.idleShutdown)}`);
|
|
1398
|
+
if (!ios.udid && ios.host && "command" in ios.host.agent) out.push(chalk.dim(` agent: ${ios.host.agent.command}`));
|
|
1399
|
+
}
|
|
1400
|
+
return out;
|
|
1401
|
+
}
|
|
1402
|
+
function androidStatusLines(record, slotLabel) {
|
|
1403
|
+
const out = [];
|
|
1404
|
+
if (record?.host && !record.serial) {
|
|
1405
|
+
const host = record.host;
|
|
1406
|
+
out.push(` android${slotLabel}: ${chalk.cyan(`${host.device?.name ?? "Android emulator"} on ${host.machine}${host.selected === "auto" && host.reason ? ` (auto: ${host.reason})` : ""}`)} ${host.state ?? "unverified"}`);
|
|
1407
|
+
} else if (record) {
|
|
1408
|
+
const kind = record.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
|
|
1409
|
+
const observed = record.state ? ` ${record.state}${record.serial ? ` (${record.serial})` : ""}` : "";
|
|
1410
|
+
out.push(` android${slotLabel}: ${chalk.cyan(record.name)} ${kind}${observed}${record.owned ? chalk.dim(" (owned)") : ""}${activitySuffix(record.activity)}${appSuffix(record.app)}${idleShutdownSuffix(record.idleShutdown)}`);
|
|
1411
|
+
if (record.host) {
|
|
1412
|
+
const host = record.host;
|
|
1413
|
+
out.push(` android${slotLabel}: ${chalk.cyan(`${host.device?.name ?? "Android emulator"} on ${host.machine}${host.selected === "auto" && host.reason ? ` (auto: ${host.reason})` : ""}`)} ${host.state ?? "unverified"}`);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
if (record?.host && "command" in record.host.agent) out.push(chalk.dim(` agent: ${record.host.agent.command}`));
|
|
1417
|
+
return out;
|
|
1418
|
+
}
|
|
1419
|
+
function formatGb(mb) {
|
|
1420
|
+
return `${(mb / 1024).toFixed(1)} GB`;
|
|
1421
|
+
}
|
|
1422
|
+
function phaseMarker({ phase, live, warmStep }) {
|
|
1423
|
+
if (phase === "warming") return chalk.cyan(` [warming: ${warmStep}]`);
|
|
1424
|
+
if (phase === "ready") return chalk.green(" [ready]");
|
|
1425
|
+
return live ? "" : chalk.dim(" [idle]");
|
|
1426
|
+
}
|
|
1427
|
+
const WATCH_GIT_MAX_AGE_MS = 6e4;
|
|
1428
|
+
function statusCommand(program) {
|
|
1429
|
+
program.command("status").description("Show every environment on this machine: devices, ports, what is actually running, and anything stuck.").option("--json", "print the state as JSON").option("--watch", "keep running and print the state again each time it changes").action(async (opts) => {
|
|
1430
|
+
if (opts.watch) return watchStatus(Boolean(opts.json));
|
|
1431
|
+
const json = Boolean(opts.json);
|
|
1432
|
+
for (const line of renderStatus(await readStatus(), json)) console.log(line);
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
function renderStatus({ archived, archivedUsage: usage, projects, states, labelOnlyRoots, leases, leaseNow, orphanWorktrees, simsAvailable, simctlError, cwdRoot, machine }, json, settle = (payload) => payload, cwd = process.cwd()) {
|
|
1436
|
+
const out = [];
|
|
1437
|
+
const totalMemoryMb = Math.round(totalmem() / 1048576);
|
|
1438
|
+
const cap = capacity(states, totalMemoryMb);
|
|
1439
|
+
const pools = ["ios", "android"].map((platform) => {
|
|
1440
|
+
const { max, error } = parkedMaxSetting(platform);
|
|
1441
|
+
return {
|
|
1442
|
+
error,
|
|
1443
|
+
line: poolLine({
|
|
1444
|
+
platform,
|
|
1445
|
+
parked: readParked(platform).length,
|
|
1446
|
+
max
|
|
1447
|
+
})
|
|
1448
|
+
};
|
|
1449
|
+
});
|
|
1450
|
+
const maintenance = maintenanceStatus();
|
|
1451
|
+
if (json) {
|
|
1452
|
+
const payload = {
|
|
1453
|
+
environments: states.map((state, i) => withDerivedFacts(labelOnlyRoots[i] ? {
|
|
1454
|
+
...state,
|
|
1455
|
+
labelOnly: true
|
|
1456
|
+
} : state)),
|
|
1457
|
+
archived,
|
|
1458
|
+
archivedUsage: usage,
|
|
1459
|
+
capacity: cap,
|
|
1460
|
+
deviceLeases: leases,
|
|
1461
|
+
unprovisionedWorktrees: orphanWorktrees.map(withGitChip),
|
|
1462
|
+
simctlAvailable: simsAvailable,
|
|
1463
|
+
machine,
|
|
1464
|
+
maintenance
|
|
1465
|
+
};
|
|
1466
|
+
out.push(JSON.stringify(settle(payload)));
|
|
1467
|
+
return out;
|
|
1468
|
+
}
|
|
1469
|
+
out.push(...maintenanceLines(maintenance).map((line) => chalk.dim(line)));
|
|
1470
|
+
if (usage.count) out.push(`Archived: ${plural(usage.count, "workspace")}, ${formatBytes(usage.bytes)}`);
|
|
1471
|
+
if (projects.length === 0 && orphanWorktrees.length === 0) {
|
|
1472
|
+
out.push(chalk.dim("No projects registered."));
|
|
1473
|
+
for (const pool of pools) {
|
|
1474
|
+
if (pool.error) out.push(chalk.yellow(`${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
1475
|
+
if (pool.line) out.push(chalk.dim(pool.line));
|
|
1476
|
+
}
|
|
1477
|
+
for (const line of deviceLeaseLines(leases, leaseNow)) out.push(line);
|
|
1478
|
+
return out;
|
|
1479
|
+
}
|
|
1480
|
+
if (!simsAvailable) out.push(chalk.yellow(`simctl could not be read (${simctlError}), so no iOS sim below could be checked.`));
|
|
1481
|
+
for (const [i, [path, proj]] of projects.entries()) {
|
|
1482
|
+
const state = states[i];
|
|
1483
|
+
if (!state) continue;
|
|
1484
|
+
const shortcut = projectShortcut(path, proj);
|
|
1485
|
+
const marker = path === cwdRoot ? chalk.bold.cyan(`* ${shortcut}`) : shortcut;
|
|
1486
|
+
const idle = phaseMarker(state);
|
|
1487
|
+
out.push(`\n${marker}${idle} ${chalk.dim(`(${path})`)}`);
|
|
1488
|
+
out.push(labelOnlyRoots[i] ? chalk.dim(" worktree root (holds the label; the app registers its own entry)") : chalk.dim(` app: ${proj.bundleId ?? "?"} (${proj.isExpo ?? detectIsExpo(path) ? "expo" : "bare"})`));
|
|
1489
|
+
if (state.metro) {
|
|
1490
|
+
const label = state.metro.running ? chalk.green(`running (pid ${state.metro.pid})`) : state.metro.idleStop ? chalk.dim(`stopped (idle) after ${state.metro.idleStop.idleMinutes}m; \`stim start\`, \`ios\` or \`android\` restarts it`) : state.metro.lastStop ? chalk.dim(`not running${state.metro.lastStop.reason === "vanished" ? "" : ` since ${state.metro.lastStop.at}`}; ${describeMetroLastStop(state.metro.lastStop)}`) : chalk.dim("not running");
|
|
1491
|
+
out.push(` metro: port ${state.metro.port} ${label}`);
|
|
1492
|
+
if (state.metro.tunnel) {
|
|
1493
|
+
const { provider, url } = state.metro.tunnel;
|
|
1494
|
+
out.push(` tunnel: ${provider}${provider === "tailscale" ? " (tailnet-only)" : ""} ${url}`);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
if (state.supervisor) {
|
|
1498
|
+
const health = state.supervisor.healthy ? chalk.green("healthy") : chalk.yellow("not answering");
|
|
1499
|
+
const mode = state.supervisor.mode ? chalk.dim(` (${state.supervisor.mode})`) : "";
|
|
1500
|
+
out.push(` supervisor: pid ${state.supervisor.pid}${mode} ${health}`);
|
|
1501
|
+
}
|
|
1502
|
+
if (state.build) {
|
|
1503
|
+
const line = ` ${buildStatusLine(state.build, Date.now())}`;
|
|
1504
|
+
out.push(state.build.state === "running" ? line : chalk.yellow(line));
|
|
1505
|
+
}
|
|
1506
|
+
out.push(...lastBuildsLines(state.lastBuilds));
|
|
1507
|
+
if (state.worktree?.git) out.push(chalk.dim(` git: ${gitSummaryText(state.worktree.git)}`));
|
|
1508
|
+
for (const agent of state.agents ?? []) out.push(chalk.dim(` agent: ${agentLine(agent)}`));
|
|
1509
|
+
if (state.logs) {
|
|
1510
|
+
const n = state.logs.errorsSinceMarker;
|
|
1511
|
+
const errs = n > 0 ? chalk.yellow(` (${n} error${n === 1 ? "" : "s"} since the last marker)`) : "";
|
|
1512
|
+
out.push(chalk.dim(` logs: ${state.logs.dir}`) + errs);
|
|
1513
|
+
}
|
|
1514
|
+
for (const deviceState of [{
|
|
1515
|
+
slot: "default",
|
|
1516
|
+
ios: state.ios,
|
|
1517
|
+
android: state.android
|
|
1518
|
+
}, ...state.slots ?? []]) {
|
|
1519
|
+
const slotLabel = deviceState.slot === "default" ? "" : ` [${deviceState.slot}]`;
|
|
1520
|
+
out.push(...iosStatusLines(deviceState.ios, slotLabel));
|
|
1521
|
+
out.push(...androidStatusLines(deviceState.android, slotLabel));
|
|
1522
|
+
}
|
|
1523
|
+
if (state.macos) {
|
|
1524
|
+
const host = state.macos.host;
|
|
1525
|
+
const where = host ? ` on ${host.machine} as ${host.bundleId}${chalk.dim(` (session ${host.session})`)}` : "";
|
|
1526
|
+
const build = state.macos.build;
|
|
1527
|
+
const placement = build.buildMachine === void 0 ? "" : `; build placement ${build.buildMachine}, built on ${build.builtOn ?? "none"}`;
|
|
1528
|
+
out.push(` macOS ${state.macos.product}: ${state.macos.state}${where}; build ${build.state}${placement}`);
|
|
1529
|
+
if (host && "command" in host.agent) out.push(chalk.dim(` agent: ${host.agent.command}`));
|
|
1530
|
+
}
|
|
1531
|
+
if (state.web) {
|
|
1532
|
+
const browser = state.web.running ? chalk.green(`running (pid ${state.web.pid}, DevTools ${state.web.cdpEndpoint})`) : chalk.dim("not running");
|
|
1533
|
+
const page = state.web.page;
|
|
1534
|
+
const failed = page?.state === "failed" ? ` -- ${chalk.yellow(`page failed: ${page.error}`)}` : "";
|
|
1535
|
+
out.push(` web: ${chalk.cyan(page?.url ?? state.web.url)} ${browser}${state.web.headless ? "" : chalk.dim(" (headed)")}${activitySuffix(state.web.activity)}${failed}`);
|
|
1536
|
+
}
|
|
1537
|
+
for (const device of state.physicalDevices ?? []) out.push(` ${physicalDeviceLine(device, leaseNow)}`);
|
|
1538
|
+
for (const remote of state.remoteDevices ?? []) out.push(` ${remoteDeviceLine(remote)}`);
|
|
1539
|
+
for (const w of state.warnings) out.push(chalk.yellow(` ! ${w}`));
|
|
1540
|
+
for (const note of state.issues.filter((issue) => issue.severity === "info")) out.push(chalk.dim(` - ${note.message}`));
|
|
1541
|
+
}
|
|
1542
|
+
for (const pool of pools) {
|
|
1543
|
+
if (pool.error) out.push(chalk.yellow(`\n${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
1544
|
+
if (pool.line) out.push(chalk.dim(`\n${pool.line}`));
|
|
1545
|
+
}
|
|
1546
|
+
const leaseLines = deviceLeaseLines(leases, leaseNow);
|
|
1547
|
+
if (leaseLines.length) {
|
|
1548
|
+
out.push("");
|
|
1549
|
+
for (const line of leaseLines) out.push(line);
|
|
1550
|
+
}
|
|
1551
|
+
if (orphanWorktrees.length) {
|
|
1552
|
+
out.push(chalk.dim(`\nWorktrees with no environment (${orphanWorktrees.length}):`));
|
|
1553
|
+
for (const w of orphanWorktrees) out.push(chalk.dim(` ${orphanWorktreeLine(w)}`));
|
|
1554
|
+
}
|
|
1555
|
+
out.push(chalk.dim(machine?.memorySource === "footprint" ? `\n${cap.liveCount} active environment(s) use ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)}.` : `\n${cap.liveCount} active environment(s), roughly ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)} committed.`));
|
|
1556
|
+
const volumes = readVolumes(cwdRoot || cwd);
|
|
1557
|
+
const line = diskLine(volumes);
|
|
1558
|
+
if (line) {
|
|
1559
|
+
const tight = tightVolumes(volumes);
|
|
1560
|
+
if (tight.length) {
|
|
1561
|
+
const which = tight.map((v) => v.volume).join(" and ");
|
|
1562
|
+
out.push(chalk.yellow(`${line} A single iOS build can exhaust ${which} -- run \`stim gc\` before starting another environment.`));
|
|
1563
|
+
} else out.push(chalk.dim(line));
|
|
1564
|
+
}
|
|
1565
|
+
if (cap.overCapacity) out.push(chalk.yellow("Over comfortable capacity. A machine that swaps is slower than one working in sequence -- release one before starting another."));
|
|
1566
|
+
return out;
|
|
1567
|
+
}
|
|
1568
|
+
function watchedPids({ roots, states }) {
|
|
1569
|
+
return [...roots.flatMap((root) => [
|
|
1570
|
+
...root.supervisorPid ? [root.supervisorPid] : [],
|
|
1571
|
+
...root.build ? [root.build.pid] : [],
|
|
1572
|
+
...root.browserPids,
|
|
1573
|
+
...root.macosPids ?? []
|
|
1574
|
+
]), ...states.flatMap((state) => state.metro?.running && state.metro.pid ? [state.metro.pid] : [])];
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Reads status now and again on every change until stopped, and calls `emit` with each new rendering: the JSON payload
|
|
1578
|
+
* with `json`, the human view otherwise. `emit` never sees the same rendering twice in a row. `cwd` stands for the
|
|
1579
|
+
* directory status runs in, which marks the current workspace.
|
|
1580
|
+
*/
|
|
1581
|
+
function runStatusWatch({ json, cwd = process.cwd(), emit, failed }) {
|
|
1582
|
+
let last = null;
|
|
1583
|
+
let lastPayload = null;
|
|
1584
|
+
let archiveStamp = null;
|
|
1585
|
+
let archives;
|
|
1586
|
+
let snapshot = null;
|
|
1587
|
+
let sources = null;
|
|
1588
|
+
let tablesAt = 0;
|
|
1589
|
+
let machineDue = false;
|
|
1590
|
+
const measurer = createStatusMeasurer({ updated: () => scheduler.trigger("light") });
|
|
1591
|
+
const scheduler = createRefreshScheduler({
|
|
1592
|
+
debounceMs: 250,
|
|
1593
|
+
lightIntervalMs: WATCH_LIGHT_INTERVAL_MS,
|
|
1594
|
+
run: async (kind) => {
|
|
1595
|
+
triggerMaintenance("status-watch", { warn: false });
|
|
1596
|
+
let text;
|
|
1597
|
+
let payload = null;
|
|
1598
|
+
try {
|
|
1599
|
+
const now = Date.now();
|
|
1600
|
+
if (kind === "light" && snapshot) {
|
|
1601
|
+
const machine = json && machineDue;
|
|
1602
|
+
const tables = machine || now - tablesAt >= 5e3;
|
|
1603
|
+
machineDue = false;
|
|
1604
|
+
await refreshLightFacts(snapshot, {
|
|
1605
|
+
tables,
|
|
1606
|
+
machine
|
|
1607
|
+
});
|
|
1608
|
+
if (tables) tablesAt = now;
|
|
1609
|
+
} else {
|
|
1610
|
+
let stamp = null;
|
|
1611
|
+
try {
|
|
1612
|
+
stamp = statSync$1(archiveRoot()).mtimeMs;
|
|
1613
|
+
} catch {}
|
|
1614
|
+
if (archives === void 0 || stamp !== archiveStamp) {
|
|
1615
|
+
archives = readArchives();
|
|
1616
|
+
archiveStamp = stamp;
|
|
1617
|
+
}
|
|
1618
|
+
const first = snapshot === null;
|
|
1619
|
+
snapshot = await readStatus({
|
|
1620
|
+
git: first ? "none" : "all",
|
|
1621
|
+
cwd,
|
|
1622
|
+
probes: liveProbes({
|
|
1623
|
+
simctlListing: sources?.simulatorListing(),
|
|
1624
|
+
gitMaxAgeMs: WATCH_GIT_MAX_AGE_MS,
|
|
1625
|
+
archives
|
|
1626
|
+
})
|
|
1627
|
+
});
|
|
1628
|
+
tablesAt = now;
|
|
1629
|
+
machineDue = false;
|
|
1630
|
+
sources?.watchRepositories(snapshot.gitCommonDirs);
|
|
1631
|
+
sources?.watchProcesses(watchedPids(snapshot));
|
|
1632
|
+
if (first) scheduler.trigger("full", 0);
|
|
1633
|
+
}
|
|
1634
|
+
measurer.schedule(snapshot.states, snapshot.worktrees);
|
|
1635
|
+
text = renderStatus(snapshot, json, (full) => payload = watchPayload(lastPayload, full), cwd).join("\n");
|
|
1636
|
+
} catch (error) {
|
|
1637
|
+
failed(String(error?.message || error));
|
|
1638
|
+
return;
|
|
1639
|
+
} finally {
|
|
1640
|
+
sources?.reconcile();
|
|
1641
|
+
}
|
|
1642
|
+
const key = json && payload ? watchChangeKey(payload) : text;
|
|
1643
|
+
if (key === last) return;
|
|
1644
|
+
last = key;
|
|
1645
|
+
lastPayload = payload;
|
|
1646
|
+
emit(text);
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
const fallback = setInterval(() => scheduler.trigger("full"), WATCH_FALLBACK_MS);
|
|
1650
|
+
const machine = setInterval(() => {
|
|
1651
|
+
if (!json || !snapshot?.machine) return;
|
|
1652
|
+
machineDue = true;
|
|
1653
|
+
scheduler.trigger("light");
|
|
1654
|
+
}, WATCH_MACHINE_INTERVAL_MS);
|
|
1655
|
+
sources = watchStatusSources({
|
|
1656
|
+
home: getConfigDir(),
|
|
1657
|
+
deviceSet: process.platform === "darwin" ? join$1(userInfo().homedir, "Library", "Developer", "CoreSimulator", "Devices") : null,
|
|
1658
|
+
onChange: (kind) => scheduler.trigger(kind)
|
|
1659
|
+
});
|
|
1660
|
+
scheduler.trigger("full", 0);
|
|
1661
|
+
return { stop() {
|
|
1662
|
+
clearInterval(fallback);
|
|
1663
|
+
clearInterval(machine);
|
|
1664
|
+
scheduler.stop();
|
|
1665
|
+
sources?.stop();
|
|
1666
|
+
} };
|
|
1667
|
+
}
|
|
1668
|
+
async function watchStatus(json) {
|
|
1669
|
+
const finish = () => {
|
|
1670
|
+
stopReader();
|
|
1671
|
+
watch.stop();
|
|
1672
|
+
process.exit(0);
|
|
1673
|
+
};
|
|
1674
|
+
process.on("SIGINT", finish);
|
|
1675
|
+
process.on("SIGTERM", finish);
|
|
1676
|
+
const watch = runStatusWatch({
|
|
1677
|
+
json,
|
|
1678
|
+
emit: (text) => process.stdout.write(`${!json && process.stdout.isTTY ? "\x1B[2J\x1B[H" : ""}${text}\n`),
|
|
1679
|
+
failed: (message) => console.error(chalk.red(message))
|
|
1680
|
+
});
|
|
1681
|
+
const stopReader = watchStdoutReader(finish);
|
|
1682
|
+
await new Promise(() => {});
|
|
1683
|
+
}
|
|
1684
|
+
function agentLine({ tool, title, sessionId, lastActiveAt }) {
|
|
1685
|
+
const at = lastActiveAt ? `, active ${lastActiveAt}` : "";
|
|
1686
|
+
return `${tool === "codex" ? "Codex" : "Claude Code"} ${title ? `"${title}"` : sessionId}${at}`;
|
|
1687
|
+
}
|
|
1688
|
+
function orphanWorktreeLine(w) {
|
|
1689
|
+
return `${w.path}${w.branch ? ` [${w.branch}]` : ""}${w.git ? ` -- ${gitSummaryText(w.git)}` : ""}`;
|
|
1690
|
+
}
|
|
1691
|
+
function lastBuildsLines(reports) {
|
|
1692
|
+
const texts = Object.values(reports ?? {}).map(lastBuildText);
|
|
1693
|
+
return texts.length ? [chalk.dim(` last build: ${texts.join(", ")}`)] : [];
|
|
1694
|
+
}
|
|
1695
|
+
function lastBuildText(report) {
|
|
1696
|
+
const source = report.cacheHit ? `${report.cacheHit} cache` : report.status === "ok" ? "compiled" : "no cache hit";
|
|
1697
|
+
const took = report.durationMs === null ? "" : ` in ${formatDuration(report.durationMs)}`;
|
|
1698
|
+
const placement = report.buildMachine === void 0 ? "" : `; build placement ${report.buildMachine}, built on ${report.builtOn ?? (report.cacheHit ? "none (cache)" : "none")}`;
|
|
1699
|
+
return `${report.platform} ${report.status === "ok" ? source : `failed (${report.errorCode ?? "error"}), ${source}`}${took}${placement}`;
|
|
1700
|
+
}
|
|
1701
|
+
function idleShutdownSuffix(record) {
|
|
1702
|
+
return record ? chalk.dim(` -- shut down after ${record.idleMinutes}m idle at ${record.at} (${record.reason === DEVICE_RECLAIM_REASON ? "reclaimed for a waiting run; devices.reclaimIdleMinutes" : "devices.idleShutdownMinutes"})`) : "";
|
|
1703
|
+
}
|
|
1704
|
+
function activitySuffix(activity) {
|
|
1705
|
+
const label = activityLabel(activity, Date.now());
|
|
1706
|
+
return label ? ` -- ${activity?.state === "driven" ? chalk.magenta(label) : chalk.dim(label)}` : "";
|
|
1707
|
+
}
|
|
1708
|
+
function appSuffix(app) {
|
|
1709
|
+
if (!app) return "";
|
|
1710
|
+
if (app.state === "running") return chalk.dim(` -- ${app.id} running`);
|
|
1711
|
+
if (app.state === "stopped") return ` -- ${chalk.yellow(`${app.id} not running`)}`;
|
|
1712
|
+
return chalk.dim(` -- ${app.id} process unknown`);
|
|
1713
|
+
}
|
|
1714
|
+
function readVolumes(projectPath) {
|
|
1715
|
+
const roots = [.../* @__PURE__ */ new Set([
|
|
1716
|
+
"/",
|
|
1717
|
+
volumeRootFor(getConfigDir()),
|
|
1718
|
+
volumeRootFor(projectPath)
|
|
1719
|
+
])];
|
|
1720
|
+
const volumes = [];
|
|
1721
|
+
for (const volume of roots) {
|
|
1722
|
+
const disk = parseDfFree(getExecutor().runFileQuiet("df", ["-k", volume], { timeoutMs: 5e3 }));
|
|
1723
|
+
if (disk) volumes.push({
|
|
1724
|
+
volume,
|
|
1725
|
+
disk
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
return volumes;
|
|
1729
|
+
}
|
|
1730
|
+
//#endregion
|
|
1731
|
+
export { runStatusWatch as n, statusCommand as r, readVolumes as t };
|