stim 1.20.2 → 1.21.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 (217) hide show
  1. package/README.md +88 -8
  2. package/dist/acquire-artifact-CD4lbiWE.mjs +153 -0
  3. package/dist/act-DHAw2A2S.mjs +2667 -0
  4. package/dist/activity-BzVfHSrY.mjs +1376 -0
  5. package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-zh1vhbLp.mjs} +21 -65
  6. package/dist/{android-HqP1_vB_.mjs → android-BEJ8Jpl7.mjs} +2 -2
  7. package/dist/{android-DCKZrNvV.mjs → android-BLgbNqox.mjs} +128 -78
  8. package/dist/{android-Dlzxshgp.mjs → android-CV_GCELZ.mjs} +5 -5
  9. package/dist/{android-Mz_Inn3w.mjs → android-DUYkNF4u.mjs} +184 -102
  10. package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-Ct5b1xCK.mjs} +7 -6
  11. package/dist/android-cas-compiler.mjs +2 -2
  12. package/dist/android-project-BCAAmMwz.mjs +12 -0
  13. package/dist/api.d.mts +740 -8
  14. package/dist/api.mjs +585 -1
  15. package/dist/{artifact-HSwkIWEQ.mjs → artifact-B8T3S5gi.mjs} +223 -201
  16. package/dist/{artifact-D3czlUvT.mjs → artifact-DAuZ-FNU.mjs} +158 -148
  17. package/dist/{browser-web-CA-F1GQo.mjs → browser-web-QQzVjz3O.mjs} +26 -24
  18. package/dist/budget-Bs6SxxzO.mjs +9154 -0
  19. package/dist/{build-DYDbfkk5.mjs → build-CoPzQRNw.mjs} +144 -96
  20. package/dist/build-cache-DmyR9Zzc.mjs +602 -0
  21. package/dist/build-plan-CaFskB7_.mjs +188 -0
  22. package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DkkqguoK.mjs} +2 -2
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/{ccache-zdKiYQ3E.mjs → ccache-BJRZ9pG3.mjs} +10 -9
  25. package/dist/{cdp-Dq_ypAlJ.mjs → cdp-CWmIUMbw.mjs} +18 -5
  26. package/dist/{chrome-BnzZMqsR.mjs → chrome-B6tfCta1.mjs} +7 -4
  27. package/dist/{cli-CLP3diBm.mjs → cli-0DYf8QhQ.mjs} +20 -20
  28. package/dist/cli.mjs +1 -1
  29. package/dist/client-B7QVOlCr.d.mts +253 -0
  30. package/dist/client-UXD70ZbM.mjs +1406 -0
  31. package/dist/collector-run.d.mts +4 -40
  32. package/dist/collector-run.mjs +9 -8
  33. package/dist/{command-output-BTy8hZ0F.mjs → command-output-B1UrjZHL.mjs} +1 -1
  34. package/dist/config-CYcBF478.mjs +949 -0
  35. package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-CqeBlrEn.mjs} +3 -3
  36. package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-BbKQW83h.mjs} +20 -5
  37. package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-DFRyG1_o.mjs} +1 -1
  38. package/dist/{dev-client-DAWVIGBu.mjs → dev-client-UOeESKm6.mjs} +2 -2
  39. package/dist/device-DCxH7_By.mjs +1068 -0
  40. package/dist/{device-BECOiufl.mjs → device-ExJq8Ei7.mjs} +35 -35
  41. package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-CMlqEcvw.mjs} +43 -13
  42. package/dist/device-host-worker.mjs +65 -61
  43. package/dist/{device-ios-COSi6oS1.mjs → device-ios-DRUeKaFV.mjs} +48 -45
  44. package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-C8raGFoP.mjs} +14 -26
  45. package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-DMRpVX9a.mjs} +5 -5
  46. package/dist/doctor-BLHCYxzi.mjs +2 -0
  47. package/dist/{doctor-kfMBnUw6.mjs → doctor-DTvaDOda.mjs} +281 -317
  48. package/dist/{doctor-CB8oZKCk.mjs → doctor-Dhqebm0q.mjs} +183 -91
  49. package/dist/doctor-fingerprint.mjs +19 -0
  50. package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-Cv1F10Kj.mjs} +40 -21
  51. package/dist/{eas-build-JyfqyHfC.mjs → eas-build-BomfRnFT.mjs} +53 -20
  52. package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-DJwZpy0c.mjs} +26 -208
  53. package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-op6A54yi.mjs} +229 -11
  54. package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-Bf0rZvG9.mjs} +172 -82
  55. package/dist/exec-H20xSg2T.d.mts +65 -0
  56. package/dist/exec-_UbtCQcG.mjs +750 -0
  57. package/dist/gc-C-WwL0yi.mjs +3 -0
  58. package/dist/{gc-qWOMdnER.mjs → gc-_-dCXdyL.mjs} +584 -796
  59. package/dist/git-C3iTsJaZ.mjs +73 -0
  60. package/dist/{guide-G9cAbVAc.mjs → guide-Yqwt2bd6.mjs} +941 -269
  61. package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-Bw-honsd.mjs} +8 -6
  62. package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DB_gBPfY.mjs} +34 -19
  63. package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CUvOf4Vr.mjs} +1 -1
  64. package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-DL_P5AdN.mjs} +77 -43
  65. package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-QI141yKk.mjs} +21 -17
  66. package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-Ksyjgzq-.mjs} +30 -21
  67. package/dist/idle-BVeRGroT.d.mts +24 -0
  68. package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DaKmZi0z.mjs} +11 -10
  69. package/dist/{ios-BwVCF7oA.mjs → ios-CQ68hG9s.mjs} +8 -8
  70. package/dist/{ios-RkW4pnQf.mjs → ios-CpByZy12.mjs} +140 -80
  71. package/dist/{ios-device-B5veSDDQ.mjs → ios-device-CXGP1bsD.mjs} +1 -1
  72. package/dist/{ios-device-D7pi2Sca.mjs → ios-device-CwFMehUS.mjs} +51 -26
  73. package/dist/{ios-project-K9hY_Jab.mjs → ios-project-WuwwBdvW.mjs} +13 -13
  74. package/dist/{ios-nOLJGVdy.mjs → ios-qNJt4dFm.mjs} +1 -1
  75. package/dist/ios-signing-DTTIChGs.mjs +489 -0
  76. package/dist/{ios-state-CBLe1xYw.mjs → ios-state-DvFX-K_l.mjs} +1 -1
  77. package/dist/{ios-Ce7bc7br.mjs → ios-ubFsBzwq.mjs} +129 -86
  78. package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Cc1dttps.mjs} +53 -26
  79. package/dist/{launch-F4sOqAhB.mjs → launch-CD1yVc7U.mjs} +91 -90
  80. package/dist/{launch-C3qJ6Agb.mjs → launch-Zq2mOSDy.mjs} +82 -541
  81. package/dist/logs-BS00Anxf.mjs +352 -0
  82. package/dist/logs-CMm05HxN.mjs +255 -0
  83. package/dist/{macos-D7uDvO-z.mjs → macos-B65--pPd.mjs} +1 -1
  84. package/dist/{macos-Ch5VJmcS.mjs → macos-C-0qJ6zq.mjs} +225 -212
  85. package/dist/macos-run.mjs +1 -1
  86. package/dist/maintenance-run.mjs +122 -247
  87. package/dist/{metro-DnCEjCxs.mjs → metro-DEXpIhHC.mjs} +67 -12
  88. package/dist/{metro-gateway-CX9Xlkq2.mjs → metro-gateway-BMJNlj3E.mjs} +20 -12
  89. package/dist/{named-ports-4WopRPg-.mjs → named-ports-BWTzt6mu.mjs} +8 -63
  90. package/dist/native-android-JACyjTZs.mjs +844 -0
  91. package/dist/{native-gradle-inputs-BsLRrl7u.mjs → native-gradle-inputs-Bep9JcSF.mjs} +128 -140
  92. package/dist/native-inputs-TRTTTRxt.mjs +91 -0
  93. package/dist/native-run-DY_RLx3C.mjs +277 -0
  94. package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-Dg1Q7tfF.mjs} +9 -8
  95. package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-CB2iQeWq.mjs} +27 -18
  96. package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-CXX39F7o.mjs} +96 -47
  97. package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
  98. package/dist/offload-worker.d.mts +1 -46
  99. package/dist/offload-worker.mjs +197 -66
  100. package/dist/{ownership-DCtw_2IA.mjs → ownership-DEmM5vhh.mjs} +3 -3
  101. package/dist/{page-DRHy329N.mjs → page-CPaHeYqj.mjs} +7 -4
  102. package/dist/paths-BsJMoPP2.mjs +12 -0
  103. package/dist/paths-DQtTgsBf.mjs +42 -0
  104. package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BqGbTa61.mjs} +5 -5
  105. package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-Bwj-IjY1.mjs} +6 -6
  106. package/dist/{ports-DdSUicVo.mjs → ports-D-MmCTdv.mjs} +3 -3
  107. package/dist/prebuild-uD_ipCxF.mjs +449 -0
  108. package/dist/{project-_phNIJfs.mjs → project-BZNjmW_8.mjs} +65 -37
  109. package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-Lfetn8Kr.mjs} +2 -2
  110. package/dist/pull-request-zjCSAryH.d.mts +120 -0
  111. package/dist/pull-requests.d.mts +1 -119
  112. package/dist/pull-requests.mjs +1 -1
  113. package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-DuzH0cn3.mjs} +74 -48
  114. package/dist/{gradle-DSrXb6lG.mjs → react-native-build-rhk4smwQ.mjs} +292 -15
  115. package/dist/react-native-doctor-CQpuIMso.mjs +234 -0
  116. package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-Bhq1rJeV.mjs} +46 -28
  117. package/dist/{recordings-D0d5aQt0.mjs → recordings-DYteQSu4.mjs} +12 -9
  118. package/dist/{reload-C8JhxjSh.mjs → reload-CmTRFJaX.mjs} +93 -47
  119. package/dist/reload-DzjSl5P_.mjs +2 -0
  120. package/dist/{remote-BiR6aYjy.mjs → remote-ByYkXdGD.mjs} +15 -10
  121. package/dist/result-DNiS-tTP.mjs +434 -0
  122. package/dist/{run-BtPgpKks.mjs → run-D23HmJMs.mjs} +4 -5
  123. package/dist/selection-CSl9i5qU.mjs +619 -0
  124. package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CxTrvDg8.mjs} +3 -4
  125. package/dist/{server-command-CTtCkmcQ.mjs → server-command-CtzloH3v.mjs} +14 -7
  126. package/dist/server-expo-C-90EhcG.mjs +2 -0
  127. package/dist/{server-expo-DsguMGUF.mjs → server-expo-DT_F_uVI.mjs} +50 -9
  128. package/dist/{settings-B717odTD.mjs → settings-CsJDEXgK.mjs} +234 -24
  129. package/dist/{settings-vk3mJGSm.d.mts → settings-DkdmlelE.d.mts} +6 -4
  130. package/dist/settings-T1gtc3bf.mjs +114 -0
  131. package/dist/settings-write-HyVZ8eQ8.mjs +359 -0
  132. package/dist/settings.schema.json +163 -16
  133. package/dist/{simslim-CCr3rE-A.mjs → simslim-Cgk17SXV.mjs} +14 -12
  134. package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-DF8VfT64.mjs} +15 -20
  135. package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
  136. package/dist/stage-BIS0ydsV.mjs +183 -0
  137. package/dist/{start-BWqzODpb.mjs → start-7lpH7hmN.mjs} +63 -44
  138. package/dist/{start-TXeMmmO2.mjs → start-RChynRDp.mjs} +1 -1
  139. package/dist/{state-D1Icyjlu.mjs → state-C4ZtUisW.mjs} +40 -13
  140. package/dist/{state-CG_OFoaA.mjs → state-XMziexv2.mjs} +3 -2
  141. package/dist/{stats-BoY5sEPU.mjs → stats-53T7OTb9.mjs} +7 -13
  142. package/dist/stats-report-BFfMpWWF.mjs +16 -0
  143. package/dist/{status-WgFbkRzj.mjs → status-BL7jVyAB.mjs} +535 -447
  144. package/dist/status-CSi6tlRq.mjs +2 -0
  145. package/dist/{status-BTA7kKiQ.mjs → status-DqEUSSxs.mjs} +6 -4
  146. package/dist/{status-watch-C23ILtf9.mjs → status-watch-GDCfqpTE.mjs} +187 -22
  147. package/dist/status-worker.d.mts +1 -0
  148. package/dist/status-worker.mjs +19 -0
  149. package/dist/stim-desktop-C12we7lz.mjs +112 -0
  150. package/dist/{stop-DR6VoDIk.mjs → stop-Bk_1qiV6.mjs} +2 -2
  151. package/dist/{stop-BNmBMi1F.mjs → stop-CPzlM1L-.mjs} +138 -98
  152. package/dist/{stop-DPEhunlw.mjs → stop-D7h6jAXQ.mjs} +11 -10
  153. package/dist/supervisor-run.d.mts +8 -17
  154. package/dist/supervisor-run.mjs +63 -27
  155. package/dist/{support-DMTqj3Hm.mjs → support-67vraa1Q.mjs} +18 -11
  156. package/dist/{support-CwjbFs9H.mjs → support-Dlu37g6H.mjs} +12 -12
  157. package/dist/{swiftpm-macos-DRNVJWlb.mjs → swiftpm-macos-p8WZbxKU.mjs} +35 -24
  158. package/dist/toolchain-DhKwp9iI.mjs +2 -0
  159. package/dist/toolchain-Hp9sCpK4.mjs +873 -0
  160. package/dist/{trigger-CigAYjeL.mjs → trigger-BAahxUPq.mjs} +20 -5
  161. package/dist/trigger-Bf3uDcpv.mjs +2 -0
  162. package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-BHX5r0Ei.mjs} +250 -156
  163. package/dist/{web-BDBMxDpx.mjs → web-CJmIj6AI.mjs} +18 -13
  164. package/dist/web-DknQETPs.mjs +2 -0
  165. package/dist/web-run.mjs +11 -12
  166. package/dist/windows-report.d.mts +1 -0
  167. package/dist/windows-report.mjs +18 -0
  168. package/dist/windows-report.ps1 +43 -0
  169. package/dist/workspace-process-lock-1_1OoVW5.mjs +57 -0
  170. package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-Cjuigeeu.mjs} +62 -58
  171. package/dist/{workspaces-C36s2jb9.mjs → workspaces-BccMFmGQ.mjs} +1188 -1079
  172. package/dist/worktree-CK2MpJW5.mjs +2 -0
  173. package/dist/{worktree-CgvJYJ-Q.mjs → worktree-DQ6Zi2Mv.mjs} +304 -53
  174. package/dist/xcode-Zlx3qjEs.mjs +896 -0
  175. package/package.json +7 -5
  176. package/shim/android-optimizations.gradle +7 -5
  177. package/dist/activity-BSV745Kz.mjs +0 -629
  178. package/dist/api-qvOzWyfO.mjs +0 -154
  179. package/dist/api-run.mjs +0 -294
  180. package/dist/app-install-BIKtMfPq.mjs +0 -896
  181. package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
  182. package/dist/budget-f7516Zk0.mjs +0 -4106
  183. package/dist/build-facts-DcLv2HSd.d.mts +0 -111
  184. package/dist/cancellation-C_22VQTH.mjs +0 -24
  185. package/dist/client-qQAaXSUs.mjs +0 -1771
  186. package/dist/config-BYDxlMY3.mjs +0 -562
  187. package/dist/device-DuiPJQSn.mjs +0 -290
  188. package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
  189. package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
  190. package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
  191. package/dist/exec-DqKo9GKJ.mjs +0 -268
  192. package/dist/git-DDfFzkMm.mjs +0 -45
  193. package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
  194. package/dist/logs-BGrEUaEs.mjs +0 -383
  195. package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
  196. package/dist/native-android-D5qc3-_v.mjs +0 -226
  197. package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
  198. package/dist/plan-C4TjdPsR.mjs +0 -260
  199. package/dist/prebuild-DYbucPXy.mjs +0 -212
  200. package/dist/preview-78a9kR_-.mjs +0 -1011
  201. package/dist/react-native-build-CtCccJtb.mjs +0 -239
  202. package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
  203. package/dist/remote-cache-OyOyVIS3.mjs +0 -526
  204. package/dist/result-CaJg5Iat.mjs +0 -186
  205. package/dist/server-expo-Bigriskl.mjs +0 -2
  206. package/dist/settings-BORNaaCO.mjs +0 -402
  207. package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
  208. package/dist/stage-KNTQopqv.mjs +0 -157
  209. package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
  210. package/dist/tailnet-Dh-qiYzG.mjs +0 -265
  211. package/dist/toolchain-BFkAcstd.mjs +0 -2
  212. package/dist/toolchain-DxSsNssu.mjs +0 -1657
  213. package/dist/trigger-9_USgmxz.mjs +0 -2
  214. package/dist/web-Dq-i3wzJ.mjs +0 -2
  215. package/dist/worktree-DpLdCHga.mjs +0 -2
  216. package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
  217. package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stim",
