stim 1.16.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 (107) hide show
  1. package/dist/{activity-BxwdD81S.mjs → activity-IRvJY_ru.mjs} +23 -3
  2. package/dist/{agent-device-usage-output-Dpih1Tfa.mjs → agent-device-usage-output-BK41vnzN.mjs} +3 -3
  3. package/dist/{android-Ift4kVvt.mjs → android--GorydsK.mjs} +679 -317
  4. package/dist/{android-B_NumVyQ.mjs → android-B_YNZy61.mjs} +7 -43
  5. package/dist/{android-r2rBL8kV.mjs → android-DE4v59Mb.mjs} +12 -3
  6. package/dist/{android-cas-8U4DPqeR.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
  7. package/dist/{app-install-CKWdbXIX.mjs → app-install-VPkI5WEg.mjs} +6 -5
  8. package/dist/{budget-DjrURfQn.mjs → budget-DM984mnd.mjs} +34 -18
  9. package/dist/{build-plan-DjeSb2Xl.mjs → build-plan-CmQCoyT-.mjs} +345 -86
  10. package/dist/{build-slots-rUk77xqh.mjs → build-slots-41v_d2x9.mjs} +35 -25
  11. package/dist/{cli-BkYZ_6hy.mjs → cli-Daxug5-K.mjs} +17 -17
  12. package/dist/cli.mjs +1 -1
  13. package/dist/collector-run.mjs +3 -3
  14. package/dist/{command-output-DnJMdEY-.mjs → command-output-CDAIFD-8.mjs} +3 -3
  15. package/dist/{created-devices-D5owjN4C.mjs → created-devices-CpvzBL25.mjs} +1 -1
  16. package/dist/{dependency-state-B6cMXZab.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
  17. package/dist/{deps-urbmfXig.mjs → deps-DNWaQs4V.mjs} +1 -1
  18. package/dist/{dev-client-CroAIjjj.mjs → dev-client-B-XC4uRH.mjs} +2 -2
  19. package/dist/{device-DZQjF7H5.mjs → device-C8IOoJPv.mjs} +7 -7
  20. package/dist/device-capacity-D0GWHnTM.mjs +580 -0
  21. package/dist/device-host-worker.mjs +436 -154
  22. package/dist/{device-ios-BadmeL2V.mjs → device-ios-Bc7vbGwl.mjs} +75 -44
  23. package/dist/{device-lease-D-hLqx1b.mjs → device-lease-DpoS36_u.mjs} +2 -2
  24. package/dist/{device-lease-run-CqjShqWW.mjs → device-lease-run-B8YltIH_.mjs} +3 -3
  25. package/dist/{device-pool-CUaEWMMm.mjs → device-pool-3o7s5lo4.mjs} +2 -2
  26. package/dist/{device-remote-D5WVWqOq.mjs → device-remote-hFSkpfQu.mjs} +12 -12
  27. package/dist/{doctor-Cimf-gGB.mjs → doctor-Cnk9d7Hm.mjs} +32 -51
  28. package/dist/{error-diagnostics-B9L4Ae0x.mjs → error-diagnostics-C-NMnhrk.mjs} +7 -7
  29. package/dist/{gc-Bqy4bjEu.mjs → gc-DxCL2A46.mjs} +308 -26
  30. package/dist/{gradle-BsO1MdsH.mjs → gradle-D7-L2Th3.mjs} +3 -3
  31. package/dist/{guide-B_uyKTxW.mjs → guide-DjrTQGik.mjs} +1662 -565
  32. package/dist/{guide-status-CjEZMAD4.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
  33. package/dist/hosted-android-DwLS4Mse.mjs +32 -0
  34. package/dist/{hosted-client-a-WmqE2L.mjs → hosted-client-wk1W_CNW.mjs} +2 -3
  35. package/dist/hosted-ios-aMo7Cljf.mjs +15 -0
  36. package/dist/{hosted-logs-D5g041Q3.mjs → hosted-logs-DqYmWtXc.mjs} +16 -16
  37. package/dist/{hosted-macos-BSZyIb3y.mjs → hosted-macos-dlHXEeF5.mjs} +4 -4
  38. package/dist/{hosted-ios-CIWelIqf.mjs → hosted-native-C9xJ9rpA.mjs} +77 -42
  39. package/dist/{idle-DYVymG92.mjs → idle-B2m-Ovod.mjs} +122 -58
  40. package/dist/{idle-shutdown-CTsDnAde.mjs → idle-shutdown-_3oOV1V_.mjs} +25 -17
  41. package/dist/{in-use-DvBw0Kxo.mjs → in-use-CvGOUn-x.mjs} +11 -11
  42. package/dist/{ios-aq3QoGI3.mjs → ios-DE6duQoz.mjs} +170 -88
  43. package/dist/{ios-BaInn3sW.mjs → ios-DSfnPfse.mjs} +4 -4
  44. package/dist/{ios-device-FfCN_C8p.mjs → ios-device-pAN4t54-.mjs} +1 -1
  45. package/dist/ios-state-8L3lgum6.mjs +89 -0
  46. package/dist/{launch-verify-2DBRizjo.mjs → launch-verify-lTnWZikR.mjs} +2 -2
  47. package/dist/{logs-CHEVK8zD.mjs → logs-DUoKlDoS.mjs} +36 -23
  48. package/dist/{client-BTY686R6.mjs → machines-C2XiNwh9.mjs} +278 -20
  49. package/dist/{macos-CSYEAFmF.mjs → macos-32po3kUq.mjs} +14 -14
  50. package/dist/macos-run.mjs +1 -1
  51. package/dist/maintenance-run.mjs +2 -2
  52. package/dist/{metro-BeK1ZPz1.mjs → metro-g8NqiJp-.mjs} +1 -1
  53. package/dist/{metro-gateway-BJ-rxQAB.mjs → metro-gateway-DmslUM30.mjs} +22 -3
  54. package/dist/{named-ports-Bk_YXEmE.mjs → named-ports-C8m8EQs2.mjs} +2 -2
  55. package/dist/{native-run-NaBrRFtQ.mjs → native-run-D1Q56rAD.mjs} +17 -6
  56. package/dist/{native-runtime-DBzRnEKS.mjs → native-runtime-DhJI3IVQ.mjs} +6 -6
  57. package/dist/offload-worker.mjs +8 -8
  58. package/dist/{teardown-CL6vDs2Y.mjs → ownership-BMLqyBgJ.mjs} +603 -26
  59. package/dist/{ownership-DiA16AsN.mjs → ownership-DyRQru0q.mjs} +2 -2
  60. package/dist/{ports-R2k4Knz3.mjs → ports-4nYqxPWC.mjs} +2 -2
  61. package/dist/{prebuild-D2fsca_Z.mjs → prebuild-D7RUMkwN.mjs} +3 -3
  62. package/dist/{preview-DhVbvPAZ.mjs → preview-CxPRIEht.mjs} +7 -7
  63. package/dist/{project-Du91Ilvc.mjs → project-D47Rh0ly.mjs} +7 -2
  64. package/dist/{recordings-BIXOzVnr.mjs → recordings-BNgsD1Tr.mjs} +1 -1
  65. package/dist/{reload-rM9jV1fz.mjs → reload-qZei6iWn.mjs} +62 -35
  66. package/dist/{remote-cache-C8-V13XN.mjs → remote-cache-Ci4DQYYj.mjs} +3 -3
  67. package/dist/{run-f4vI6EnK.mjs → run-CkE9y0nc.mjs} +1 -1
  68. package/dist/{server-bare-CpPGmnmO.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
  69. package/dist/{server-expo-MC0rHlOC.mjs → server-expo-CHTyXD0G.mjs} +2 -2
  70. package/dist/server-expo-CeakhI8P.mjs +2 -0
  71. package/dist/{settings-oTSkkNrM.mjs → settings-Cfd-0r2d.mjs} +10 -9
  72. package/dist/{settings-ZkDzkzvB.mjs → settings-SR9OmW9h.mjs} +3 -3
  73. package/dist/settings.schema.json +42 -13
  74. package/dist/{simslim-B8-7AoTI.mjs → simslim-BWNrc3M3.mjs} +3 -3
  75. package/dist/{slot-launch-B8VrHxn1.mjs → slot-launch-DmjBmpQV.mjs} +8 -8
  76. package/dist/{start-CX8Ig-U2.mjs → start-BopZcr4n.mjs} +1 -1
  77. package/dist/{start-ClDfwXa4.mjs → start-uee1wWjY.mjs} +11 -11
  78. package/dist/{state-DcW6vOd_.mjs → state-BKa8wNN5.mjs} +1 -1
  79. package/dist/{state-3DwSQIBK.mjs → state-DyaNTgfR.mjs} +1 -1
  80. package/dist/{state-C1jB7Q8q.mjs → state-PeQiJuIu.mjs} +2 -2
  81. package/dist/{stats-CEZ_i5je.mjs → stats-Bq4fJOdB.mjs} +7 -4
  82. package/dist/{status-BuvBFeII.mjs → status-CzS4bPO9.mjs} +4 -4
  83. package/dist/{status-Cs7VLg9D.mjs → status-dXX2JX1C.mjs} +125 -35
  84. package/dist/{stop-Dt_dM16A.mjs → stop-BCwvvs7F.mjs} +2 -2
  85. package/dist/{stop-Bffozsac.mjs → stop-BjizrQwv.mjs} +48 -27
  86. package/dist/{stop-B0Yxtmiy.mjs → stop-Cr1d8DSE.mjs} +4 -4
  87. package/dist/{stop-cause-CidxIqup.mjs → stop-cause-rhmGfwvt.mjs} +1 -1
  88. package/dist/supervisor-run.d.mts +7 -4
  89. package/dist/supervisor-run.mjs +26 -28
  90. package/dist/{support-D4aYJniO.mjs → support-BJPgYCu-.mjs} +44 -19
  91. package/dist/{support-CAP8qDUF.mjs → support-F9-sr0Oi.mjs} +6 -6
  92. package/dist/{toolchain-DkUflduf.mjs → toolchain-CNIBTIOv.mjs} +7 -7
  93. package/dist/{warm-progress-CpGv3Wb6.mjs → warm-progress-DF4JRvYI.mjs} +3 -3
  94. package/dist/watchman-APYjXSQa.mjs +48 -0
  95. package/dist/{web-DWUaMp8P.mjs → web-exQtGkoc.mjs} +12 -13
  96. package/dist/web-run.mjs +4 -4
  97. package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
  98. package/dist/{workspace-state-B8-aJ1_5.mjs → workspace-state-DqcCbpE7.mjs} +2 -2
  99. package/dist/{workspaces-BV4pdHFz.mjs → workspaces-Bcib97-6.mjs} +3 -3
  100. package/dist/{worktree-jnG8Iph5.mjs → worktree-Dc98cE6_.mjs} +1 -1
  101. package/dist/{worktree-K-xj9Db0.mjs → worktree-ZpZR3S1k.mjs} +141 -40
  102. package/package.json +5 -5
  103. package/dist/device-capacity-BHwxNBlu.mjs +0 -136
  104. package/dist/ios-state-DS5UpYTH.mjs +0 -48
  105. package/dist/machines-BIBUdhpj.mjs +0 -265
  106. package/dist/ownership-hCkPzGmr.mjs +0 -571
  107. package/dist/server-expo-CVqO2c35.mjs +0 -2
@@ -1,34 +1,35 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { A as directorySize, D as withConfigLock$1, F as volumeRootFor, H as projectDeviceSlots, M as isOnMountedVolume, N as listMountedVolumes, S as removeProject, _ as loadConfig$1, j as formatBytes, k as acquireAvdClaim, p as getProject } from "./config-D0DbpZtM.mjs";
3
- import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
3
+ import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
4
4
  import { n as describePullRequest, o as pullRequestLookups, r as endedPullRequest } from "./pull-request-pxnDCQzn.mjs";
5
- import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-DnJMdEY-.mjs";
6
- import { _t as resolveFullRef, bt as sourceCheckoutOf, ct as hasUncommittedWork, dt as listWorktrees, ot as hasPopulatedSubmodules, rt as dirtyPaths, xt as unpushedCommits } from "./settings-oTSkkNrM.mjs";
7
- import { o as findProjectRoot$1, r as detectIsExpo } from "./project-Du91Ilvc.mjs";
8
- import { C as workspaceStateFile, s as workspaceLastUsed, v as workspaceDir, w as withDirLock$1, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
9
- import { A as isWorkspacesScope, B as memoryCacheKind, C as unverifiedDeviceCommand, D as includesParkedDevices, E as includesArchives, F as trimCaches, G as reclaimMemory, H as memoryScope, K as scopedMemoryReport, M as previewScopedEmptying, N as selectCaches, O as includesRecordings, P as selectsBeyondCaches, R as collectMemoryReport, S as findStaleProjectDevices, T as emptyCaches, U as memorySweepIsScoped, V as memoryLines, W as memoryWorkPending, X as discoverCaches, Z as sizeCaches, _ as describeUnverifiableDevices, a as machineNumber, b as findOrphanedDevices, d as collectParkedAvds, f as collectParkedSims, g as describeParkedSims, h as deleteProjectDevices, j as planCacheEmptying, k as includesWorkspaceOutputs, l as DEVICE_LIST_TIMEOUT_MS, m as deleteParkedSims, p as deleteParkedAvds, q as phase, u as collectDeviceLeases, v as deviceSweepIsScoped, w as withAndroidAvdSizes, x as findStaleDeviceRecords, y as eraseParkedDevices } from "./budget-DjrURfQn.mjs";
10
- import { a as takeGcResults, i as recordGcResult, n as withIdleWorkspace, o as canonicalPath, r as workspaceInUse } from "./in-use-DvBw0Kxo.mjs";
11
- import { d as removeExpiredLease, h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-D-hLqx1b.mjs";
12
- import { n as listBuildSlots } from "./build-slots-rUk77xqh.mjs";
13
- import { a as parseIdleDuration, o as shutDownIdleDevices, r as idleDeviceLines, t as collectIdleDevices } from "./idle-DYVymG92.mjs";
14
- import { n as readCreatedDevices$1, t as forgetCreatedDevice } from "./created-devices-D5owjN4C.mjs";
15
- import { A as listAvds, H as parseAvdSystemImage, I as ownedAvdDirectory, M as listOrphanedAvdDirectories, V as parseAvdDeviceProfile, _ as avdStorageRoots, at as isStimOwnedSim, d as androidToolPath, ft as parkedMaxSetting, it as isStimOwnedAvd, j as listInstalledSystemImages, m as avdNameAbsent, o as androidHome, ot as POOL_SETTING_REMEDY, p as avdIniPaths, pt as readParked, z as ownedAvdSerialResolver } from "./android-B_NumVyQ.mjs";
16
- import { u as listAllIosSims } from "./ios-BaInn3sW.mjs";
17
- import { a as collectWorkspaceOutputs, c as listWorkspaceDirs, i as collectOrphanedWorkspaces, l as rootPresence, n as WORKSPACE_OUTPUT_DIRS, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs, s as isInsideWorkspaces, t as REBUILD_COST, u as sizeText } from "./workspaces-BV4pdHFz.mjs";
18
- import { n as previewMaintenance } from "./preview-DhVbvPAZ.mjs";
19
- import { r as readCollectors } from "./ownership-DiA16AsN.mjs";
20
- import { f as resolveEasCliBin } from "./remote-cache-C8-V13XN.mjs";
21
- import { C as listOwnedSessionsArgs, D as verifyStoppedSession, E as stopSessionArgs, S as isDefinitiveMissingSessionError, T as parseSessionListPage, b as getSessionArgs, d as withRemoteSessionLock, f as withEasProjectLock, h as removeEasSessionClaim, m as readEasSessionLedger$1, p as easMachineStateRoot$1, x as inspectSessionForTeardown, y as findOrphanedOwnedSessions } from "./device-remote-D5WVWqOq.mjs";
22
- import { o as fetchDefaultBranch, s as mergeState } from "./warm-progress-CpGv3Wb6.mjs";
23
- import { _ as deleteSelectedArchives, f as removeWorktreeTarget, g as reclaimProject, h as describeDereferenced, i as matchWorktreeEntry, n as excludePodChurn, o as reclaimKeys, r as excludeWatchmanCookies, v as sweepArchiveStaging } from "./worktree-K-xj9Db0.mjs";
24
- import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-Dpih1Tfa.mjs";
5
+ import { h as shortUdid, o as formatLongDuration, u as plural } from "./command-output-CDAIFD-8.mjs";
6
+ import { _t as resolveFullRef, bt as sourceCheckoutOf, ct as hasUncommittedWork, dt as listWorktrees, ot as hasPopulatedSubmodules, rt as dirtyPaths, xt as unpushedCommits } from "./settings-Cfd-0r2d.mjs";
7
+ import { r as detectIsExpo, s as findProjectRoot$1 } from "./project-D47Rh0ly.mjs";
8
+ import { C as workspaceStateFile, s as workspaceLastUsed, v as workspaceDir, w as withDirLock$1, x as workspaceLogsDir$1 } from "./workspace-state-DqcCbpE7.mjs";
9
+ import { A as includesWorkspaceOutputs, C as findStaleProjectDevices, D as includesArchives, E as emptyCaches, F as selectsBeyondCaches, G as memoryWorkPending, H as memoryLines, I as trimCaches, J as phase, K as reclaimMemory, M as planCacheEmptying, N as previewScopedEmptying, O as includesParkedDevices, P as selectCaches, Q as sizeCaches, S as findStaleDeviceRecords, T as withAndroidAvdSizes, U as memoryScope, V as memoryCacheKind, W as memorySweepIsScoped, Z as discoverCaches, _ as describeParkedSims, a as machineNumber, b as eraseParkedDevices, d as collectDeviceLeases, f as collectParkedAvds, g as deleteProjectDevices, h as deleteParkedSims, j as isWorkspacesScope, k as includesRecordings, m as deleteParkedAvds, p as collectParkedSims, q as scopedMemoryReport, u as DEVICE_LIST_TIMEOUT_MS, v as describeUnverifiableDevices, w as unverifiedDeviceCommand, x as findOrphanedDevices, y as deviceSweepIsScoped, z as collectMemoryReport } from "./budget-DM984mnd.mjs";
10
+ import { a as takeGcResults, i as recordGcResult, n as withIdleWorkspace, o as canonicalPath, r as workspaceInUse } from "./in-use-CvGOUn-x.mjs";
11
+ import { d as removeExpiredLease, h as listBuildLocks, i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-DpoS36_u.mjs";
12
+ import { n as listBuildSlots } from "./build-slots-41v_d2x9.mjs";
13
+ import { n as readCreatedDevices$1, t as forgetCreatedDevice } from "./created-devices-CpvzBL25.mjs";
14
+ import { A as listAvds, H as parseAvdSystemImage, I as ownedAvdDirectory, M as listOrphanedAvdDirectories, V as parseAvdDeviceProfile, _ as avdStorageRoots, at as isStimOwnedSim, d as androidToolPath, ft as parkedMaxSetting, it as isStimOwnedAvd, j as listInstalledSystemImages, m as avdNameAbsent, o as androidHome, ot as POOL_SETTING_REMEDY, p as avdIniPaths, pt as readParked, z as ownedAvdSerialResolver } from "./android-B_YNZy61.mjs";
15
+ import { u as listAllIosSims } from "./ios-DSfnPfse.mjs";
16
+ import { a as parseIdleDuration, o as shutDownIdleDevices, r as idleDeviceLines, t as collectIdleDevices } from "./idle-B2m-Ovod.mjs";
17
+ import { a as collectWorkspaceOutputs, c as listWorkspaceDirs, i as collectOrphanedWorkspaces, l as rootPresence, n as WORKSPACE_OUTPUT_DIRS, o as deleteOrphanedWorkspaces, r as clearWorkspaceOutputs, s as isInsideWorkspaces, t as REBUILD_COST, u as sizeText } from "./workspaces-Bcib97-6.mjs";
18
+ import { n as previewMaintenance } from "./preview-CxPRIEht.mjs";
19
+ import { r as readCollectors } from "./ownership-DyRQru0q.mjs";
20
+ import { f as resolveEasCliBin } from "./remote-cache-Ci4DQYYj.mjs";
21
+ import { C as listOwnedSessionsArgs, D as verifyStoppedSession, E as stopSessionArgs, S as isDefinitiveMissingSessionError, T as parseSessionListPage, b as getSessionArgs, d as withRemoteSessionLock, f as withEasProjectLock, h as removeEasSessionClaim, m as readEasSessionLedger$1, p as easMachineStateRoot$1, x as inspectSessionForTeardown, y as findOrphanedOwnedSessions } from "./device-remote-hFSkpfQu.mjs";
22
+ import { o as fetchDefaultBranch, s as mergeState } from "./warm-progress-DF4JRvYI.mjs";
23
+ import { _ as deleteSelectedArchives, f as removeWorktreeTarget, g as reclaimProject, h as describeDereferenced, i as matchWorktreeEntry, n as excludePodChurn, o as reclaimKeys, r as excludeWatchmanCookies, v as sweepArchiveStaging } from "./worktree-ZpZR3S1k.mjs";
24
+ import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-BK41vnzN.mjs";
25
25
  import { existsSync, lstatSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
26
26
  import { basename, dirname, join } from "node:path";
27
27
  import { closeSync as closeSync$1, existsSync as existsSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, readdirSync as readdirSync$1, renameSync as renameSync$1, rmSync as rmSync$1, statSync as statSync$1, utimesSync as utimesSync$1, writeFileSync as writeFileSync$1 } from "fs";
28
28
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1 } from "path";
29
29
  import { LOG_ROTATE_BYTES, rotatedLogPath } from "@stim-cli/core";
30
30
  import { InvalidArgumentError } from "commander";
31
- import { listRecordedDevices, listStatusCacheEntries, maintenanceRunClaims, readArchives, recordedBytes, settingDefinition } from "@stim-cli/core/state";
31
+ import { assertHostedDeviceLedger, deviceHostArea, deviceHostRoot, hostedDeviceId, isJsonObject, listRecordedDevices, listStatusCacheEntries, maintenanceRunClaims, parseHostedPlatformDevice, readArchives, readHostedDevice, readHostedDeviceLedger, readHostedSessions, recordedBytes, settingDefinition } from "@stim-cli/core/state";
32
+ import { fileURLToPath } from "node:url";
32
33
  import chalk from "chalk";
33
34
  //#region src/commands/gc/archives.ts
34
35
  function stagingOrNone() {
@@ -1214,6 +1215,16 @@ function formatParkedAvdReport(parkedAvds, now, erase) {
1214
1215
  lines.push(erase ? PARKED_ERASE_NOTE : PARKED_DELETE_NOTE);
1215
1216
  return lines;
1216
1217
  }
1218
+ function formatParkedHostedDeviceReport(devices = [], now) {
1219
+ if (!devices.length) return [];
1220
+ const lines = [`Parked hosted devices (${devices.length}):`];
1221
+ for (const device of devices) {
1222
+ const ledger = device.listed === true ? "" : device.listed === false ? " - already removed; stim-server clears the marker" : " - ledger ownership unavailable; kept";
1223
+ lines.push(` ${device.platform} ${device.name ?? "unknown device"} client ${device.client} session ${device.session} ${parkedAge(device.parkedAt, now)}${ledger}`);
1224
+ }
1225
+ lines.push(PARKED_DELETE_NOTE);
1226
+ return lines;
1227
+ }
1217
1228
  function projectEntryLines(header, paths) {
1218
1229
  return paths.length ? [header, ...paths.map((path) => ` ${path}`)] : [];
1219
1230
  }
@@ -1242,7 +1253,7 @@ function maintenanceReportLines(maintenance) {
1242
1253
  }
1243
1254
  return lines;
1244
1255
  }
1245
- function formatGcReport({ maintenance, archives, skipped = [], deadProjects = [], orphanedPorts, invalidProjects = [], orphanedWorkspaces = [], parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1256
+ function formatGcReport({ maintenance, archives, skipped = [], deadProjects = [], orphanedPorts, invalidProjects = [], orphanedWorkspaces = [], parkedSims = [], parkedAvds = [], parkedHostedDevices, orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1246
1257
  stale: [],
1247
1258
  live: [],
1248
1259
  unresolved: []
@@ -1260,6 +1271,7 @@ function formatGcReport({ maintenance, archives, skipped = [], deadProjects = []
1260
1271
  deletionSafe: true
1261
1272
  }, agentDeviceUsage = null, swiftpmCacheUsage, caches = [], workspaceOutputs = null, workspaceLogs = [], recordings = [], worktreeSweep = null, memory, cacheScope = null, olderThan = null }, { now = Date.now() } = {}) {
1262
1273
  const lines = archiveLines(archives);
1274
+ const parkedHostedLines = formatParkedHostedDeviceReport(parkedHostedDevices, now);
1263
1275
  const staleLocks = buildLocks?.stale ?? [];
1264
1276
  const liveLocks = buildLocks?.live ?? [];
1265
1277
  const staleSlots = buildSlots?.stale ?? [];
@@ -1271,6 +1283,7 @@ function formatGcReport({ maintenance, archives, skipped = [], deadProjects = []
1271
1283
  orphanedWorkspaces,
1272
1284
  parkedSims,
1273
1285
  parkedAvds,
1286
+ parkedHostedLines,
1274
1287
  orphanedDevices,
1275
1288
  staleDevices,
1276
1289
  staleDeviceRecords,
@@ -1298,6 +1311,7 @@ function formatGcReport({ maintenance, archives, skipped = [], deadProjects = []
1298
1311
  lines.push(...worktreeSweepLines(worktreeSweep));
1299
1312
  lines.push(...formatParkedSimReport(parkedSims, now, cacheScope !== null));
1300
1313
  lines.push(...formatParkedAvdReport(parkedAvds, now, cacheScope !== null));
1314
+ lines.push(...parkedHostedLines);
1301
1315
  if (orphanedDevices.length) {
1302
1316
  lines.push(`Orphaned devices (${orphanedDevices.length}):`);
1303
1317
  for (const d of orphanedDevices) lines.push(` ${d.kind} ${d.name} (${d.id})${deviceSizeSuffix(d)}`);
@@ -1513,7 +1527,7 @@ function jsonPullRequest(lookup) {
1513
1527
  containsHead: pr.containsHead
1514
1528
  } : null;
1515
1529
  }
1516
- function gcReportSections({ archives, skipped = [], deadProjects = [], orphanedPorts = [], invalidProjects = [], orphanedWorkspaces = [], worktreeSweep = null, parkedSims = [], parkedAvds = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1530
+ function gcReportSections({ archives, skipped = [], deadProjects = [], orphanedPorts = [], invalidProjects = [], orphanedWorkspaces = [], worktreeSweep = null, parkedSims = [], parkedAvds = [], parkedHostedDevices = [], orphanedDevices = [], unverifiedDevices = [], staleDevices = [], staleDeviceRecords = [], staleLedgerEntries = [], staleStatusCaches = [], buildLocks = {
1517
1531
  stale: [],
1518
1532
  live: [],
1519
1533
  unresolved: []
@@ -1577,6 +1591,7 @@ function gcReportSections({ archives, skipped = [], deadProjects = [], orphanedP
1577
1591
  bytes,
1578
1592
  listed
1579
1593
  })),
1594
+ parkedHostedDevices,
1580
1595
  orphanedDevices: orphanedDevices.map((d) => ({
1581
1596
  kind: d.kind,
1582
1597
  id: d.id,
@@ -2205,6 +2220,266 @@ function collectInventory(config, deadProjects) {
2205
2220
  };
2206
2221
  }
2207
2222
  //#endregion
2223
+ //#region src/commands/gc/hosted-devices.ts
2224
+ function collectParkedHostedDevices({ olderThanDays = null, now = Date.now() } = {}) {
2225
+ const notices = [];
2226
+ let sessions;
2227
+ try {
2228
+ try {
2229
+ statSync(join(deviceHostRoot(), "sessions.json"));
2230
+ } catch (error) {
2231
+ if (error.code === "ENOENT") return {
2232
+ devices: [],
2233
+ notices
2234
+ };
2235
+ throw error;
2236
+ }
2237
+ sessions = readHostedSessions();
2238
+ } catch (error) {
2239
+ return {
2240
+ devices: [],
2241
+ notices: [`Hosted session journal unreadable; devices kept: ${describeError(error)}`]
2242
+ };
2243
+ }
2244
+ const devices = [];
2245
+ for (const record of sessions) {
2246
+ if (!record.parked || record.platform === "macos") continue;
2247
+ if (olderThanDays !== null && now - Date.parse(record.parked.at) < olderThanDays * 864e5) continue;
2248
+ const id = record.device ? hostedDeviceId(record.device) : null;
2249
+ let listed = null;
2250
+ try {
2251
+ const ledger = readHostedDeviceLedger(join(deviceHostArea(record.id), "home"));
2252
+ listed = ledger !== null && id !== null && ledger[record.platform].includes(id);
2253
+ } catch (error) {
2254
+ notices.push(`Hosted session ${record.id} ledger unreadable; device kept: ${describeError(error)}`);
2255
+ }
2256
+ devices.push({
2257
+ session: record.id,
2258
+ client: record.client,
2259
+ platform: record.platform,
2260
+ id,
2261
+ name: record.device && "name" in record.device ? record.device.name : id,
2262
+ parkedAt: record.parked.at,
2263
+ listed
2264
+ });
2265
+ }
2266
+ return {
2267
+ devices,
2268
+ notices
2269
+ };
2270
+ }
2271
+ async function stopHostedDevice(record, claim) {
2272
+ const home = join(deviceHostArea(record.id), "home");
2273
+ (0, ownership_claim_exports.markClaimChildPending)(claim);
2274
+ let child;
2275
+ try {
2276
+ child = getExecutor().spawn(process.execPath, [join(dirname(fileURLToPath(import.meta.url)), "device-host-worker.mjs")], {
2277
+ cwd: home,
2278
+ env: {
2279
+ ...process.env,
2280
+ STIM_HOME: home
2281
+ },
2282
+ detached: true,
2283
+ stdio: [
2284
+ "pipe",
2285
+ "pipe",
2286
+ "pipe"
2287
+ ]
2288
+ });
2289
+ } catch (error) {
2290
+ (0, ownership_claim_exports.clearClaimChild)(claim);
2291
+ return {
2292
+ settled: true,
2293
+ value: null,
2294
+ notice: describeError(error)
2295
+ };
2296
+ }
2297
+ let identity = null;
2298
+ let closed = false;
2299
+ let output = "";
2300
+ let stderr = "";
2301
+ let notice;
2302
+ let timer;
2303
+ let killTimer;
2304
+ let groupTimer;
2305
+ let finished = false;
2306
+ let cancelling = false;
2307
+ let finishTimer;
2308
+ return await new Promise((resolve) => {
2309
+ const finish = () => {
2310
+ if (finished) return;
2311
+ finished = true;
2312
+ clearTimeout(timer);
2313
+ clearTimeout(killTimer);
2314
+ clearTimeout(finishTimer);
2315
+ clearTimeout(groupTimer);
2316
+ const settled = closed && (!child.pid || !(0, ownership_claim_exports.processGroupAlive)(child.pid));
2317
+ if (settled) (0, ownership_claim_exports.clearClaimChild)(claim);
2318
+ let value = null;
2319
+ try {
2320
+ value = JSON.parse(output);
2321
+ } catch {
2322
+ notice ??= stderr.trim() || "Hosted worker returned no valid result.";
2323
+ }
2324
+ if (!settled) {
2325
+ child.stdin?.destroy();
2326
+ child.stdout?.destroy();
2327
+ child.stderr?.destroy();
2328
+ child.unref();
2329
+ }
2330
+ resolve({
2331
+ settled,
2332
+ value,
2333
+ notice
2334
+ });
2335
+ };
2336
+ const signal = (name) => {
2337
+ if (child.pid && identity && ["same", "gone"].includes((0, process_identity_exports.inspectProcessIdentity)(identity))) try {
2338
+ process.kill(-child.pid, name);
2339
+ } catch {}
2340
+ else if (!identity) child.kill(name);
2341
+ };
2342
+ const cancel = () => {
2343
+ if (finished || cancelling) return;
2344
+ cancelling = true;
2345
+ notice ??= "Hosted worker exceeded its deadline.";
2346
+ signal("SIGTERM");
2347
+ killTimer = setTimeout(() => signal("SIGKILL"), 5e3);
2348
+ finishTimer = setTimeout(finish, 1e4);
2349
+ };
2350
+ const finishGroup = () => {
2351
+ if (finished) return;
2352
+ if (!child.pid || !(0, ownership_claim_exports.processGroupAlive)(child.pid)) finish();
2353
+ else {
2354
+ cancel();
2355
+ groupTimer = setTimeout(finishGroup, 25);
2356
+ }
2357
+ };
2358
+ timer = setTimeout(cancel, 9e4);
2359
+ child.stdout?.on("data", (chunk) => {
2360
+ if (Buffer.byteLength(output) + chunk.length > 16384) {
2361
+ notice = "Hosted worker output exceeded its bound.";
2362
+ cancel();
2363
+ } else output += chunk.toString("utf8");
2364
+ });
2365
+ child.stderr?.on("data", (chunk) => {
2366
+ stderr = (stderr + chunk.toString("utf8")).slice(-8192);
2367
+ });
2368
+ child.stdin?.on("error", () => cancel());
2369
+ child.once("error", (error) => {
2370
+ notice = error.message;
2371
+ closed = true;
2372
+ finishGroup();
2373
+ });
2374
+ child.once("close", (code) => {
2375
+ if (code !== 0) notice ??= stderr.trim() || `Hosted worker exited ${code}.`;
2376
+ closed = true;
2377
+ finishGroup();
2378
+ });
2379
+ const captured = child.pid === void 0 ? null : (0, process_identity_exports.captureProcessIdentity)(child.pid);
2380
+ if (!captured?.ok || child.pid === void 0) {
2381
+ notice = "Hosted worker identity unavailable; no native request was sent.";
2382
+ cancel();
2383
+ return;
2384
+ }
2385
+ identity = {
2386
+ pid: child.pid,
2387
+ processToken: captured.token
2388
+ };
2389
+ try {
2390
+ (0, ownership_claim_exports.setClaimChild)(claim, identity);
2391
+ child.stdin?.end(JSON.stringify({
2392
+ mode: "stop",
2393
+ platform: record.platform,
2394
+ session: record.id,
2395
+ deviceType: record.deviceType,
2396
+ runtime: record.runtime,
2397
+ systemImage: record.systemImage,
2398
+ deviceProfile: record.deviceProfile,
2399
+ consolePort: record.consolePort
2400
+ }));
2401
+ } catch (error) {
2402
+ notice = describeError(error);
2403
+ cancel();
2404
+ }
2405
+ });
2406
+ }
2407
+ async function deleteParkedHostedDevices(devices, { listAvds: list = listAvds } = {}) {
2408
+ let failures = 0;
2409
+ for (const device of devices) {
2410
+ if (device.listed === false) continue;
2411
+ const label = `${device.platform} ${device.name ?? device.session} (hosted session ${device.session})`;
2412
+ const kept = (detail) => {
2413
+ console.log(`Kept ${label}: ${detail}`);
2414
+ recordGcResult("parkedHostedDevice", "kept", label, {
2415
+ id: device.id,
2416
+ detail
2417
+ });
2418
+ };
2419
+ let claim;
2420
+ let settled = true;
2421
+ try {
2422
+ let attempt;
2423
+ try {
2424
+ attempt = (0, ownership_claim_exports.tryAcquireClaim)({
2425
+ root: join(deviceHostRoot(), `${device.session}.claims`),
2426
+ mode: "exclusive",
2427
+ label: "hosted device session",
2428
+ details: {
2429
+ session: device.session,
2430
+ client: device.client
2431
+ }
2432
+ });
2433
+ } catch (error) {
2434
+ kept(`session claim unavailable: ${describeError(error)}`);
2435
+ continue;
2436
+ }
2437
+ if (attempt.pending) (0, ownership_claim_exports.releaseClaim)(attempt.pending);
2438
+ claim = attempt.acquired;
2439
+ if (!claim) {
2440
+ kept("session claim is held by another process");
2441
+ continue;
2442
+ }
2443
+ const current = readHostedSessions().find((record) => record.id === device.session);
2444
+ if (!current?.parked || current.client !== device.client || current.parked.at !== device.parkedAt || current.platform !== device.platform || !current.device || hostedDeviceId(current.device) !== device.id) {
2445
+ kept("session is no longer the collected parked device");
2446
+ continue;
2447
+ }
2448
+ const home = join(deviceHostArea(current.id), "home");
2449
+ try {
2450
+ assertHostedDeviceLedger(home, hostedDeviceId(current.device), device.platform);
2451
+ if (hostedDeviceId(readHostedDevice(home, device.platform)) !== device.id) throw new Error("The private device record no longer matches the session.");
2452
+ } catch (error) {
2453
+ kept(describeError(error));
2454
+ continue;
2455
+ }
2456
+ if (device.platform === "android" && !list().includes(device.id)) {
2457
+ kept("AVD not visible from this shell's Android environment; run gc with the server's ANDROID_AVD_HOME/HOME");
2458
+ continue;
2459
+ }
2460
+ settled = false;
2461
+ const outcome = await stopHostedDevice(current, claim);
2462
+ settled = outcome.settled;
2463
+ const result = isJsonObject(outcome.value) ? outcome.value : null;
2464
+ const stopped = result && parseHostedPlatformDevice(result.device, device.platform);
2465
+ if (!settled || outcome.notice || result?.state !== "stopped" || !stopped || hostedDeviceId(stopped) !== device.id) throw new Error(outcome.notice ?? (typeof result?.notice === "string" ? result.notice : "Hosted deletion could not be verified."));
2466
+ console.log(`Deleted ${label}`);
2467
+ recordGcResult("parkedHostedDevice", "done", label, { id: device.id });
2468
+ } catch (error) {
2469
+ const detail = describeError(error);
2470
+ console.error(`Failed to delete ${label}: ${detail}`);
2471
+ recordGcResult("parkedHostedDevice", "failed", label, {
2472
+ id: device.id,
2473
+ detail
2474
+ });
2475
+ failures += 1;
2476
+ } finally {
2477
+ if (claim && settled) (0, ownership_claim_exports.releaseClaim)(claim);
2478
+ }
2479
+ }
2480
+ return failures;
2481
+ }
2482
+ //#endregion
2208
2483
  //#region src/commands/gc.ts
2209
2484
  function removeInvalidProjectEntries(invalidProjects) {
2210
2485
  for (const path of invalidProjects) {
@@ -2303,6 +2578,7 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2303
2578
  olderThanDays: olderThan,
2304
2579
  now
2305
2580
  }) : [],
2581
+ parkedHostedDevices: [],
2306
2582
  caches,
2307
2583
  workspaceOutputs: withWorkspaces ? collectWorkspaceOutputs({
2308
2584
  olderThan,
@@ -2353,7 +2629,11 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2353
2629
  skipped.push(...workspaceDirs.skipped);
2354
2630
  const statusCaches = collectStaleStatusCaches(mountedVolumes);
2355
2631
  skipped.push(...statusCaches.skipped);
2356
- const deviceSweepNotices = [];
2632
+ const hosted = collectParkedHostedDevices({
2633
+ olderThanDays: olderThan,
2634
+ now
2635
+ });
2636
+ const deviceSweepNotices = [...hosted.notices];
2357
2637
  let orphanedDevices = [];
2358
2638
  let unverifiedDevices = [];
2359
2639
  let staleDevices = [];
@@ -2462,6 +2742,7 @@ async function collectGcReport({ olderThan = null, cache = null, worktrees = fal
2462
2742
  orphanedWorkspaces: workspaceDirs.orphaned,
2463
2743
  parkedSims,
2464
2744
  parkedAvds,
2745
+ parkedHostedDevices: hosted.devices,
2465
2746
  orphanedDevices,
2466
2747
  unverifiedDevices,
2467
2748
  staleDevices,
@@ -2751,7 +3032,7 @@ async function runGcCore(opts, deps) {
2751
3032
  const all = report.all;
2752
3033
  for (const line of formatGcReport(report)) console.log(line);
2753
3034
  const { deadProjects, invalidProjects, orphanedDevices, staleDevices, staleDeviceRecords, buildLocks, buildSlots, deviceLeases, easSessionSweep, caches } = report;
2754
- const actionable = archiveWorkPending(report.archives, deadProjects.length + invalidProjects.length > 0 || report.orphanedWorkspaces.length > 0 || Boolean(report.workspaceOutputs?.workspaces.some((entry) => entry.willClear)) || report.workspaceLogs.some((entry) => entry.willTrim) || report.recordings.some((entry) => entry.willDelete && !entry.withWorkspace) || Boolean(report.worktreeSweep?.worktrees.some((entry) => !entry.skipped)) || report.parkedSims.length > 0 || report.parkedAvds.length > 0 || orphanedDevices.length > 0 || staleDevices.length > 0 || staleDeviceRecords.length > 0 || report.staleLedgerEntries.length > 0 || report.staleStatusCaches.length > 0 || buildLocks.stale.length > 0 || buildSlots.stale.length > 0 || deviceLeases.expired.length > 0 || easSessionSweep.orphaned.length > 0 || (olderThan !== null || all) && caches.length > 0 || memoryWorkPending(cache, report.memory));
3035
+ const actionable = archiveWorkPending(report.archives, deadProjects.length + invalidProjects.length > 0 || report.orphanedWorkspaces.length > 0 || Boolean(report.workspaceOutputs?.workspaces.some((entry) => entry.willClear)) || report.workspaceLogs.some((entry) => entry.willTrim) || report.recordings.some((entry) => entry.willDelete && !entry.withWorkspace) || Boolean(report.worktreeSweep?.worktrees.some((entry) => !entry.skipped)) || report.parkedSims.length > 0 || report.parkedAvds.length + report.parkedHostedDevices.filter((device) => device.listed !== false).length > 0 || orphanedDevices.length > 0 || staleDevices.length > 0 || staleDeviceRecords.length > 0 || report.staleLedgerEntries.length > 0 || report.staleStatusCaches.length > 0 || buildLocks.stale.length > 0 || buildSlots.stale.length > 0 || deviceLeases.expired.length > 0 || easSessionSweep.orphaned.length > 0 || (olderThan !== null || all) && caches.length > 0 || memoryWorkPending(cache, report.memory));
2755
3036
  const idle = opts.idle ?? null;
2756
3037
  const idleFailures = idle === null ? 0 : shutDownIdleDevices(report.idleDevices, idle, () => collectIdleDevices(loadConfig$1(), listAllIosSims({ timeoutMs: DEVICE_LIST_TIMEOUT_MS }), report.deadProjects)).failures;
2757
3038
  if (idleFailures) process.exitCode = 1;
@@ -2784,6 +3065,7 @@ async function runGcCore(opts, deps) {
2784
3065
  now: Date.now()
2785
3066
  });
2786
3067
  deleteFailures += reclaimParkedDevices(report, deps);
3068
+ deleteFailures += await deleteParkedHostedDevices(report.parkedHostedDevices);
2787
3069
  deleteFailures += await reclaimMemory(cache, report.memory);
2788
3070
  removeInvalidProjectEntries(invalidProjects);
2789
3071
  deleteFailures += await pruneDeadProjects(deadProjects);
@@ -1,9 +1,9 @@
1
1
  import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
2
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
3
- import { l as phaseLine } from "./command-output-DnJMdEY-.mjs";
3
+ import { l as phaseLine } from "./command-output-CDAIFD-8.mjs";
4
4
  import { a as spawnDeclared } from "./spawn-claims-D0XfSe8u.mjs";
5
- import { o as androidHome } from "./android-B_NumVyQ.mjs";
6
- import { O as readCcacheActivity, T as CCACHE_UNAVAILABLE, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-DkUflduf.mjs";
5
+ import { o as androidHome } from "./android-B_YNZy61.mjs";
6
+ import { O as readCcacheActivity, T as CCACHE_UNAVAILABLE, u as HEARTBEAT_INTERVAL_MS, y as startBuildHeartbeat } from "./toolchain-CNIBTIOv.mjs";
7
7
  import { createHash } from "node:crypto";
8
8
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
9
9
  import { dirname, isAbsolute, join, relative, sep } from "node:path";