stim 1.15.0 → 1.17.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.
Files changed (123) hide show
  1. package/dist/{activity-B2-kb7k0.mjs → activity-IRvJY_ru.mjs} +49 -16
  2. package/dist/agent-device-usage-output-BK41vnzN.mjs +411 -0
  3. package/dist/{android-Cu_L4RpL.mjs → android--GorydsK.mjs} +692 -321
  4. package/dist/{android-Db2eEMaf.mjs → android-B_YNZy61.mjs} +25 -60
  5. package/dist/{android-CYmq0jNi.mjs → android-DE4v59Mb.mjs} +12 -3
  6. package/dist/{android-cas-PnKfAdB2.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
  7. package/dist/{app-install-CAAplXAt.mjs → app-install-VPkI5WEg.mjs} +52 -8
  8. package/dist/attempt-Bk2ouQVL.mjs +39 -0
  9. package/dist/{budget-CMiqghig.mjs → budget-DM984mnd.mjs} +372 -366
  10. package/dist/{build-plan-aeGMFX7e.mjs → build-plan-CmQCoyT-.mjs} +346 -88
  11. package/dist/{build-slots-Df1ApSuH.mjs → build-slots-41v_d2x9.mjs} +36 -21
  12. package/dist/{cli-0cX5s4NM.mjs → cli-Daxug5-K.mjs} +23 -17
  13. package/dist/cli.mjs +1 -1
  14. package/dist/collector-run.mjs +5 -192
  15. package/dist/{command-output-CliHHn7a.mjs → command-output-CDAIFD-8.mjs} +3 -3
  16. package/dist/{created-devices-BwVb3liH.mjs → created-devices-CpvzBL25.mjs} +1 -1
  17. package/dist/{dependency-state-BmsjKZ2H.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
  18. package/dist/{deps-BFlKbOIp.mjs → deps-DNWaQs4V.mjs} +2 -2
  19. package/dist/{dev-client-CjzLoNs0.mjs → dev-client-B-XC4uRH.mjs} +3 -40
  20. package/dist/{device-BZ1IyS5A.mjs → device-C8IOoJPv.mjs} +7 -6
  21. package/dist/device-capacity-D0GWHnTM.mjs +580 -0
  22. package/dist/device-host-worker.mjs +587 -110
  23. package/dist/{device-ios-DMQBUPus.mjs → device-ios-Bc7vbGwl.mjs} +75 -44
  24. package/dist/{device-lease-W5Pi1q38.mjs → device-lease-DpoS36_u.mjs} +2 -2
  25. package/dist/{device-pool-B2r38YjS.mjs → device-lease-run-B8YltIH_.mjs} +5 -125
  26. package/dist/device-pool-3o7s5lo4.mjs +125 -0
  27. package/dist/{device-remote-9ulPsdhY.mjs → device-remote-hFSkpfQu.mjs} +13 -13
  28. package/dist/{doctor-BcE5xsBn.mjs → doctor-Cnk9d7Hm.mjs} +86 -59
  29. package/dist/{error-diagnostics-Cb0P1WLS.mjs → error-diagnostics-C-NMnhrk.mjs} +11 -15
  30. package/dist/{gc-BuL1Genr.mjs → gc-DxCL2A46.mjs} +478 -33
  31. package/dist/{gradle-CmdOBq1d.mjs → gradle-D7-L2Th3.mjs} +4 -4
  32. package/dist/{guide-cCSGRFd3.mjs → guide-DjrTQGik.mjs} +2198 -566
  33. package/dist/{guide-status-CIoWK6mG.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
  34. package/dist/hosted-android-DwLS4Mse.mjs +32 -0
  35. package/dist/hosted-client-wk1W_CNW.mjs +196 -0
  36. package/dist/hosted-ios-aMo7Cljf.mjs +15 -0
  37. package/dist/hosted-logs-DqYmWtXc.mjs +187 -0
  38. package/dist/hosted-macos-dlHXEeF5.mjs +135 -0
  39. package/dist/hosted-native-C9xJ9rpA.mjs +255 -0
  40. package/dist/{build-progress-C2Jv1AtA.mjs → idle-B2m-Ovod.mjs} +300 -9
  41. package/dist/{idle-shutdown-B5LPaNyY.mjs → idle-shutdown-_3oOV1V_.mjs} +25 -17
  42. package/dist/{in-use-CndPMilN.mjs → in-use-CvGOUn-x.mjs} +30 -10
  43. package/dist/ios-Cr1h5gnO.mjs +189 -0
  44. package/dist/{ios-Chob8ny7.mjs → ios-DE6duQoz.mjs} +819 -460
  45. package/dist/{ios-3CtCRhwr.mjs → ios-DSfnPfse.mjs} +4 -4
  46. package/dist/{ios-device-DERmMmk-.mjs → ios-device-pAN4t54-.mjs} +1 -1
  47. package/dist/ios-state-8L3lgum6.mjs +89 -0
  48. package/dist/{launch-verify-CLlofxRt.mjs → launch-verify-lTnWZikR.mjs} +3 -3
  49. package/dist/logs-DUoKlDoS.mjs +384 -0
  50. package/dist/{client-C2IS36Qf.mjs → machines-C2XiNwh9.mjs} +330 -37
  51. package/dist/{macos-BwtbUtTN.mjs → macos-32po3kUq.mjs} +23 -18
  52. package/dist/macos-run.mjs +1 -1
  53. package/dist/maintenance-run.d.mts +4 -0
  54. package/dist/maintenance-run.mjs +254 -0
  55. package/dist/{metro-Di8EN2Tb.mjs → metro-g8NqiJp-.mjs} +1 -1
  56. package/dist/metro-gateway-DmslUM30.mjs +103 -0
  57. package/dist/{named-ports-Dj_XBNaL.mjs → named-ports-C8m8EQs2.mjs} +2 -2
  58. package/dist/{native-run-DFDoIRbY.mjs → native-run-D1Q56rAD.mjs} +17 -6
  59. package/dist/{native-runtime-i6OkVg-w.mjs → native-runtime-DhJI3IVQ.mjs} +6 -6
  60. package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
  61. package/dist/offload-worker.d.mts +1 -0
  62. package/dist/offload-worker.mjs +13 -8
  63. package/dist/{teardown-BYuQafiA.mjs → ownership-BMLqyBgJ.mjs} +639 -53
  64. package/dist/{ownership-BkYxUtuj.mjs → ownership-DyRQru0q.mjs} +2 -2
  65. package/dist/{ports-DddwttKM.mjs → ports-4nYqxPWC.mjs} +2 -2
  66. package/dist/{prebuild-BvxDlD6C.mjs → prebuild-D7RUMkwN.mjs} +4 -4
  67. package/dist/preview-CxPRIEht.mjs +318 -0
  68. package/dist/{project-CV3tDFHl.mjs → project-D47Rh0ly.mjs} +72 -3
  69. package/dist/{recordings-GEXp4iBT.mjs → recordings-BNgsD1Tr.mjs} +1 -1
  70. package/dist/{reload-ChPiwvot.mjs → reload-qZei6iWn.mjs} +77 -13
  71. package/dist/{remote-cache-CO2elm_b.mjs → remote-cache-Ci4DQYYj.mjs} +4 -4
  72. package/dist/{run-B-xqRrsg.mjs → run-CkE9y0nc.mjs} +2 -2
  73. package/dist/{server-bare-X7PUgizL.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
  74. package/dist/{server-expo-DhtX6bom.mjs → server-expo-CHTyXD0G.mjs} +4 -4
  75. package/dist/server-expo-CeakhI8P.mjs +2 -0
  76. package/dist/settings-BBpMcDbD.mjs +25 -0
  77. package/dist/settings-Cfd-0r2d.mjs +1440 -0
  78. package/dist/{settings-DbL6uhH8.mjs → settings-SR9OmW9h.mjs} +10 -4
  79. package/dist/settings.schema.json +472 -50
  80. package/dist/{simslim-Ciluxlq4.mjs → simslim-BWNrc3M3.mjs} +3 -3
  81. package/dist/{slot-launch-BY0BrOLh.mjs → slot-launch-DmjBmpQV.mjs} +10 -7
  82. package/dist/{spawn-entry-DncpJvWL.mjs → spawn-entry-jw19m8Nl.mjs} +1 -0
  83. package/dist/{start-CPO4wRg7.mjs → start-BopZcr4n.mjs} +1 -1
  84. package/dist/{start-CUD9nasA.mjs → start-uee1wWjY.mjs} +21 -17
  85. package/dist/{state-CaeaHbDA.mjs → state-BKa8wNN5.mjs} +1 -1
  86. package/dist/{state-BxCgeTQu.mjs → state-DyaNTgfR.mjs} +2 -2
  87. package/dist/{state-DFm77wRn.mjs → state-PeQiJuIu.mjs} +5 -5
  88. package/dist/{stats-DBLLFmKd.mjs → stats-Bq4fJOdB.mjs} +19 -5
  89. package/dist/{status-l84Gbvp2.mjs → status-CzS4bPO9.mjs} +5 -3
  90. package/dist/status-DlKvVJBE.mjs +49 -0
  91. package/dist/{status-DYXxNOT0.mjs → status-dXX2JX1C.mjs} +244 -50
  92. package/dist/{stop-CceYh1yG.mjs → stop-BCwvvs7F.mjs} +2 -2
  93. package/dist/{stop-Bad61z_2.mjs → stop-BjizrQwv.mjs} +83 -21
  94. package/dist/{stop-Bvf1MflS.mjs → stop-Cr1d8DSE.mjs} +4 -4
  95. package/dist/stop-cause-rhmGfwvt.mjs +97 -0
  96. package/dist/supervisor-run.d.mts +7 -4
  97. package/dist/supervisor-run.mjs +156 -27
  98. package/dist/{support-WLOzVKUv.mjs → support-BJPgYCu-.mjs} +61 -11
  99. package/dist/{support-CDQbDkL5.mjs → support-F9-sr0Oi.mjs} +6 -5
  100. package/dist/{toolchain-DmeYjXD9.mjs → toolchain-CNIBTIOv.mjs} +11 -11
  101. package/dist/trigger-Bemu8ytw.mjs +65 -0
  102. package/dist/trigger-CXts6qt1.mjs +2 -0
  103. package/dist/{warm-progress-DVHLN4uC.mjs → warm-progress-DF4JRvYI.mjs} +274 -5
  104. package/dist/watchman-APYjXSQa.mjs +48 -0
  105. package/dist/{web-k6w8-HnE.mjs → web-exQtGkoc.mjs} +14 -16
  106. package/dist/web-run.mjs +5 -5
  107. package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
  108. package/dist/{workspace-state-CL2V2Ons.mjs → workspace-state-DqcCbpE7.mjs} +34 -34
  109. package/dist/workspaces-Bcib97-6.mjs +306 -0
  110. package/dist/{worktree-BT_uULFx.mjs → worktree-Dc98cE6_.mjs} +1 -1
  111. package/dist/{worktree-qXKzADSC.mjs → worktree-ZpZR3S1k.mjs} +601 -33
  112. package/package.json +5 -5
  113. package/dist/device-capacity-DMuKC7nx.mjs +0 -136
  114. package/dist/hosted-macos-DwowNU7W.mjs +0 -447
  115. package/dist/logs-h9h6MUvE.mjs +0 -568
  116. package/dist/machine-usage-D_YYMzfR.mjs +0 -283
  117. package/dist/machines-CYtOCqcj.mjs +0 -259
  118. package/dist/merge-state-BnxLNQiM.mjs +0 -272
  119. package/dist/server-expo-KJeD109I.mjs +0 -2
  120. package/dist/settings-CduVcoxj.mjs +0 -680
  121. package/dist/stop-cause-CZ_Mr-v9.mjs +0 -665
  122. package/dist/watchman-Bx0wceoF.mjs +0 -238
  123. package/dist/worktree-C0c5Udwa.mjs +0 -753
@@ -1,40 +1,100 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { B as parseDeviceSlotKey, F as volumeRootFor, H as projectDeviceSlots, R as deviceSlotKey, _ as loadConfig$1, d as getConfigDir } from "./config-D0DbpZtM.mjs";
2
+ import { B as parseDeviceSlotKey, F as volumeRootFor, H as projectDeviceSlots, R as deviceSlotKey, _ as loadConfig$1, d as getConfigDir, j as formatBytes } from "./config-D0DbpZtM.mjs";
3
3
  import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
- import { a as parseNdjsonLine } from "./ndjson-CDY9IkVC.mjs";
5
- import { C as workspaceLogsDir, S as workspaceLogErrorIndex, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
6
- import { c as gitCommonDirOnDisk, p as linkedWorktreesOnDisk, s as gitCommonDir, y as repoRoot } from "./worktree-C0c5Udwa.mjs";
7
- import { l as projectShortcut, o as findServerWorkspace, r as detectIsExpo } from "./project-CV3tDFHl.mjs";
8
- import { c as readMetroTunnel, f as readWorkspaceLaunches, u as readRemoteSession } from "./state-CaeaHbDA.mjs";
9
- import { c as tailLines, n as createActivityReader, r as createDeviceProcessTables, s as readWebActivity } from "./activity-B2-kb7k0.mjs";
10
- import { a as formatElapsed, i as formatDuration, r as clockTime } from "./command-output-CliHHn7a.mjs";
11
- import { i as listLeaseFiles, r as leaseIsExpired, s as parseWorkspaceLeases } from "./device-lease-W5Pi1q38.mjs";
12
- import { F as ownedAvdDeviceProfile, O as listAdbDevices, at as POOL_SETTING_REMEDY, d as androidToolPath, dt as parkedMaxSetting, ft as readParked, z as ownedAvdSerialResolver } from "./android-Db2eEMaf.mjs";
13
- import { a as listeningPidsByPort, c as processCwds, d as isMetroRunning, i as listeningPids, l as resolveProjectMetro, o as pidExists, s as processCwd } from "./metro-Di8EN2Tb.mjs";
14
- import { a as readWebPage, o as readWebRecord, u as webFacts } from "./state-DFm77wRn.mjs";
15
- import { d as listAllIosSimsAsync, v as parseSimctlList } from "./ios-3CtCRhwr.mjs";
16
- import { a as buildStatusLine, h as statsProjectKey$1, i as buildReport, p as readStats, r as activeBuildState, s as parseActiveBuild, t as ACTIVE_BUILD_KEY } from "./build-progress-C2Jv1AtA.mjs";
17
- import { n as describeMetroLastStop, o as metroLastStop, u as resolveSupervisorTarget } from "./stop-cause-CZ_Mr-v9.mjs";
18
- import { m as hasMetroReverse } from "./app-install-CAAplXAt.mjs";
19
- import { r as probeHostedMacos } from "./hosted-macos-DwowNU7W.mjs";
20
- import { m as readEasSessionLedger$1, p as easMachineStateRoot$1 } from "./device-remote-9ulPsdhY.mjs";
21
- import { _ as statusActivity, a as capacity, b as withWebFacts, c as diskLine, d as gitSummaryText, f as metroReverseTargets, g as remoteDeviceState, h as remoteDeviceLine, i as applyMachineMemory, l as environmentState, m as poolLine, n as activityLabel, o as deviceLeaseLines, p as parseDfFree, r as addReverseMissingIssue, s as deviceLeaseStates, v as tightVolumes, y as unprovisionedWorktrees } from "./status-l84Gbvp2.mjs";
22
- import { n as attributeMachineUsage, r as readFootprints } from "./machine-usage-D_YYMzfR.mjs";
23
- import { d as readIosDevices, s as isReachable } from "./ios-device-DERmMmk-.mjs";
24
- import { n as mergeState } from "./merge-state-BnxLNQiM.mjs";
25
- import { i as createStatusMeasurer, n as workspacePhase, r as applyStatusMeasures } from "./warm-progress-DVHLN4uC.mjs";
4
+ import { a as formatElapsed, i as formatDuration, r as clockTime, u as plural } from "./command-output-CDAIFD-8.mjs";
5
+ import { P as resolveSettings, at as gitCommonDirOnDisk, gt as repoRoot, it as gitCommonDir, ut as linkedWorktreesOnDisk } from "./settings-Cfd-0r2d.mjs";
6
+ import { a as detectTutorial, c as findServerWorkspace, d as projectShortcut, i as detectPlatforms, p as readAppJson, r as detectIsExpo } from "./project-D47Rh0ly.mjs";
7
+ import { a as listeningPidsByPort, c as processCwds, d as isMetroRunning, i as listeningPids, l as resolveProjectMetro, o as pidExists, s as processCwd } from "./metro-g8NqiJp-.mjs";
8
+ import { b as workspaceLogErrorIndex, r as readWorkspaceState$1, x as workspaceLogsDir$1 } from "./workspace-state-DqcCbpE7.mjs";
9
+ import { a as readWebPage, o as readWebRecord, u as webFacts } from "./state-PeQiJuIu.mjs";
10
+ import { _ as statusActivity, a as capacity, b as withWebFacts, c as diskLine, d as gitSummaryText, f as metroReverseTargets, g as remoteDeviceState, h as remoteDeviceLine, i as applyMachineMemory, l as environmentState, m as poolLine, n as activityLabel, o as deviceLeaseLines, p as parseDfFree, r as addReverseMissingIssue, s as deviceLeaseStates, v as tightVolumes, y as unprovisionedWorktrees } from "./status-CzS4bPO9.mjs";
11
+ import { X as readFootprints, Y as attributeMachineUsage, a as machineNumber } from "./budget-DM984mnd.mjs";
12
+ import { d as readWebActivity, f as tailLines, i as createDeviceProcessTables, r as createActivityReader } from "./activity-IRvJY_ru.mjs";
13
+ import { i as listLeaseFiles, r as leaseIsExpired, s as parseWorkspaceLeases } from "./device-lease-DpoS36_u.mjs";
14
+ import { c as readMetroTunnel, f as readWorkspaceLaunches, u as readRemoteSession } from "./state-BKa8wNN5.mjs";
15
+ import { F as ownedAvdDeviceProfile, O as listAdbDevices, d as androidToolPath, ft as parkedMaxSetting, ot as POOL_SETTING_REMEDY, pt as readParked, z as ownedAvdSerialResolver } from "./android-B_YNZy61.mjs";
16
+ import { d as listAllIosSimsAsync, v as parseSimctlList } from "./ios-DSfnPfse.mjs";
17
+ import { t as resolveSupervisorTarget } from "./ownership-BMLqyBgJ.mjs";
18
+ import { b as readStats$1, c as ACTIVE_BUILD_KEY, d as buildReport, f as buildStatusLine, m as parseActiveBuild, u as activeBuildState, w as statsProjectKey$1 } from "./idle-B2m-Ovod.mjs";
19
+ import { a as parseNdjsonLine } from "./ndjson-PclOIwVY.mjs";
20
+ import { n as describeMetroLastStop, o as metroLastStop } from "./stop-cause-rhmGfwvt.mjs";
21
+ import { l as probeHostedSession } from "./hosted-client-wk1W_CNW.mjs";
22
+ import { m as hasMetroReverse } from "./app-install-VPkI5WEg.mjs";
23
+ import "./hosted-macos-dlHXEeF5.mjs";
24
+ import { m as readEasSessionLedger$1, p as easMachineStateRoot$1 } from "./device-remote-hFSkpfQu.mjs";
25
+ import { d as readIosDevices, s as isReachable } from "./ios-device-pAN4t54-.mjs";
26
+ import { n as maintenanceLines, r as maintenanceStatus } from "./status-DlKvVJBE.mjs";
27
+ import { i as createStatusMeasurer, n as workspacePhase, r as applyStatusMeasures, s as mergeState } from "./warm-progress-DF4JRvYI.mjs";
28
+ import { r as workspaceRecordingEnabled } from "./recordings-BNgsD1Tr.mjs";
26
29
  import { t as watchStdoutReader } from "./stdout-reader-C8yjre1x.mjs";
27
- import { r as workspaceRecordingEnabled } from "./recordings-GEXp4iBT.mjs";
28
- import { i as readSupervisorState } from "./stop-Bad61z_2.mjs";
30
+ import { t as triggerMaintenance } from "./trigger-Bemu8ytw.mjs";
31
+ import { i as readSupervisorState } from "./stop-BjizrQwv.mjs";
29
32
  import { createHash, randomUUID } from "node:crypto";
30
33
  import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
31
34
  import { join, posix, resolve } from "node:path";
32
- 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, writeFileSync as writeFileSync$1 } from "fs";
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";
33
36
  import { homedir, totalmem } from "os";
34
37
  import { basename as basename$1, dirname as dirname$1, join as join$1 } from "path";
35
38
  import { rotatedLogPath } from "@stim-cli/core";
36
- import { ERROR_SOURCES, bundleMarkerPlatform, countErrorEntries, gitMergeCacheDir, logFiles, macosAppState, queryLogs, readBuildDetail, readBuildHistory, readDeviceIdleShutdowns, readIdleStop, readLastBuilds, readMacosRecord, recordMatches, sortByTs, withDerivedFacts, withGitChip, withStateReadCache } from "@stim-cli/core/state";
39
+ 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";
37
40
  import chalk from "chalk";
41
+ //#region src/device-host/hosted-native-status.ts
42
+ function hostedNativeProbe(placement, probe, slot, platform) {
43
+ const label = platform === "ios" ? "iOS" : "Android";
44
+ const rerun = `stim ${platform} --remote ${placement.machine}${slot === "default" ? "" : ` --slot ${slot}`}`;
45
+ return {
46
+ state: probe.state === "ready" ? "ready" : probe.state === "stopped" ? "stopped" : "unverified",
47
+ ...probe.state === "ready" ? {} : { warning: probe.state === "stopped" ? `The ${label} session on ${placement.machine} stopped or no longer exists. Run ${rerun} to launch it again, or stim stop to clear the placement.` : `${placement.machine} could not confirm its ${label} session${probe.state === "unknown" ? probe.notice ? `: ${probe.notice}` : "" : `: ${probe.reason.replace(/\.+$/, "")}`}. The placement stays recorded; run stim stop when the host answers.` }
48
+ };
49
+ }
50
+ //#endregion
51
+ //#region src/device-host/hosted-android-status.ts
52
+ function applyHostedAndroidProbe(placement, probe, slot = "default") {
53
+ const { state, warning } = hostedNativeProbe(placement, probe, slot, "android");
54
+ const host = {
55
+ ...hostedAndroidStatus(placement),
56
+ state
57
+ };
58
+ return {
59
+ android: {
60
+ host,
61
+ name: host.device?.name,
62
+ serial: null,
63
+ owned: false,
64
+ physical: false,
65
+ state
66
+ },
67
+ ...warning ? { warning } : {}
68
+ };
69
+ }
70
+ async function readHostedAndroidStatus(placements) {
71
+ return Object.fromEntries(await Promise.all(Object.entries(placements).map(async ([slot, placement]) => [slot, applyHostedAndroidProbe(placement, await probeHostedSession({
72
+ ...placement,
73
+ platform: "android"
74
+ }), slot)])));
75
+ }
76
+ //#endregion
77
+ //#region src/device-host/hosted-ios-status.ts
78
+ function applyHostedIosProbe(placement, probe, slot = "default") {
79
+ const { state, warning } = hostedNativeProbe(placement, probe, slot, "ios");
80
+ return {
81
+ ios: {
82
+ host: {
83
+ ...hostedIosStatus(placement),
84
+ state
85
+ },
86
+ name: placement.device?.name ?? null,
87
+ udid: "",
88
+ owned: false,
89
+ state
90
+ },
91
+ ...warning ? { warning } : {}
92
+ };
93
+ }
94
+ async function readHostedIosStatus(placements) {
95
+ return Object.fromEntries(await Promise.all(Object.entries(placements).map(async ([slot, placement]) => [slot, applyHostedIosProbe(placement, await probeHostedSession(placement), slot)])));
96
+ }
97
+ //#endregion
38
98
  //#region src/device-host/hosted-macos-status.ts
39
99
  function applyHostedMacosProbe(record, probe) {
40
100
  if (!record.host || probe.state === "ready") return { record };
@@ -56,7 +116,7 @@ function applyHostedMacosProbe(record, probe) {
56
116
  }
57
117
  async function readHostedMacosStatus(record, options) {
58
118
  if (!record?.host || record.supervisor || !record.hostLaunched) return { record };
59
- return applyHostedMacosProbe(record, await probeHostedMacos(record.host, options));
119
+ return applyHostedMacosProbe(record, await probeHostedSession(record.host, options));
60
120
  }
61
121
  //#endregion
62
122
  //#region src/status-watch.ts
@@ -125,14 +185,18 @@ function createRefreshScheduler({ debounceMs, lightIntervalMs = 0, run }) {
125
185
  * null for none. A null name means the platform did not report one.
126
186
  */
127
187
  function statusChange(dir, name) {
188
+ if (dir === "archive" && (name?.startsWith(".incoming-") || name?.startsWith(".removing-") || name?.startsWith(".lock"))) return null;
128
189
  if (name?.includes(".lock")) return null;
129
190
  if (dir === "logs") return "light";
130
191
  if (name === null) return "full";
131
192
  switch (dir) {
132
- case "home": return name.startsWith("config.json") || name === "workspaces" || name === "device-locks" ? "full" : null;
193
+ case "home":
194
+ if (name === "maintenance") return "light";
195
+ return name.startsWith("config.json") || name === "archive" || name === "workspaces" || name === "device-locks" ? "full" : null;
133
196
  case "workspace":
134
197
  if (name.startsWith("build-detail.json")) return "light";
135
198
  return name.startsWith("state.json") || name.startsWith("ended-agents.json") || name === "logs" ? "full" : null;
199
+ case "maintenance": return name === "state.json" ? "light" : null;
136
200
  case "eas": return name.startsWith("sessions.json") ? "full" : null;
137
201
  default: return "full";
138
202
  }
@@ -156,7 +220,9 @@ function watchStatusSources({ home, onChange, platform = process.platform, simct
156
220
  const desiredDirs = () => {
157
221
  const dirs = /* @__PURE__ */ new Map([
158
222
  [home, "home"],
223
+ [join(home, "archive"), "archive"],
159
224
  [join(home, "workspaces"), "workspaces"],
225
+ [join(home, "maintenance"), "maintenance"],
160
226
  [join(home, "device-locks"), "leases"],
161
227
  [easMachineStateRoot$1(), "eas"]
162
228
  ]);
@@ -970,6 +1036,71 @@ function physicalDeviceLine(device, now) {
970
1036
  //#endregion
971
1037
  //#region src/commands/status.ts
972
1038
  const WATCH_GIT_MAX_AGE_MS = 6e4;
1039
+ function iosStatusName(ios) {
1040
+ const host = ios.host;
1041
+ 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;
1042
+ }
1043
+ function iosStatusLines(record, slotLabel) {
1044
+ const out = [];
1045
+ const host = record?.udid ? record.host : void 0;
1046
+ const iosDevices = [record, ...host ? [{
1047
+ host,
1048
+ name: host.device?.name ?? null,
1049
+ udid: "",
1050
+ owned: false,
1051
+ state: host.state ?? "unverified"
1052
+ }] : []];
1053
+ for (const ios of iosDevices) {
1054
+ if (!ios) continue;
1055
+ const booted = ios.state === "Booted" ? chalk.green("booted") : chalk.dim(ios.state.toLowerCase());
1056
+ const owned = ios.owned ? chalk.dim(" (owned)") : "";
1057
+ out.push(` ios${slotLabel}: ${chalk.cyan(iosStatusName(ios))} ${booted}${owned}${activitySuffix(ios.activity)}${appSuffix(ios.app)}${idleShutdownSuffix(ios.idleShutdown)}`);
1058
+ if (!ios.udid && ios.host?.agent.driver === "agent-device") out.push(chalk.dim(` agent: ${ios.host.agent.command}`));
1059
+ }
1060
+ return out;
1061
+ }
1062
+ function applyHostedAndroidStates(state, saved, factsBySlot) {
1063
+ for (const [slot, record] of Object.entries(hostedAndroidRecords(saved))) if (!parseHostedAndroidPlacement(record)) state.warnings.push(unreadableHostedAndroid(slot));
1064
+ for (const [slot, facts] of Object.entries(factsBySlot)) {
1065
+ const local = slot === "default" ? state.android : state.slots?.find((entry) => entry.slot === slot)?.android;
1066
+ const conflict = local && (local.state === "detected" || local.state === "unknown");
1067
+ const android = conflict ? {
1068
+ ...local,
1069
+ host: facts.android.host
1070
+ } : facts.android;
1071
+ if (conflict) state.warnings.push(`Slot ${slot} records both a local and hosted Android emulator (${facts.android.name} on ${facts.android.host?.machine}); run stim stop to reconcile them.`);
1072
+ if (slot === "default") state.android = android;
1073
+ else {
1074
+ state.slots ??= [];
1075
+ const savedSlot = state.slots.find((entry) => entry.slot === slot);
1076
+ if (savedSlot) savedSlot.android = android;
1077
+ else state.slots.push({
1078
+ slot,
1079
+ ios: null,
1080
+ android
1081
+ });
1082
+ }
1083
+ if (facts.warning) state.warnings.push(facts.warning);
1084
+ state.live ||= facts.android.state === "ready";
1085
+ }
1086
+ }
1087
+ function androidStatusLines(record, slotLabel) {
1088
+ const out = [];
1089
+ if (record?.host && !record.serial) {
1090
+ const host = record.host;
1091
+ 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"}`);
1092
+ } else if (record) {
1093
+ const kind = record.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
1094
+ const observed = record.state ? ` ${record.state}${record.serial ? ` (${record.serial})` : ""}` : "";
1095
+ out.push(` android${slotLabel}: ${chalk.cyan(record.name)} ${kind}${observed}${record.owned ? chalk.dim(" (owned)") : ""}${activitySuffix(record.activity)}${appSuffix(record.app)}${idleShutdownSuffix(record.idleShutdown)}`);
1096
+ if (record.host) {
1097
+ const host = record.host;
1098
+ 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"}`);
1099
+ }
1100
+ }
1101
+ if (record?.host?.agent.driver === "agent-device") out.push(chalk.dim(` agent: ${record.host.agent.command}`));
1102
+ return out;
1103
+ }
973
1104
  function formatGb(mb) {
974
1105
  return `${(mb / 1024).toFixed(1)} GB`;
975
1106
  }
@@ -980,12 +1111,14 @@ function statusCommand(program) {
980
1111
  for (const line of renderStatus(await readStatus(0), json)) console.log(line);
981
1112
  });
982
1113
  }
983
- function readStatus(gitMaxAgeMs, simctlListing = null) {
984
- return withStateReadCache(() => readStatusFacts(gitMaxAgeMs, simctlListing));
1114
+ function readStatus(gitMaxAgeMs, simctlListing = null, archives) {
1115
+ return withStateReadCache(() => readStatusFacts(gitMaxAgeMs, simctlListing, archives));
985
1116
  }
986
- async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1117
+ async function readStatusFacts(gitMaxAgeMs, simctlListing, cachedArchives) {
987
1118
  const cfg = loadConfig$1();
988
1119
  const projects = Object.entries(cfg?.projects || {});
1120
+ const iosReads = projects.map(([path]) => readHostedIosStatus(hostedIosPlacements(readWorkspaceState$1(path))));
1121
+ const androidReads = projects.map(([path]) => readHostedAndroidStatus(hostedAndroidPlacements(readWorkspaceState$1(path))));
989
1122
  const macosReads = projects.map(([path]) => readHostedMacosStatus(readMacosRecord(path)));
990
1123
  const cwdRoot = findServerWorkspace(process.cwd())?.root ?? null;
991
1124
  const worktrees = linkedWorktrees([process.cwd(), ...projects.map(([path]) => path)]);
@@ -1021,7 +1154,7 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1021
1154
  }
1022
1155
  const running = await processes;
1023
1156
  await gitRead;
1024
- const history = readStats().record?.history;
1157
+ const history = readStats$1().record?.history;
1025
1158
  const states = [];
1026
1159
  const labelOnlyRoots = [];
1027
1160
  const launchesByState = [];
@@ -1080,6 +1213,30 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1080
1213
  }), web));
1081
1214
  const state = states[states.length - 1];
1082
1215
  if (state) {
1216
+ for (const [slot, record] of Object.entries(hostedIosRecords(saved))) if (!parseHostedIosPlacement(record)) state.warnings.push(unreadableHostedIos(slot));
1217
+ for (const [slot, facts] of Object.entries(await iosReads[i])) {
1218
+ const local = slot === "default" ? state.ios : state.slots?.find((entry) => entry.slot === slot)?.ios;
1219
+ const conflict = local?.udid && (local.state === "Booted" || local.state === "unknown");
1220
+ const ios = conflict ? {
1221
+ ...local,
1222
+ host: facts.ios.host
1223
+ } : facts.ios;
1224
+ if (conflict) state.warnings.push(`Slot ${slot} records both a local and hosted iOS simulator (${iosStatusName(facts.ios)}); run stim stop to reconcile them.`);
1225
+ if (slot === "default") state.ios = ios;
1226
+ else {
1227
+ state.slots ??= [];
1228
+ const savedSlot = state.slots.find((entry) => entry.slot === slot);
1229
+ if (savedSlot) savedSlot.ios = ios;
1230
+ else state.slots.push({
1231
+ slot,
1232
+ ios,
1233
+ android: null
1234
+ });
1235
+ }
1236
+ if (facts.warning) state.warnings.push(facts.warning);
1237
+ state.live ||= facts.ios.state === "ready";
1238
+ }
1239
+ applyHostedAndroidStates(state, saved, await androidReads[i]);
1083
1240
  const tunnel = readMetroTunnel(path);
1084
1241
  if (state.metro && tunnel?.kind === "managed" && tunnel.port === state.metro.port && pidExists(tunnel.pid)) state.metro.tunnel = {
1085
1242
  provider: tunnel.provider,
@@ -1090,7 +1247,16 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1090
1247
  if (macosFacts.warning) state.warnings.push(macosFacts.warning);
1091
1248
  state.live ||= macos.state === "running" || macos.state === "orphaned" || macos.build.state === "running";
1092
1249
  }
1093
- Object.assign(state, builds, workspacePhase(state.live, saved, { now: leaseNow }), { recording: { enabled: workspaceRecordingEnabled(path, proj, cfg, process.env) } });
1250
+ Object.assign(state, builds, workspacePhase(state.live, saved, { now: leaseNow }), {
1251
+ platforms: detectPlatforms(path, resolveSettings({
1252
+ projectPath: path,
1253
+ gitCommonDir: gitCommonDirOnDisk(path),
1254
+ repoRoot: state.worktree?.path ?? path
1255
+ })),
1256
+ recording: { enabled: workspaceRecordingEnabled(path, proj, cfg, process.env) }
1257
+ });
1258
+ const tutorial = detectTutorial(readAppJson(path));
1259
+ if (tutorial) state.tutorial = tutorial;
1094
1260
  }
1095
1261
  const physicalDevices = physicalDeviceStates(leaseFiles, parseWorkspaceLeases(saved?.deviceLeases), {
1096
1262
  root: path,
@@ -1118,7 +1284,11 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1118
1284
  tables,
1119
1285
  busy: sims.some((sim) => sim.state === "Booted")
1120
1286
  });
1287
+ const archives = cachedArchives ?? readArchives();
1288
+ const maxCount = machineNumber("archive.maxCount", cfg, process.env);
1121
1289
  return {
1290
+ archived: linkReplacedArchives(archives.slice(0, maxCount.value ?? 200), states.map((state) => state.path)),
1291
+ archivedUsage: archivedUsage(archives),
1122
1292
  projects,
1123
1293
  states,
1124
1294
  labelOnlyRoots,
@@ -1139,8 +1309,21 @@ async function readStatusFacts(gitMaxAgeMs, simctlListing) {
1139
1309
  function readLogDerivedFacts(states) {
1140
1310
  const now = Date.now();
1141
1311
  for (const state of states) {
1312
+ const saved = readWorkspaceState$1(state.path);
1313
+ for (const devices of [{
1314
+ slot: "default",
1315
+ ios: state.ios,
1316
+ android: state.android
1317
+ }, ...state.slots ?? []]) for (const platform of ["ios", "android"]) {
1318
+ const device = devices[platform];
1319
+ const placement = readDevicePlacement(saved, platform, devices.slot);
1320
+ if (device) {
1321
+ if (placement) device.devicePlacement = placement;
1322
+ else delete device.devicePlacement;
1323
+ }
1324
+ }
1142
1325
  if (state.metro) {
1143
- const bundle = metroBundleState(tailLines(join$1(workspaceLogsDir(state.path), "metro.ndjson")) ?? [], {
1326
+ const bundle = metroBundleState(tailLines(join$1(workspaceLogsDir$1(state.path), "metro.ndjson")) ?? [], {
1144
1327
  running: state.metro.running,
1145
1328
  now
1146
1329
  });
@@ -1225,7 +1408,7 @@ async function refreshLightFacts(snapshot, machine) {
1225
1408
  busy: true
1226
1409
  });
1227
1410
  }
1228
- function renderStatus({ projects, states, labelOnlyRoots, leases, leaseNow, orphanWorktrees, simsAvailable, simctlError, cwdRoot, machine }, json) {
1411
+ function renderStatus({ archived, archivedUsage: usage, projects, states, labelOnlyRoots, leases, leaseNow, orphanWorktrees, simsAvailable, simctlError, cwdRoot, machine }, json) {
1229
1412
  const out = [];
1230
1413
  const totalMemoryMb = Math.round(totalmem() / 1048576);
1231
1414
  const cap = capacity(states, totalMemoryMb);
@@ -1240,20 +1423,26 @@ function renderStatus({ projects, states, labelOnlyRoots, leases, leaseNow, orph
1240
1423
  })
1241
1424
  };
1242
1425
  });
1426
+ const maintenance = maintenanceStatus();
1243
1427
  if (json) {
1244
1428
  out.push(JSON.stringify({
1245
1429
  environments: states.map((state, i) => withDerivedFacts(labelOnlyRoots[i] ? {
1246
1430
  ...state,
1247
1431
  labelOnly: true
1248
1432
  } : state)),
1433
+ archived,
1434
+ archivedUsage: usage,
1249
1435
  capacity: cap,
1250
1436
  deviceLeases: leases,
1251
1437
  unprovisionedWorktrees: orphanWorktrees.map(withGitChip),
1252
1438
  simctlAvailable: simsAvailable,
1253
- machine
1439
+ machine,
1440
+ maintenance
1254
1441
  }));
1255
1442
  return out;
1256
1443
  }
1444
+ out.push(...maintenanceLines(maintenance).map((line) => chalk.dim(line)));
1445
+ if (usage.count) out.push(`Archived: ${plural(usage.count, "workspace")}, ${formatBytes(usage.bytes)}`);
1257
1446
  if (projects.length === 0 && orphanWorktrees.length === 0) {
1258
1447
  out.push(chalk.dim("No projects registered."));
1259
1448
  for (const pool of pools) {
@@ -1303,16 +1492,8 @@ function renderStatus({ projects, states, labelOnlyRoots, leases, leaseNow, orph
1303
1492
  android: state.android
1304
1493
  }, ...state.slots ?? []]) {
1305
1494
  const slotLabel = deviceState.slot === "default" ? "" : ` [${deviceState.slot}]`;
1306
- if (deviceState.ios) {
1307
- const booted = deviceState.ios.state === "Booted" ? chalk.green("booted") : chalk.dim(deviceState.ios.state.toLowerCase());
1308
- const owned = deviceState.ios.owned ? chalk.dim(" (owned)") : "";
1309
- out.push(` ios${slotLabel}: ${chalk.cyan(deviceState.ios.name ?? deviceState.ios.udid)} ${booted}${owned}${activitySuffix(deviceState.ios.activity)}${appSuffix(deviceState.ios.app)}${idleShutdownSuffix(deviceState.ios.idleShutdown)}`);
1310
- }
1311
- if (deviceState.android) {
1312
- const kind = deviceState.android.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
1313
- const observed = deviceState.android.state ? ` ${deviceState.android.state}${deviceState.android.serial ? ` (${deviceState.android.serial})` : ""}` : "";
1314
- out.push(` android${slotLabel}: ${chalk.cyan(deviceState.android.name)} ${kind}${observed}${deviceState.android.owned ? chalk.dim(" (owned)") : ""}${activitySuffix(deviceState.android.activity)}${appSuffix(deviceState.android.app)}${idleShutdownSuffix(deviceState.android.idleShutdown)}`);
1315
- }
1495
+ out.push(...iosStatusLines(deviceState.ios, slotLabel));
1496
+ out.push(...androidStatusLines(deviceState.android, slotLabel));
1316
1497
  }
1317
1498
  if (state.macos) {
1318
1499
  const host = state.macos.host;
@@ -1361,6 +1542,8 @@ function renderStatus({ projects, states, labelOnlyRoots, leases, leaseNow, orph
1361
1542
  }
1362
1543
  async function watchStatus(json) {
1363
1544
  let last = null;
1545
+ let archiveStamp = null;
1546
+ let archives;
1364
1547
  let snapshot = null;
1365
1548
  let sources = null;
1366
1549
  const measurer = createStatusMeasurer({ updated: () => scheduler.trigger("light") });
@@ -1368,10 +1551,21 @@ async function watchStatus(json) {
1368
1551
  debounceMs: 250,
1369
1552
  lightIntervalMs: WATCH_LIGHT_INTERVAL_MS,
1370
1553
  run: async (kind) => {
1554
+ triggerMaintenance("status-watch");
1371
1555
  let text;
1372
1556
  try {
1373
1557
  if (kind === "light" && snapshot) await refreshLightFacts(snapshot, json);
1374
- else snapshot = await readStatus(WATCH_GIT_MAX_AGE_MS, sources?.simulatorListing());
1558
+ else {
1559
+ let stamp = null;
1560
+ try {
1561
+ stamp = statSync$1(archiveRoot()).mtimeMs;
1562
+ } catch {}
1563
+ if (archives === void 0 || stamp !== archiveStamp) {
1564
+ archives = readArchives();
1565
+ archiveStamp = stamp;
1566
+ }
1567
+ snapshot = await readStatus(WATCH_GIT_MAX_AGE_MS, sources?.simulatorListing(), archives);
1568
+ }
1375
1569
  measurer.schedule(snapshot.states, snapshot.worktrees);
1376
1570
  text = renderStatus(snapshot, json).join("\n");
1377
1571
  } catch (error) {
@@ -1431,7 +1625,7 @@ function lastBuildText(report) {
1431
1625
  return `${report.platform} ${report.status === "ok" ? source : `failed (${report.errorCode ?? "error"}), ${source}`}${took}${placement}`;
1432
1626
  }
1433
1627
  function idleShutdownSuffix(record) {
1434
- return record ? chalk.dim(` -- shut down after ${record.idleMinutes}m idle at ${record.at} (devices.idleShutdownMinutes)`) : "";
1628
+ 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"})`) : "";
1435
1629
  }
1436
1630
  function activitySuffix(activity) {
1437
1631
  const label = activityLabel(activity, Date.now());
@@ -1649,7 +1843,7 @@ async function supervisorFacts(path, proj, metroResolution, lookup) {
1649
1843
  };
1650
1844
  }
1651
1845
  function logFacts(path) {
1652
- const dir = workspaceLogsDir(path);
1846
+ const dir = workspaceLogsDir$1(path);
1653
1847
  if (!existsSync$1(dir)) return null;
1654
1848
  try {
1655
1849
  return {
@@ -1,3 +1,3 @@
1
- import { u as resolveSupervisorTarget } from "./stop-cause-CZ_Mr-v9.mjs";
2
- import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-Bad61z_2.mjs";
1
+ import { t as resolveSupervisorTarget } from "./ownership-BMLqyBgJ.mjs";
2
+ import { a as resolveCollectorTargets, c as stopWorkspaceNow, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-BjizrQwv.mjs";
3
3
  export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop, stopWorkspaceNow };
@@ -1,28 +1,31 @@
1
- import { B as parseDeviceSlotKey, D as withConfigLock, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
1
+ import { B as parseDeviceSlotKey, D as withConfigLock$1, E as upsertProject, H as projectDeviceSlots, V as parseDeviceSlotOption, W as validateDeviceSlot, o as clearSupervisor, p as getProject, z as deviceSlotPlatforms } from "./config-D0DbpZtM.mjs";
2
2
  import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
3
- import { b as workspaceDir, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-CL2V2Ons.mjs";
4
- import { i as findCommandWorkspace } from "./project-CV3tDFHl.mjs";
5
- import { a as clearRemoteSession, c as readMetroTunnel, i as clearManagedMetroTunnel, o as clearWorkspaceLaunches, s as clearWorkspaceSupervisor, u as readRemoteSession } from "./state-CaeaHbDA.mjs";
6
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
7
- import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CliHHn7a.mjs";
8
- import { n as fileLeaseIo, u as releaseWorkspaceLeases } from "./device-lease-W5Pi1q38.mjs";
9
- import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-Di8EN2Tb.mjs";
10
- import { a as teardownOwnedBrowser, i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-BYuQafiA.mjs";
11
- import { a as logVanishedSupervisor, l as withdrawDevServerStopRequest, p as stopTunnel, s as requestDevServerStop, u as resolveSupervisorTarget } from "./stop-cause-CZ_Mr-v9.mjs";
12
- import { n as verifyCollectorOwnership } from "./ownership-BkYxUtuj.mjs";
13
- import { t as stopMacosApp } from "./stop-Bvf1MflS.mjs";
14
- import { f as resolveEasCliBin } from "./remote-cache-CO2elm_b.mjs";
15
- import { i as endRecordedSession } from "./device-remote-9ulPsdhY.mjs";
16
- import { a as decideStopAction, c as nativeRunWaitNotice, i as clearNativeRunCancel, l as requestNativeRunCancel, n as NATIVE_RUN_WAIT_MS, o as describeNativeRunHolder, s as nativeRunHolder, t as NATIVE_RUN_LOCK } from "./native-run-DFDoIRbY.mjs";
3
+ import { f as refuseNoProject, l as phaseLine, p as releasedLeaseFact, u as plural } from "./command-output-CDAIFD-8.mjs";
4
+ import { o as findCommandWorkspace } from "./project-D47Rh0ly.mjs";
5
+ import { l as resolveProjectMetro, o as pidExists, r as killMetroTree, u as signalProcessTree } from "./metro-g8NqiJp-.mjs";
6
+ import { a as updateWorkspaceState, c as writeWorkspaceState, n as clearWorkspaceStateKeys, o as withWorkspaceStateLock, r as readWorkspaceState$1, v as workspaceDir } from "./workspace-state-DqcCbpE7.mjs";
7
+ import { n as fileLeaseIo, u as releaseWorkspaceLeases } from "./device-lease-DpoS36_u.mjs";
8
+ import { a as clearRemoteSession, c as readMetroTunnel, i as clearManagedMetroTunnel, o as clearWorkspaceLaunches, s as clearWorkspaceSupervisor, u as readRemoteSession } from "./state-BKa8wNN5.mjs";
9
+ import { g as teardownOwnedIosSim, h as teardownOwnedBrowser, i as stopTunnel, m as teardownOwnedAvd, t as resolveSupervisorTarget } from "./ownership-BMLqyBgJ.mjs";
10
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-2mNzOlaB.mjs";
11
+ import { a as logVanishedSupervisor, l as withdrawDevServerStopRequest, s as requestDevServerStop } from "./stop-cause-rhmGfwvt.mjs";
12
+ import { n as verifyCollectorOwnership } from "./ownership-DyRQru0q.mjs";
13
+ import { t as stopMacosApp } from "./stop-Cr1d8DSE.mjs";
14
+ import { i as stopHostedAndroid } from "./hosted-android-DwLS4Mse.mjs";
15
+ import { f as resolveEasCliBin } from "./remote-cache-Ci4DQYYj.mjs";
16
+ import { i as endRecordedSession } from "./device-remote-hFSkpfQu.mjs";
17
+ import { a as decideStopAction, c as nativeRunWaitNotice, i as clearNativeRunCancel, l as requestNativeRunCancel, n as NATIVE_RUN_WAIT_MS, o as describeNativeRunHolder, s as nativeRunHolder, t as NATIVE_RUN_LOCK } from "./native-run-D1Q56rAD.mjs";
18
+ import { r as stopHostedIos } from "./hosted-ios-aMo7Cljf.mjs";
19
+ import { hostedAndroidDeviceName, hostedAndroidRecords, hostedIosRecords, hostedNativeRecords, isJsonObject, parseHostedNativePlacement } from "@stim-cli/core/state";
17
20
  import chalk from "chalk";
18
21
  //#region src/commands/stop.ts
19
22
  const DEFAULT_WAIT_MS = 1e4;
20
23
  function readSupervisorState(root) {
21
- const sup = readWorkspaceState(root)?.supervisor;
24
+ const sup = readWorkspaceState$1(root)?.supervisor;
22
25
  return sup && typeof sup === "object" ? sup : null;
23
26
  }
24
27
  function readCollectorState(root) {
25
- const collectors = readWorkspaceState(root)?.collectors;
28
+ const collectors = readWorkspaceState$1(root)?.collectors;
26
29
  return collectors && typeof collectors === "object" ? collectors : {};
27
30
  }
28
31
  function clearSupervisorState(root, expected) {
@@ -34,7 +37,7 @@ function clearSupervisorState(root, expected) {
34
37
  }
35
38
  function clearCollectorState(root, expected) {
36
39
  return withWorkspaceStateLock(root, () => {
37
- const current = { ...readWorkspaceState(root)?.collectors };
40
+ const current = { ...readWorkspaceState$1(root)?.collectors };
38
41
  if (expected === void 0) {
39
42
  clearWorkspaceStateKeys(root, ["collectors"]);
40
43
  return true;
@@ -156,6 +159,7 @@ async function runStop(options) {
156
159
  clearRegistration: async () => true,
157
160
  teardownBrowser: null,
158
161
  stopMacos: false,
162
+ hostedSlot: slot,
159
163
  releaseLeases: (projectRoot) => releaseWorkspaceLeases(projectRoot, { slot })
160
164
  });
161
165
  result.outcomes.port = {
@@ -214,8 +218,39 @@ async function stopBrowserOnly({ root, project = void 0, teardownBrowser = (proj
214
218
  summary: summarize(root, outcomes, ok)
215
219
  };
216
220
  }
221
+ async function stopWorkspaceHostedNative(root, slot, report, failed) {
222
+ const devices = {};
223
+ let anyFailed = false;
224
+ for (const platform of ["ios", "android"]) for (const [name, record] of Object.entries(hostedNativeRecords(readWorkspaceState$1(root), platform))) {
225
+ if (slot !== void 0 && name !== slot) continue;
226
+ const placement = parseHostedNativePlacement(record, platform);
227
+ const label = placement ? `${placement.device ? "udid" in placement.device ? placement.device.name : hostedAndroidDeviceName(placement.device) : `${platform} device`} on ${placement.machine}` : `hosted ${platform === "ios" ? "iOS simulator" : "Android emulator"} for slot ${name}`;
228
+ try {
229
+ await (platform === "ios" ? stopHostedIos : stopHostedAndroid)(root, name);
230
+ devices[`${platform}:host:${name}`] = {
231
+ status: "shut-down",
232
+ label
233
+ };
234
+ report(chalk.dim(phaseLine("device", `stopped ${label}`)));
235
+ } catch (error) {
236
+ const reason = error.message;
237
+ devices[`${platform}:host:${name}`] = {
238
+ status: "failed",
239
+ label,
240
+ reason
241
+ };
242
+ report(chalk.red(phaseLine("device", reason)));
243
+ failed();
244
+ anyFailed = true;
245
+ }
246
+ }
247
+ return {
248
+ devices,
249
+ failed: anyFailed
250
+ };
251
+ }
217
252
  async function stopWorkspaceMacos(root, failed, enabled) {
218
- if (enabled === false || readWorkspaceState(root)?.macos === void 0) return void 0;
253
+ if (enabled === false || readWorkspaceState$1(root)?.macos === void 0) return void 0;
219
254
  try {
220
255
  await stopMacosApp(root);
221
256
  return { status: "stopped" };
@@ -228,7 +263,7 @@ async function stopWorkspaceMacos(root, failed, enabled) {
228
263
  };
229
264
  }
230
265
  }
231
- async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid) => signalProcessTree(pid), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
266
+ async function stopWorkspace({ root, project = void 0, state = void 0, collectors = void 0, signalCollector = (pid) => signalProcessTree(pid), verifyCollector = verifyCollectorOwnership, clearCollectors = clearCollectorState, isAlive = pidExists, killGroup = killMetroTree, signalServer = (pid) => signalProcessTree(pid), inspectIdentity = process_identity_exports.inspectProcessIdentity, waitForDeath = void 0, waitMs = DEFAULT_WAIT_MS, resolveMetro = resolveProjectMetro, teardownIos = teardownOwnedIosSim, teardownAvd = teardownOwnedAvd, teardownBrowser = (projectRoot) => teardownOwnedBrowser(projectRoot), stopMacos, hostedSlot, remoteDevice = void 0, teardownRemoteSession = defaultTeardownRemoteSession, metroTunnel = void 0, stopMetroTunnel = stopTunnel, releaseLeases = releaseWorkspaceLeases, freePort = defaultFreePort, clearRegistration = defaultClearRegistration, clearState = clearSupervisorState, report = (line) => console.error(line) }) {
232
267
  const proj = project === void 0 ? getProject(root) : project;
233
268
  const sup = state === void 0 ? readSupervisorState(root) : state;
234
269
  const collectorRecords = collectors === void 0 ? readCollectorState(root) : collectors;
@@ -389,6 +424,25 @@ async function stopWorkspace({ root, project = void 0, state = void 0, collector
389
424
  ok = false;
390
425
  report(reason);
391
426
  }, stopMacos);
427
+ const hosted = await stopWorkspaceHostedNative(root, hostedSlot, report, () => {
428
+ ok = false;
429
+ });
430
+ Object.assign(outcomes.device, hosted.devices);
431
+ updateWorkspaceState(root, (workspace) => {
432
+ const slots = isJsonObject(workspace.deviceSlots) ? workspace.deviceSlots : {};
433
+ for (const name of ["default", ...Object.keys(slots)]) {
434
+ if (hostedSlot !== void 0 && name !== hostedSlot) continue;
435
+ const records = name === "default" ? workspace : slots[name];
436
+ if (!isJsonObject(records)) continue;
437
+ for (const platform of ["ios", "android"]) {
438
+ const hostOutcome = outcomes.device[`${platform}:host:${name}`];
439
+ if (hostOutcome?.status === "failed" || stillHolding && hostOutcome?.status !== "shut-down") continue;
440
+ if (outcomes.device[name === "default" || hostedSlot !== void 0 ? platform : `${platform}:${name}`]?.status === "failed") continue;
441
+ if (isJsonObject(records[platform])) delete records[platform].devicePlacement;
442
+ }
443
+ }
444
+ return workspace;
445
+ });
392
446
  const remote = remoteDevice === void 0 ? readRemoteSession(root) : remoteDevice;
393
447
  const sessionId = typeof remote?.sessionId === "string" ? remote.sessionId : null;
394
448
  if (sessionId) {
@@ -795,7 +849,7 @@ function summarize(root, outcomes, ok) {
795
849
  return `${ok ? "Stopped" : "Stopped with problems"}: ${what} (${root})`;
796
850
  }
797
851
  function defaultFreePort(root, port) {
798
- return withConfigLock(() => {
852
+ return withConfigLock$1(() => {
799
853
  const current = getProject(root);
800
854
  if (!current) return true;
801
855
  if (current.supervisor || current.metroPort !== port) return false;
@@ -836,10 +890,18 @@ function recordedDeviceSlots(root) {
836
890
  const parsed = parseDeviceSlotKey(key);
837
891
  if (parsed) slots.add(parsed.slot);
838
892
  }
893
+ for (const slot of Object.keys({
894
+ ...hostedIosRecords(readWorkspaceState$1(root)),
895
+ ...hostedAndroidRecords(readWorkspaceState$1(root))
896
+ })) slots.add(slot);
839
897
  return [...slots].toSorted();
840
898
  }
841
899
  function workspaceDeviceSlots(root) {
842
900
  const slots = projectDeviceSlots(getProject(root)).filter(({ platforms }) => Object.values(platforms).some(Boolean)).map(({ slot }) => slot);
901
+ for (const slot of Object.keys({
902
+ ...hostedIosRecords(readWorkspaceState$1(root)),
903
+ ...hostedAndroidRecords(readWorkspaceState$1(root))
904
+ })) if (!slots.includes(slot)) slots.push(slot);
843
905
  if (typeof readRemoteSession(root)?.sessionId === "string" && !slots.includes("default")) slots.push("default");
844
906
  return slots;
845
907
  }