3
- "version": "1.20.2",
3
+ "version": "1.21.0",
4
4
  "description": "Stim: fast, isolated React Native environments for coding agents",
5
5
  "keywords": [
6
6
  "agent",
@@ -53,9 +53,11 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@expo/fingerprint": "^0.20.10",
56
- "@stim-cli/cache": "^1.20.2",
57
- "@stim-cli/core": "^1.20.2",
58
- "@stim-cli/metro": "^1.20.2",
56
+ "@stim-cli/agent-driver": "^1.21.0",
57
+ "@stim-cli/agent-driver-agent-device": "^1.21.0",
58
+ "@stim-cli/cache": "^1.21.0",
59
+ "@stim-cli/core": "^1.21.0",
60
+ "@stim-cli/metro": "^1.21.0",
59
61
  "@xmldom/xmldom": "0.9.12",
60
62
  "chalk": "^6.0.0",
61
63
  "commander": "^15.0.0",
@@ -64,7 +66,7 @@
64
66
  "ws": "^8.21.3"
65
67
  },
66
68
  "devDependencies": {
67
- "@stim-cli/expo-build-cache": "1.20.2",
69
+ "@stim-cli/expo-build-cache": "1.21.0",
68
70
  "@types/cross-spawn": "^6.0.6",
69
71
  "@types/which": "^3.0.4",
70
72
  "@types/ws": "^8.18.1",
@@ -5,12 +5,14 @@ gradle.beforeProject { project ->
5
5
  def reactApplication = project.plugins.hasPlugin("com.android.application") && project.plugins.hasPlugin("com.facebook.react")
6
6
  if (!android.externalNativeBuild.cmake.path && !reactApplication) return
7
7
  def profile = System.getenv("STIM_ANDROID_NATIVE_PROFILE")
8
+ def windows = System.getProperty("os.name").toLowerCase().startsWith("windows")
8
9
  def staging = android.externalNativeBuild.cmake.buildStagingDirectory ?: new File(project.projectDir, ".cxx")
9
- android.externalNativeBuild.cmake.buildStagingDirectory = new File(staging, "stim-" + profile)
10
- // Windows caps a path at 260 characters and the SDK's ninja is not long-path aware, so the
11
- // staging directory added above has to buy its room back: CMake replaces the mangled absolute
12
- // source directory in an over-long object path with a hash of it.
13
- if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
10
+ // Windows caps a path at 260 characters and the SDK's ninja is not long-path aware, so every
11
+ // character of the staging directory comes out of the project root's budget: there the profile
12
+ // directory keeps 4 hex characters, and CMake replaces the mangled absolute source directory in an
13
+ // over-long object path with a hash of it.
14
+ android.externalNativeBuild.cmake.buildStagingDirectory = new File(staging, windows ? profile.take(4) : "stim-" + profile)
15
+ if (windows) {
14
16
  android.defaultConfig.externalNativeBuild.cmake.arguments.add("-DCMAKE_OBJECT_PATH_MAX=240")
15
17
  }
16
18
  def configs = [android.defaultConfig] + android.buildTypes.toList() + android.productFlavors.toList()
@@ -1,629 +0,0 @@
1
- import { k as process_identity_exports } from "./config-BYDxlMY3.mjs";
2
- import { t as getExecutor } from "./exec-DqKo9GKJ.mjs";
3
- import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-BX1sJQ2E.mjs";
4
- import { r as readWorkspaceState$1, w as workspaceLogsDir$1 } from "./workspace-state-DJt_MMvf.mjs";
5
- import { closeSync, fstatSync, openSync, readFileSync, readSync, readdirSync, statSync } from "node:fs";
6
- import { basename, join, resolve } from "node:path";
7
- import { agentDeviceStateDirs, readViewedDevices } from "@stim-cli/core/state";
8
- import { homedir } from "node:os";
9
- //#region src/devices/automation-tools.ts
10
- const AUTOMATION_TOOLS = [
11
- {
12
- tool: "agent-browser",
13
- platforms: ["web"],
14
- cdp: /agent-browser/i
15
- },
16
- {
17
- tool: "agent-device",
18
- platforms: [
19
- "ios",
20
- "android",
21
- "web"
22
- ],
23
- host: /agent-device/i,
24
- cdp: /agent-device/i
25
- },
26
- {
27
- tool: "argent",
28
- platforms: [
29
- "ios",
30
- "android",
31
- "web"
32
- ],
33
- host: /\/bin\/[\w-]+\/(simulator-server(\.exe)?\s+(ios|android|android_device)|ax-service)\b|com\.argent\.androiddevtools/,
34
- instrumentation: /com\.argent\.androiddevtools/,
35
- cdp: /@swmansion\/argent\/dist\/tool-server/
36
- },
37
- {
38
- tool: "idb",
39
- platforms: ["ios"],
40
- host: /idb_companion/
41
- },
42
- {
43
- tool: "maestro",
44
- platforms: ["ios", "android"],
45
- host: /maestro/i
46
- },
47
- {
48
- tool: "appium",
49
- platforms: ["ios", "android"],
50
- host: /appium|WebDriverAgent/i
51
- },
52
- {
53
- tool: "xcodebuild",
54
- platforms: ["ios"],
55
- host: /\bxcodebuild\b.*\btest(-without-building)?\b/
56
- },
57
- {
58
- tool: "simctl",
59
- platforms: ["ios"],
60
- host: /\bsimctl\s+(io|spawn)\b/
61
- },
62
- {
63
- tool: "uiautomator",
64
- platforms: ["android"],
65
- instrumentation: /uiautomator/
66
- },
67
- {
68
- tool: "instrumentation",
69
- platforms: ["android"],
70
- instrumentation: /androidx\.test|\binstrument\b/
71
- },
72
- {
73
- tool: "chrome-devtools-mcp",
74
- platforms: ["web"],
75
- cdp: /chrome-devtools-mcp/i
76
- },
77
- {
78
- tool: "playwright",
79
- platforms: ["web"],
80
- cdp: /playwright/i
81
- },
82
- {
83
- tool: "puppeteer",
84
- platforms: ["web"],
85
- cdp: /puppeteer/i
86
- }
87
- ];
88
- const HOST_EXCLUSIONS = [/\bsimctl\s+spawn\b.*\blog\s+stream\b/, /\blogcat\b/];
89
- /** Stim's own DevTools clients: the browser supervisor, `stim-frames` in stim-server, Stim Desktop, the stim CLI. */
90
- const CDP_EXCLUSIONS = [/\bstim-(frames|server|web)\b|StimDesktop|\/stim(-cli)?\/(dist|bin)\/|\/bin\/stim(\s|$)|^stim(\s|$)/];
91
- function namesDevice(command, id) {
92
- const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
93
- return new RegExp(`(^|[^A-Za-z0-9])${escaped}([^A-Za-z0-9]|$)`).test(command);
94
- }
95
- /** The tool a host process drives the device `id` with, or null when the command does not name the device. */
96
- function hostDriverTool(command, platform, id) {
97
- if (!namesDevice(command, id) || HOST_EXCLUSIONS.some((pattern) => pattern.test(command))) return null;
98
- return AUTOMATION_TOOLS.find((entry) => entry.platforms.includes(platform) && entry.host?.test(command))?.tool ?? null;
99
- }
100
- /** The tool behind an on-device process's arguments, or null when it is not instrumentation. */
101
- function instrumentationTool(args) {
102
- return AUTOMATION_TOOLS.find((entry) => entry.platforms.includes("android") && entry.instrumentation?.test(args))?.tool ?? null;
103
- }
104
- /**
105
- * The tool a DevTools client's command line names, or null for Stim's own clients. A client no entry names is
106
- * reported by its script or executable name.
107
- */
108
- function cdpClientTool(command) {
109
- if (CDP_EXCLUSIONS.some((pattern) => pattern.test(command))) return null;
110
- const known = AUTOMATION_TOOLS.find((entry) => entry.platforms.includes("web") && entry.cdp?.test(command));
111
- if (known) return known.tool;
112
- const [executable = "", script] = command.trim().split(/\s+/);
113
- const name = basename(executable);
114
- return (/^(node|bun|deno|python3?)$/.test(name) && script ? basename(script) : name) || "unknown DevTools client";
115
- }
116
- //#endregion
117
- //#region src/devices/activity.ts
118
- const ACTIVE_WINDOW_MS = 6e5;
119
- const LOG_TAIL_BYTES = 262144;
120
- function classifyActivity(evidence, now) {
121
- const last = evidence.recency.reduce((best, entry) => Number.isFinite(entry.at) && (!best || entry.at > best.at) ? entry : best, null);
122
- const recent = {};
123
- for (const { basis, at } of evidence.recency) if (Number.isFinite(at) && !(Date.parse(recent[basis] ?? "") >= at)) recent[basis] = new Date(at).toISOString();
124
- const lastActivityAt = last ? {
125
- lastActivityAt: new Date(last.at).toISOString(),
126
- recent
127
- } : {};
128
- const [first] = evidence.drivers;
129
- if (first) {
130
- const { basis: _basis, ...driver } = first;
131
- return {
132
- state: "driven",
133
- driver,
134
- ...lastActivityAt,
135
- basis: [...new Set(evidence.drivers.map((entry) => entry.basis))]
136
- };
137
- }
138
- if (evidence.unknown.length) return {
139
- state: "unknown",
140
- ...lastActivityAt,
141
- basis: [...new Set(evidence.unknown)]
142
- };
143
- return {
144
- state: Boolean(last && now - last.at < ACTIVE_WINDOW_MS) ? "active" : "idle",
145
- ...lastActivityAt,
146
- basis: [...new Set(evidence.recency.map((entry) => entry.basis))]
147
- };
148
- }
149
- function idleForMs(activity, now) {
150
- if (activity?.state !== "idle" || !activity.lastActivityAt) return null;
151
- const at = Date.parse(activity.lastActivityAt);
152
- return Number.isFinite(at) ? Math.max(0, now - at) : null;
153
- }
154
- function field(entry, pidKey, startKey) {
155
- const pid = entry[pidKey];
156
- const startTime = entry[startKey];
157
- if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof startTime !== "string") return null;
158
- return {
159
- pid,
160
- startTime
161
- };
162
- }
163
- function parseObject(raw) {
164
- if (raw === null) return null;
165
- try {
166
- const parsed = JSON.parse(raw);
167
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
168
- } catch {
169
- return null;
170
- }
171
- }
172
- function parseAgentDeviceRecord(kind, path, raw) {
173
- const entry = parseObject(raw);
174
- const stem = basename(path, ".json");
175
- const device = entry?.device && typeof entry.device === "object" ? entry.device : null;
176
- const recordedId = kind === "claim" ? device?.id : entry?.deviceId;
177
- const deviceId = typeof recordedId === "string" && recordedId ? recordedId : kind === "runner-lease" ? stem : null;
178
- const createdAtMs = typeof entry?.createdAtMs === "number" ? entry.createdAtMs : null;
179
- return {
180
- path,
181
- kind,
182
- deviceId,
183
- session: kind === "claim" && typeof entry?.session === "string" && entry.session ? entry.session : null,
184
- workspace: kind === "claim" && typeof entry?.workspace === "string" && entry.workspace ? entry.workspace : null,
185
- stateDir: kind === "claim" && typeof entry?.stateDir === "string" && entry.stateDir ? entry.stateDir : null,
186
- deviceName: kind === "claim" && typeof device?.name === "string" ? device.name : null,
187
- readable: Boolean(entry && deviceId),
188
- owner: entry ? field(entry, "ownerPid", "ownerStartTime") : null,
189
- runner: entry && kind === "runner-lease" ? field(entry, "runnerPid", "runnerStartTime") : null,
190
- claimProtocol: kind === "runner-lease" && entry?.deviceClaimProtocol === 1,
191
- createdAtMs,
192
- xctestrunPath: typeof entry?.xctestrunPath === "string" ? entry.xctestrunPath : null
193
- };
194
- }
195
- function processMatches(entry, startOf) {
196
- const start = startOf(entry.pid);
197
- if (start.status === "gone") return "dead";
198
- if (start.status === "unknown") return "unknown";
199
- const recorded = Date.parse(entry.startTime);
200
- if (!Number.isFinite(recorded)) return "unknown";
201
- return Math.floor(start.startedAtMs / 1e3) === Math.floor(recorded / 1e3) ? "live" : "dead";
202
- }
203
- function agentDeviceDaemon(stateDir, startOf = process_identity_exports.inspectProcessStart) {
204
- let raw;
205
- try {
206
- raw = readFileSync(join(stateDir, "daemon.json"), "utf8");
207
- } catch (error) {
208
- return error.code === "ENOENT" ? "none" : "unknown";
209
- }
210
- const entry = parseObject(raw);
211
- const owner = entry && field(entry, "pid", "processStartTime");
212
- return owner ? processMatches(owner, startOf) : "unknown";
213
- }
214
- function agentDeviceLiveness(record, startOf) {
215
- const results = (record.kind === "claim" ? [record.owner] : [record.owner, record.runner]).map((entry) => entry ? processMatches(entry, startOf) : "unknown");
216
- if (results.includes("dead")) return "dead";
217
- if (!record.readable || results.includes("unknown")) return "unknown";
218
- return "live";
219
- }
220
- const HOST_PROCESS_COLUMNS = "pid=,ppid=,rss=,%cpu=,lstart=,command=";
221
- function parseProcessTable(output) {
222
- const rows = [];
223
- for (const line of output.split("\n")) {
224
- const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+(?:[.,]\d+)?)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{1,2}:\d{2}:\d{2}\s+\d{4})\s+(.*)$/.exec(line);
225
- if (!match) continue;
226
- const at = Date.parse(match[5]);
227
- rows.push({
228
- pid: Number(match[1]),
229
- ppid: Number(match[2]),
230
- rssKb: Number(match[3]),
231
- cpuPercent: Number(match[4].replace(",", ".")),
232
- startedAt: Number.isFinite(at) ? new Date(at).toISOString() : null,
233
- command: match[6]
234
- });
235
- }
236
- return rows;
237
- }
238
- function parseAndroidInstrumentation(output) {
239
- const found = [];
240
- for (const line of output.split("\n")) {
241
- const match = /^\s*(\d+)\s+(.*)$/.exec(line);
242
- if (!match) continue;
243
- const tool = instrumentationTool(match[2]);
244
- if (tool) found.push({
245
- pid: Number(match[1]),
246
- tool
247
- });
248
- }
249
- return found;
250
- }
251
- function latestDeviceLogAt(lines, target) {
252
- return latestRecordAt(lines, (record) => {
253
- if (record.src !== "device" || record.platform !== target.platform || !isDeviceRecord(record)) return false;
254
- if (target.slot === "default") return record.slot === void 0;
255
- return record.slot === target.slot && (record.deviceId === void 0 || record.deviceId === target.id);
256
- });
257
- }
258
- function latestBundleRequestAt(lines, platform) {
259
- return latestRecordAt(lines, (record) => record.event === "bundle_response_started" && record.platform === platform);
260
- }
261
- function latestRecordAt(lines, matches) {
262
- for (let i = lines.length - 1; i >= 0; i--) {
263
- const record = parseObject(lines[i]);
264
- if (record && typeof record.ts === "number" && matches(record)) return record.ts;
265
- }
266
- return null;
267
- }
268
- function isDeviceRecord(record) {
269
- return !(typeof record.event === "string" && record.event.startsWith("collector_"));
270
- }
271
- /** The last lines of the file at `path`, at most its final 256 KiB, or null when it cannot be read. */
272
- function tailLines(path) {
273
- let fd;
274
- try {
275
- fd = openSync(path, "r");
276
- const size = fstatSync(fd).size;
277
- const length = Math.min(size, LOG_TAIL_BYTES);
278
- const buffer = Buffer.alloc(length);
279
- readSync(fd, buffer, 0, length, size - length);
280
- const lines = buffer.toString("utf8").split("\n");
281
- return length < size ? lines.slice(1) : lines;
282
- } catch {
283
- return null;
284
- } finally {
285
- if (fd !== void 0) closeSync(fd);
286
- }
287
- }
288
- function envDir(name) {
289
- const value = process.env[name]?.trim();
290
- return value ? resolve(value) : null;
291
- }
292
- function agentDeviceDirs(home) {
293
- const root = join(home, ".agent-device");
294
- const leaseDirs = [envDir("AGENT_DEVICE_IOS_RUNNER_LEASE_DIR") ?? join(root, "apple-runner", "leases"), join(root, "ios-runner", "leases")];
295
- return [{
296
- kind: "claim",
297
- dir: envDir("AGENT_DEVICE_CLAIMS_DIR") ?? join(root, "device-claims")
298
- }, ...[...new Set(leaseDirs)].map((dir) => ({
299
- kind: "runner-lease",
300
- dir
301
- }))];
302
- }
303
- /**
304
- * When an agent-device session last recorded an event: its events file's modification time. agent-device names a
305
- * session's directory after the session with every character outside `[a-zA-Z0-9._-]` replaced by `_`.
306
- */
307
- function agentSessionActedAt(home, session, stateDir) {
308
- let latest = null;
309
- for (const root of stateDir ? [stateDir] : agentDeviceStateDirs(home)) try {
310
- const at = statSync(join(root, "sessions", session.replaceAll(/[^a-zA-Z0-9._-]/g, "_"), "events.ndjson")).mtimeMs;
311
- latest = latest === null ? at : Math.max(latest, at);
312
- } catch {}
313
- return latest;
314
- }
315
- function readAgentDeviceRecords(home) {
316
- return agentDeviceDirs(home).flatMap(({ kind, dir }) => {
317
- let names;
318
- try {
319
- names = readdirSync(dir).filter((name) => name.endsWith(".json"));
320
- } catch {
321
- return [];
322
- }
323
- return names.map((name) => {
324
- const path = join(dir, name);
325
- let raw = null;
326
- try {
327
- raw = readFileSync(path, "utf8");
328
- } catch {}
329
- return parseAgentDeviceRecord(kind, path, raw);
330
- });
331
- });
332
- }
333
- function isClaimProtocolRunner(record, row) {
334
- if (!record.claimProtocol || record.runner?.pid !== row.pid || row.startedAt === null) return false;
335
- const recorded = Date.parse(record.runner.startTime);
336
- return Math.floor(recorded / 1e3) === Math.floor(Date.parse(row.startedAt) / 1e3);
337
- }
338
- function lsofArgs(port) {
339
- return [
340
- "-nP",
341
- `-iTCP:${port}`,
342
- "-sTCP:ESTABLISHED",
343
- "-Fpn"
344
- ];
345
- }
346
- function lsofNoMatch(error) {
347
- const stdout = error.stdout;
348
- return error.status === 1 && (stdout === "" || stdout === void 0) ? "" : null;
349
- }
350
- function createDeviceProcessTables() {
351
- const exec = getExecutor();
352
- let host;
353
- const android = /* @__PURE__ */ new Map();
354
- const tcp = /* @__PURE__ */ new Map();
355
- return {
356
- tcpConnections(port) {
357
- if (!tcp.has(port)) {
358
- let output;
359
- try {
360
- output = exec.runFile("lsof", lsofArgs(port), { timeoutMs: 5e3 });
361
- } catch (error) {
362
- output = lsofNoMatch(error);
363
- }
364
- tcp.set(port, output);
365
- }
366
- return tcp.get(port) ?? null;
367
- },
368
- host() {
369
- if (host === void 0) {
370
- const output = exec.runFileQuiet("ps", [
371
- "-axww",
372
- "-o",
373
- HOST_PROCESS_COLUMNS
374
- ], { timeoutMs: 1e4 });
375
- host = output === null ? null : parseProcessTable(output);
376
- }
377
- return host;
378
- },
379
- android(serial) {
380
- if (!android.has(serial)) android.set(serial, exec.runFileQuiet("adb", [
381
- "-s",
382
- serial,
383
- "shell",
384
- "ps",
385
- "-A",
386
- "-o",
387
- "PID,ARGS"
388
- ], { timeoutMs: 5e3 }));
389
- return android.get(serial) ?? null;
390
- }
391
- };
392
- }
393
- function workspaceDeviceRecency(root) {
394
- const recency = [];
395
- const usedAt = Date.parse(String(readWorkspaceState$1(root)?.lastUsedAt ?? ""));
396
- if (Number.isFinite(usedAt)) recency.push({
397
- basis: "workspace-use",
398
- at: usedAt
399
- });
400
- for (const file of ["client.ndjson", "device.ndjson"]) try {
401
- recency.push({
402
- basis: "device-log",
403
- at: statSync(join(workspaceLogsDir$1(root), file)).mtimeMs
404
- });
405
- } catch {}
406
- return recency;
407
- }
408
- /** The newest workspace use or change to its in-app or native device logs. */
409
- function workspaceDeviceLastUseAt(root) {
410
- const times = workspaceDeviceRecency(root).map(({ at }) => at).filter(Number.isFinite);
411
- return times.length ? Math.max(...times) : NaN;
412
- }
413
- function createActivityReader({ now = Date.now(), home = homedir(), startOf = process_identity_exports.inspectProcessStart, leaseFiles = listLeaseFiles, tables = createDeviceProcessTables(), viewers = readViewedDevices } = {}) {
414
- let agentDevice;
415
- let stimLeases;
416
- let viewed;
417
- const logs = /* @__PURE__ */ new Map();
418
- const log = (path) => {
419
- if (!logs.has(path)) logs.set(path, tailLines(path));
420
- return logs.get(path) ?? null;
421
- };
422
- return (target) => {
423
- const evidence = {
424
- drivers: [],
425
- unknown: [],
426
- recency: []
427
- };
428
- agentDevice ??= readAgentDeviceRecords(home).map((record) => ({
429
- record,
430
- liveness: agentDeviceLiveness(record, startOf)
431
- }));
432
- for (const { record, liveness } of agentDevice) {
433
- if (record.deviceId !== null && record.deviceId !== target.id) continue;
434
- if (record.claimProtocol) continue;
435
- const basis = record.kind === "claim" ? "agent-device-claim" : "agent-device-lease";
436
- if (liveness === "live") {
437
- evidence.drivers.push({
438
- basis,
439
- tool: "agent-device",
440
- pid: record.owner?.pid ?? null,
441
- since: record.createdAtMs !== null ? new Date(record.createdAtMs).toISOString() : null
442
- });
443
- const actedAt = record.session ? agentSessionActedAt(home, record.session, record.stateDir) : null;
444
- if (actedAt !== null) evidence.recency.push({
445
- basis: "agent-action",
446
- at: actedAt
447
- });
448
- } else if (liveness === "unknown") evidence.unknown.push(basis);
449
- }
450
- try {
451
- stimLeases ??= leaseFiles();
452
- } catch {
453
- stimLeases = [];
454
- evidence.unknown.push("device-lock");
455
- }
456
- for (const entry of stimLeases) {
457
- if (entry.platform !== target.platform || entry.id !== target.id) continue;
458
- if (!entry.lease) evidence.unknown.push("device-lock");
459
- else if (!leaseIsExpired(entry.lease, now)) evidence.drivers.push({
460
- basis: "device-lock",
461
- tool: "stim device lock",
462
- pid: null,
463
- since: entry.lease.grantedAt
464
- });
465
- }
466
- viewed ??= viewers();
467
- if (viewed.some((device) => device.platform === target.platform && device.id === target.id)) evidence.recency.push({
468
- basis: "viewer",
469
- at: now
470
- });
471
- const processes = tables.host();
472
- if (processes === null) evidence.unknown.push("driver-process");
473
- for (const row of processes ?? []) {
474
- if (agentDevice.some(({ record }) => isClaimProtocolRunner(record, row))) continue;
475
- const tool = hostDriverTool(row.command, target.platform, target.id);
476
- if (tool) evidence.drivers.push({
477
- basis: "driver-process",
478
- tool,
479
- pid: row.pid,
480
- since: row.startedAt
481
- });
482
- }
483
- if (target.platform === "android") {
484
- const output = tables.android(target.id);
485
- if (output === null) evidence.unknown.push("instrumentation");
486
- for (const { pid, tool } of parseAndroidInstrumentation(output ?? "")) evidence.drivers.push({
487
- basis: "instrumentation",
488
- tool,
489
- pid,
490
- since: null
491
- });
492
- }
493
- if (target.workspace) {
494
- const dir = workspaceLogsDir$1(target.workspace);
495
- const deviceAt = latestDeviceLogAt(log(join(dir, "device.ndjson")) ?? [], target);
496
- if (deviceAt !== null) evidence.recency.push({
497
- basis: "device-log",
498
- at: deviceAt
499
- });
500
- const bundleAt = latestBundleRequestAt(log(join(dir, "metro.ndjson")) ?? [], target.platform);
501
- if (bundleAt !== null) evidence.recency.push({
502
- basis: "metro-bundle",
503
- at: bundleAt
504
- });
505
- const usedAt = Date.parse(String(readWorkspaceState$1(target.workspace)?.lastUsedAt ?? ""));
506
- if (Number.isFinite(usedAt)) evidence.recency.push({
507
- basis: "workspace-use",
508
- at: usedAt
509
- });
510
- }
511
- return classifyActivity(evidence, now);
512
- };
513
- }
514
- function workspaceActivity(workspace, now = Date.now()) {
515
- const dir = workspaceLogsDir$1(workspace);
516
- const state = readWorkspaceState$1(workspace);
517
- const recency = [];
518
- const deviceAt = latestRecordAt(tailLines(join(dir, "device.ndjson")) ?? [], (record) => record.src === "device" && isDeviceRecord(record));
519
- if (deviceAt !== null) recency.push({
520
- basis: "device-log",
521
- at: deviceAt
522
- });
523
- const bundleAt = latestRecordAt(tailLines(join(dir, "metro.ndjson")) ?? [], (record) => record.event === "bundle_response_started");
524
- if (bundleAt !== null) recency.push({
525
- basis: "metro-bundle",
526
- at: bundleAt
527
- });
528
- for (const [basis, value] of [["workspace-use", state?.lastUsedAt], ["supervisor-start", state?.supervisor?.startedAt]]) {
529
- const at = Date.parse(String(value ?? ""));
530
- if (Number.isFinite(at)) recency.push({
531
- basis,
532
- at
533
- });
534
- }
535
- return classifyActivity({
536
- drivers: [],
537
- unknown: [],
538
- recency
539
- }, now);
540
- }
541
- /**
542
- * The pids of processes connected to loopback `port` as clients, from `lsof -Fpn` output: a connection whose remote
543
- * end is the port. Chrome's own accepted sockets have the port as their local end and are skipped.
544
- */
545
- function parseTcpClients(output, port) {
546
- const pids = /* @__PURE__ */ new Set();
547
- let pid = null;
548
- for (const line of output.split("\n")) if (line.startsWith("p")) pid = Number(line.slice(1));
549
- else if (line.startsWith("n") && pid !== null && Number.isInteger(pid)) {
550
- const remote = line.slice(1).split("->")[1];
551
- if (remote && Number(remote.slice(remote.lastIndexOf(":") + 1)) === port) pids.add(pid);
552
- }
553
- return [...pids];
554
- }
555
- function webClientPids(connections, target) {
556
- return parseTcpClients(connections, target.port).filter((pid) => !target.ownPids.includes(pid));
557
- }
558
- function webDrivers(clients, processes) {
559
- return clients.flatMap((pid) => {
560
- const row = processes.find((candidate) => candidate.pid === pid);
561
- const tool = row ? cdpClientTool(row.command) : "unknown DevTools client";
562
- return tool ? [{
563
- tool,
564
- pid,
565
- since: row?.startedAt ?? null
566
- }] : [];
567
- });
568
- }
569
- /**
570
- * The DevTools clients of the owned browser that are not Stim's, read without blocking the event loop; null when
571
- * lsof or ps could not be read.
572
- */
573
- async function probeWebDrivers(target) {
574
- const exec = getExecutor();
575
- let connections;
576
- try {
577
- connections = await exec.runFileAsync("lsof", lsofArgs(target.port), { timeoutMs: 5e3 });
578
- } catch (error) {
579
- connections = lsofNoMatch(error);
580
- }
581
- if (connections === null) return null;
582
- const clients = webClientPids(connections, target);
583
- if (!clients.length) return [];
584
- let table;
585
- try {
586
- table = await exec.runFileAsync("ps", [
587
- "-axww",
588
- "-o",
589
- HOST_PROCESS_COLUMNS
590
- ], { timeoutMs: 5e3 });
591
- } catch {
592
- return null;
593
- }
594
- return webDrivers(clients, parseProcessTable(table));
595
- }
596
- /**
597
- * The owned browser's activity: a DevTools client other than Stim's is a driver (basis `cdp-client`). Recency comes
598
- * from the newest agent action the browser supervisor recorded (basis `agent-action`) and the newest other page
599
- * record (basis `page-log`).
600
- */
601
- function readWebActivity(target, tables, now = Date.now()) {
602
- const evidence = {
603
- drivers: [],
604
- unknown: [],
605
- recency: []
606
- };
607
- const connections = tables.tcpConnections(target.port);
608
- const clients = connections === null ? [] : webClientPids(connections, target);
609
- const processes = clients.length ? (tables.clients ?? tables.host)() : [];
610
- if (connections === null || processes === null) evidence.unknown.push("cdp-client");
611
- else for (const driver of webDrivers(clients, processes)) evidence.drivers.push({
612
- ...driver,
613
- basis: "cdp-client"
614
- });
615
- const lines = tailLines(join(workspaceLogsDir$1(target.workspace), "web.ndjson")) ?? [];
616
- const actionAt = latestRecordAt(lines, (record) => record.src === "agent");
617
- if (actionAt !== null) evidence.recency.push({
618
- basis: "agent-action",
619
- at: actionAt
620
- });
621
- const pageAt = latestRecordAt(lines, (record) => record.src !== "agent");
622
- if (pageAt !== null) evidence.recency.push({
623
- basis: "page-log",
624
- at: pageAt
625
- });
626
- return classifyActivity(evidence, now);
627
- }
628
- //#endregion
629
- export { envDir as a, probeWebDrivers as c, readWebActivity as d, tailLines as f, createDeviceProcessTables as i, processMatches as l, workspaceDeviceLastUseAt as m, agentDeviceLiveness as n, idleForMs as o, workspaceActivity as p, createActivityReader as r, parseAgentDeviceRecord as s, agentDeviceDaemon as t, readAgentDeviceRecords as u };