@xenon-device-management/xenon 2.13.2 → 2.15.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 (350) hide show
  1. package/README.md +17 -8
  2. package/lib/package.json +5 -5
  3. package/lib/public/assets/{AnnotationOverlay-BXruClDk.js → AnnotationOverlay-Btq3dZRI.js} +1 -1
  4. package/lib/public/assets/{ApiKeyGate-qTS4LPLC.js → ApiKeyGate-C9OoAgg_.js} +1 -1
  5. package/lib/public/assets/DeviceMosaicView-DBC_xczB.js +2 -0
  6. package/lib/public/assets/{EmptyState-Cr17PdDv.js → EmptyState-DqWU2-vM.js} +1 -1
  7. package/lib/public/assets/{FieldGroup-Bvn08svv.js → FieldGroup-CveQ3xrA.js} +1 -1
  8. package/lib/public/assets/{FilterMenu-DDSO8aDf.js → FilterMenu-BfKDSfHz.js} +1 -1
  9. package/lib/public/assets/{Menu-B-Qn2X3T.js → Menu-CtdCybzA.js} +1 -1
  10. package/lib/public/assets/{Modal-Cg9V5JYU.js → Modal-Bsvj1tm2.js} +1 -1
  11. package/lib/public/assets/{RecordingPage-BTUs9VTW.js → RecordingPage-CRofOiyx.js} +1 -1
  12. package/lib/public/assets/{RecordingsPage-DYcfxITK.js → RecordingsPage-jNQHb2IR.js} +2 -2
  13. package/lib/public/assets/{SegmentedControl-Zy7suhT5.js → SegmentedControl-C8HtTha-.js} +1 -1
  14. package/lib/public/assets/{SettingCard-CWYmycoe.js → SettingCard-D8K1LZNo.js} +1 -1
  15. package/lib/public/assets/{Table-io9fwa98.js → Table-zNTX92Pn.js} +1 -1
  16. package/lib/public/assets/{activity-Bdf_uIWl.js → activity-CJ8LwZq9.js} +1 -1
  17. package/lib/public/assets/ai-settings-CgxQZqrc.js +16 -0
  18. package/lib/public/assets/{api-keys-CPqtVpm3.js → api-keys-ECpo-zTo.js} +1 -1
  19. package/lib/public/assets/{apps-BgZan0H9.js → apps-BjGymyf3.js} +2 -2
  20. package/lib/public/assets/{arrow-left-B27ckB31.js → arrow-left-BWfCbeHP.js} +1 -1
  21. package/lib/public/assets/{arrow-right-DOF8ITCz.js → arrow-right-DC7UGf_n.js} +1 -1
  22. package/lib/public/assets/{arrow-up-right-eFG5KTFS.js → arrow-up-right-BOjwybDk.js} +1 -1
  23. package/lib/public/assets/{auth-shell-DlC3_27j.js → auth-shell-CxMTo9aH.js} +2 -2
  24. package/lib/public/assets/{builds-page-BuXpPfKo.js → builds-page-DOCm4HkA.js} +1 -1
  25. package/lib/public/assets/{button-fIW8owMI.js → button-Cg08-EMT.js} +1 -1
  26. package/lib/public/assets/{calendar-WNjmrF-a.js → calendar-CA1ikLJs.js} +1 -1
  27. package/lib/public/assets/{check-BdTh1Sq7.js → check-BMTaH72W.js} +1 -1
  28. package/lib/public/assets/{chevron-right-B4BKlsqk.js → chevron-right-B2QOv9Nx.js} +1 -1
  29. package/lib/public/assets/{circle-check-zJU80_EF.js → circle-check-CYXBoUqT.js} +1 -1
  30. package/lib/public/assets/{circle-x-5Uwquo0h.js → circle-x-DTwnSAnl.js} +1 -1
  31. package/lib/public/assets/{clock-BtUprDsZ.js → clock-C8_HViQP.js} +1 -1
  32. package/lib/public/assets/{copy-DGSbZI3u.js → copy-Be7LNMXV.js} +1 -1
  33. package/lib/public/assets/derive-UnLRp4r3.js +1 -0
  34. package/lib/public/assets/device-explorer-BOqtfGXz.js +282 -0
  35. package/lib/public/assets/{download-WG6l7BgD.js → download-B56lwxWP.js} +1 -1
  36. package/lib/public/assets/forgot-password-CCU6bzLn.js +1 -0
  37. package/lib/public/assets/h264Stream-C-OtmIuk.js +26 -0
  38. package/lib/public/assets/index-B9KQ6LsY.js +15 -0
  39. package/lib/public/assets/{index-DI1fGIyj.js → index-BOxe43p1.js} +5 -5
  40. package/lib/public/assets/{index-HDQVe1gi.js → index-CfxsUslp.js} +1 -1
  41. package/lib/public/assets/{input-BjDRKCea.js → input-CZHFjbSg.js} +1 -1
  42. package/lib/public/assets/{line-chart-C0zdgd0v.js → line-chart-Gl_Dz3X_.js} +1 -1
  43. package/lib/public/assets/{list-checks-BdW5CjM8.js → list-checks-CCgjeyGY.js} +1 -1
  44. package/lib/public/assets/{lock-Dy3L4I8E.js → lock-CkOwgDcx.js} +1 -1
  45. package/lib/public/assets/{login-BHbY9CLG.js → login-D5cc4w7M.js} +1 -1
  46. package/lib/public/assets/maintenance-settings-t7qr3fvX.js +6 -0
  47. package/lib/public/assets/{monitor-8xjkeHHi.js → monitor-DEJixKQO.js} +1 -1
  48. package/lib/public/assets/{mouse-pointer-2-CXdKMXQ8.js → mouse-pointer-2-CtOrk4M8.js} +1 -1
  49. package/lib/public/assets/{network-Cj8JOKON.js → network-Dii9qdvk.js} +1 -1
  50. package/lib/public/assets/{overview-CTg7F0im.js → overview-rolAACrO.js} +1 -1
  51. package/lib/public/assets/{page-header--aTyJXq6.js → page-header-COQZxJfR.js} +1 -1
  52. package/lib/public/assets/{play-B-FodgHV.js → play-DrN1Se_R.js} +1 -1
  53. package/lib/public/assets/{plus-CsIk10Cq.js → plus-5aq-9uRx.js} +1 -1
  54. package/lib/public/assets/{profile-page-DkFKkMfl.js → profile-page-6i5kY6kF.js} +1 -1
  55. package/lib/public/assets/{reset-password-I2-zqLlI.js → reset-password-sp2IBrc7.js} +1 -1
  56. package/lib/public/assets/runbook-page-DJDjeopU.js +253 -0
  57. package/lib/public/assets/{select-DvCSv25z.js → select-Bpyn7rWO.js} +1 -1
  58. package/lib/public/assets/{selector-detail-redirect-BLVfMJs_.js → selector-detail-redirect-BH74vmKv.js} +1 -1
  59. package/lib/public/assets/{selector-health-page-oqadRokn.js → selector-health-page-Cw_g218H.js} +2 -2
  60. package/lib/public/assets/session-detail-page-AZJE6XXE.js +4 -0
  61. package/lib/public/assets/settings-C3uyGhyc.js +6 -0
  62. package/lib/public/assets/{settings-Dep_3kbA.css → settings-K8UHWMdI.css} +1 -1
  63. package/lib/public/assets/{stat-tile-DV9Ix-4O.js → stat-tile-xVqAKIlI.js} +1 -1
  64. package/lib/public/assets/{tablet-6b_SEN2X.js → tablet-BxUScAeO.js} +1 -1
  65. package/lib/public/assets/{teams-BjZyfuHh.js → teams-B5ljGkY2.js} +1 -1
  66. package/lib/public/assets/{trash-2-CTZpPSdd.js → trash-2-B701i8sy.js} +1 -1
  67. package/lib/public/assets/{upload-P3XzwQUb.js → upload-C2gr44RS.js} +1 -1
  68. package/lib/public/assets/{use-builds-data-1cOCMf-z.js → use-builds-data-NeQOFEoy.js} +1 -1
  69. package/lib/public/assets/{use-password-reset-mode-DgF9w088.js → use-password-reset-mode-DEzJq5ef.js} +1 -1
  70. package/lib/public/assets/{users-DMF9Mk5H.js → users-D_vv_yz4.js} +1 -1
  71. package/lib/public/assets/{users-CiNTKUiz.js → users-MY6eNe6s.js} +1 -1
  72. package/lib/public/assets/{video-off-CHp1KU_T.js → video-off-OK1lNZQn.js} +1 -1
  73. package/lib/public/assets/webhook-settings-BU-C9lBf.js +1 -0
  74. package/lib/public/assets/{zap-DRz0tDq5.js → zap-DO9ry1iz.js} +1 -1
  75. package/lib/public/index.html +1 -1
  76. package/lib/schema.json +23 -25
  77. package/lib/src/XenonCapabilityManager.js +22 -5
  78. package/lib/src/app/dashboardPluginLink.js +117 -0
  79. package/lib/src/app/index.js +13 -34
  80. package/lib/src/app/openapi/control.yaml +73 -20
  81. package/lib/src/app/openapi/grid.yaml +31 -7
  82. package/lib/src/app/openapi/identity.yaml +103 -31
  83. package/lib/src/app/openapi/platform.yaml +165 -39
  84. package/lib/src/app/openapi/sessions.yaml +10 -3
  85. package/lib/src/app/routers/apikeys.js +14 -2
  86. package/lib/src/app/routers/auth.js +29 -5
  87. package/lib/src/app/routers/control.js +20 -2
  88. package/lib/src/app/routers/dashboard.js +69 -26
  89. package/lib/src/app/routers/grid.js +37 -13
  90. package/lib/src/app/routers/profile.js +21 -0
  91. package/lib/src/app/routers/streamType.js +7 -2
  92. package/lib/src/app/routers/users.js +10 -5
  93. package/lib/src/app/routers/webhook.js +8 -4
  94. package/lib/src/app/swagger.js +2 -0
  95. package/lib/src/app/ws/h264StreamWs.js +10 -1
  96. package/lib/src/config.js +51 -5
  97. package/lib/src/dashboard/commands.js +185 -141
  98. package/lib/src/dashboard/event-manager.js +88 -67
  99. package/lib/src/dashboard/services/failure-analysis-service.js +136 -45
  100. package/lib/src/dashboard/sessionCommandSummary.js +39 -0
  101. package/lib/src/data-service/appleFamily.js +43 -0
  102. package/lib/src/data-service/db.js +11 -0
  103. package/lib/src/data-service/device-service.js +6 -1
  104. package/lib/src/data-service/device-store.js +76 -3
  105. package/lib/src/data-service/deviceClaims.js +37 -0
  106. package/lib/src/data-service/deviceFieldOwners.js +25 -11
  107. package/lib/src/data-service/deviceSettings.js +79 -0
  108. package/lib/src/data-service/prisma-store.js +169 -15
  109. package/lib/src/data-service/web-config-service.js +50 -92
  110. package/lib/src/device-managers/AndroidDeviceManager.js +9 -31
  111. package/lib/src/device-managers/android/AndroidH264StreamService.js +69 -20
  112. package/lib/src/device-managers/android/H264Multiplexer.js +38 -4
  113. package/lib/src/device-managers/ios/WDAClient.js +44 -43
  114. package/lib/src/device-managers/shellCommands.js +96 -0
  115. package/lib/src/device-utils.js +114 -40
  116. package/lib/src/gateway/defaultGateway.js +1 -1
  117. package/lib/src/gateway/forwardToNode.js +2 -0
  118. package/lib/src/gateway/healReport.js +87 -0
  119. package/lib/src/gateway/sessionGateway.js +12 -2
  120. package/lib/src/generated/client/edge.js +18 -3
  121. package/lib/src/generated/client/index-browser.js +15 -0
  122. package/lib/src/generated/client/index.d.ts +2086 -379
  123. package/lib/src/generated/client/index.js +18 -3
  124. package/lib/src/generated/client/package.json +1 -1
  125. package/lib/src/generated/client/schema.prisma +38 -7
  126. package/lib/src/generated/client/wasm.js +15 -0
  127. package/lib/src/interceptors/CommandInterceptor.js +271 -188
  128. package/lib/src/interceptors/xenonScripts.js +55 -0
  129. package/lib/src/interfaces/IPluginArgs.js +1 -2
  130. package/lib/src/middleware/authMiddleware.js +15 -3
  131. package/lib/src/middleware/commandCaller.js +3 -3
  132. package/lib/src/middleware/verifyCredential.js +58 -1
  133. package/lib/src/plugin.js +23 -4
  134. package/lib/src/prisma.js +1 -1
  135. package/lib/src/scripts/database-check.js +124 -0
  136. package/lib/src/services/AICommandService.js +9 -2
  137. package/lib/src/services/AIService.js +281 -32
  138. package/lib/src/services/CleanupService.js +6 -1
  139. package/lib/src/services/EmailService.js +29 -0
  140. package/lib/src/services/InterceptorService.js +70 -13
  141. package/lib/src/services/NetworkConditioningService.js +85 -88
  142. package/lib/src/services/NotificationService.js +36 -29
  143. package/lib/src/services/OrphanSweeper.js +7 -0
  144. package/lib/src/services/PortAllocator.js +5 -0
  145. package/lib/src/services/SelectorVerificationJob.js +15 -4
  146. package/lib/src/services/ServerManager.js +105 -9
  147. package/lib/src/services/SessionLifecycleService.js +133 -75
  148. package/lib/src/services/ShutdownCoordinator.js +33 -0
  149. package/lib/src/services/SocketServer.js +19 -3
  150. package/lib/src/services/TeamService.js +20 -3
  151. package/lib/src/services/bug-report/video-slice.js +4 -1
  152. package/lib/src/services/device-access/leaseOverride.js +7 -5
  153. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +51 -0
  154. package/lib/src/services/healing/HealEtalonService.js +3 -2
  155. package/lib/src/services/healing/HealingOrchestrator.js +85 -71
  156. package/lib/src/services/healing/OcrHealingProvider.js +41 -64
  157. package/lib/src/services/healing/ResilioTreeHealingProvider.js +41 -50
  158. package/lib/src/services/healing/VisualAiHealingProvider.js +1 -1
  159. package/lib/src/services/healing/fingerprintIdentity.js +126 -0
  160. package/lib/src/services/healing/resilioPath.js +274 -0
  161. package/lib/src/services/interceptor/AndroidProxyAdapter.js +18 -0
  162. package/lib/src/services/interceptor/interceptorOptions.js +44 -0
  163. package/lib/src/services/logcat/SessionDeviceLogs.js +271 -0
  164. package/lib/src/services/logcat/deviceLogBook.js +163 -0
  165. package/lib/src/services/network/AndroidRadios.js +71 -0
  166. package/lib/src/services/network/PhoneNetworkLedger.js +184 -0
  167. package/lib/src/services/network/PhoneNetworkRestore.js +330 -0
  168. package/lib/src/services/network/adbForPhone.js +60 -0
  169. package/lib/src/services/network/phoneNetworkLock.js +20 -0
  170. package/lib/src/services/network/xenonProxy.js +107 -0
  171. package/lib/src/services/ocr/ocrData.js +118 -0
  172. package/lib/src/services/ocr/vendor/LICENSE-tessdata.txt +202 -0
  173. package/lib/src/services/ocr/vendor/eng.traineddata.gz +0 -0
  174. package/lib/src/services/omni-vision/OmniVisionService.js +132 -95
  175. package/lib/src/services/omni-vision/VisionAssertionService.js +28 -25
  176. package/lib/src/services/omni-vision/ocrTextMatch.js +105 -0
  177. package/lib/src/services/omni-vision/screenScale.js +68 -0
  178. package/lib/src/services/passwordResetLink.js +50 -9
  179. package/lib/src/services/passwordResetMode.js +3 -1
  180. package/lib/src/services/publicUrl.js +45 -0
  181. package/lib/src/services/recording/concurrency-gate.js +12 -3
  182. package/lib/src/services/session/sessionIdentity.js +5 -3
  183. package/lib/src/services/session/shutdownReason.js +26 -0
  184. package/lib/src/services/settings/SelfHealingSwitch.js +70 -0
  185. package/lib/src/services/settings/aiEngineSettings.js +219 -0
  186. package/lib/src/services/settings/labSettings.js +149 -0
  187. package/lib/src/services/token/mintedLifetime.js +51 -0
  188. package/lib/src/services/webhookEvents.js +173 -0
  189. package/lib/src/sessions/SessionManager.js +8 -2
  190. package/lib/src/sessions/sessionMemory.js +25 -0
  191. package/lib/test/helpers/fake-adb.js +58 -0
  192. package/lib/test/helpers/fake-ai-provider.js +188 -0
  193. package/lib/test/helpers/fake-device-table.js +63 -24
  194. package/lib/test/helpers/loki-stores.js +33 -0
  195. package/lib/test/helpers/page-sources.js +164 -0
  196. package/lib/test/helpers/scratch-database.js +58 -13
  197. package/lib/test/integration/audit-ingest.spec.js +10 -10
  198. package/lib/test/integration/auth-flow.spec.js +9 -14
  199. package/lib/test/integration/auth-rate-limit.spec.js +6 -3
  200. package/lib/test/integration/bug-report-route.spec.js +22 -2
  201. package/lib/test/integration/forgot-password-rate-limit.spec.js +6 -3
  202. package/lib/test/integration/forgot-password.spec.js +17 -18
  203. package/lib/test/integration/legacy-deprecation-headers.spec.js +5 -2
  204. package/lib/test/integration/migration.spec.js +6 -1
  205. package/lib/test/integration/node-pair-auth-rest.spec.js +5 -9
  206. package/lib/test/integration/ports-router.spec.js +4 -4
  207. package/lib/test/integration/prisma-device-store-add-devices.spec.js +2 -3
  208. package/lib/test/integration/prisma-device-store-team-filter.spec.js +2 -5
  209. package/lib/test/integration/profile-tokens.spec.js +10 -16
  210. package/lib/test/integration/recordings-router.spec.js +16 -16
  211. package/lib/test/integration/reset-revokes-sessions.spec.js +4 -9
  212. package/lib/test/integration/role-matrix.spec.js +4 -9
  213. package/lib/test/integration/sdk-leases-router.spec.js +9 -9
  214. package/lib/test/integration/sdk-version.spec.js +2 -2
  215. package/lib/test/integration/selector-health-endpoint.spec.js +5 -5
  216. package/lib/test/integration/team-membership-migration.spec.js +73 -12
  217. package/lib/test/integration/team-visibility-apps.spec.js +15 -22
  218. package/lib/test/integration/team-visibility-control.spec.js +96 -69
  219. package/lib/test/integration/team-visibility-dashboard.spec.js +7 -23
  220. package/lib/test/integration/team-visibility-grid.spec.js +16 -15
  221. package/lib/test/integration/team-visibility-leases.spec.js +8 -11
  222. package/lib/test/integration/team-visibility-recordings.spec.js +6 -19
  223. package/lib/test/integration/team-visibility-sessions.spec.js +6 -19
  224. package/lib/test/integration/users-flow.spec.js +7 -12
  225. package/lib/test/integration/users-lockout.spec.js +5 -3
  226. package/lib/test/unit/EmailService.test.js +66 -0
  227. package/lib/test/unit/ResilioTreeHealingProvider.test.js +46 -19
  228. package/lib/test/unit/TeamService.test.js +3 -0
  229. package/lib/test/unit/XenonCapabilityManager.spec.js +4 -2
  230. package/lib/test/unit/ai-call-time-limit.spec.js +130 -0
  231. package/lib/test/unit/ai-engine-settings.spec.js +338 -0
  232. package/lib/test/unit/ai-provider-switch.spec.js +130 -0
  233. package/lib/test/unit/ai-rate-limit.spec.js +126 -0
  234. package/lib/test/unit/android-h264-viewers.spec.js +272 -0
  235. package/lib/test/unit/android-preview-hold.spec.js +3 -2
  236. package/lib/test/unit/apikeys-router.spec.js +84 -0
  237. package/lib/test/unit/apple-family.spec.js +36 -0
  238. package/lib/test/unit/authMiddleware.bearer.spec.js +9 -0
  239. package/lib/test/unit/authMiddleware.credentialLifetime.spec.js +149 -0
  240. package/lib/test/unit/bug-report/video-slice.spec.js +19 -0
  241. package/lib/test/unit/cleanup-settings-db.spec.js +103 -0
  242. package/lib/test/unit/cleanup-settings.spec.js +244 -0
  243. package/lib/test/unit/dashboard-api-paths.spec.js +101 -0
  244. package/lib/test/unit/dashboard-commands.spec.js +249 -0
  245. package/lib/test/unit/dashboard-events-device-logs.spec.js +207 -0
  246. package/lib/test/unit/dashboard-events-team-scope.spec.js +9 -6
  247. package/lib/test/unit/dashboard-plugin-link.spec.js +213 -0
  248. package/lib/test/unit/database-check.spec.js +108 -0
  249. package/lib/test/unit/default-plugin-args.spec.js +33 -0
  250. package/lib/test/unit/device-log-book.spec.js +180 -0
  251. package/lib/test/unit/device-offline-webhook.spec.js +81 -0
  252. package/lib/test/unit/device-setting-columns.spec.js +66 -0
  253. package/lib/test/unit/device-settings-loki.spec.js +87 -0
  254. package/lib/test/unit/device-settings-survive.spec.js +555 -0
  255. package/lib/test/unit/device-sync-lost-update.spec.js +5 -0
  256. package/lib/test/unit/emulator-boot.spec.js +91 -0
  257. package/lib/test/unit/enable-dashboard-option.spec.js +57 -0
  258. package/lib/test/unit/event-log-session-data.spec.js +244 -0
  259. package/lib/test/unit/failure-analysis.spec.js +182 -0
  260. package/lib/test/unit/failure-categories.spec.js +128 -0
  261. package/lib/test/unit/fingerprint-identity.spec.js +433 -0
  262. package/lib/test/unit/h264-multiplexer.spec.js +46 -0
  263. package/lib/test/unit/heal-report.spec.js +71 -0
  264. package/lib/test/unit/healing-instrumentation.spec.js +6 -1
  265. package/lib/test/unit/healing-tier-gate.spec.js +73 -29
  266. package/lib/test/unit/healing-tiers-every-session.spec.js +219 -0
  267. package/lib/test/unit/hub-node-gateway-appium-server.spec.js +219 -0
  268. package/lib/test/unit/hub-node-same-host.spec.js +5 -0
  269. package/lib/test/unit/interceptor-visual-elements.spec.js +192 -0
  270. package/lib/test/unit/iphone-ipad-only.spec.js +132 -0
  271. package/lib/test/unit/json-logging-option.spec.js +74 -0
  272. package/lib/test/unit/lab-settings.spec.js +218 -0
  273. package/lib/test/unit/lease/lease-override.spec.js +23 -6
  274. package/lib/test/unit/lease/session-lease-proof.spec.js +16 -4
  275. package/lib/test/unit/max-sessions.spec.js +240 -0
  276. package/lib/test/unit/ocr-healing-tier-real-ocr.spec.js +113 -0
  277. package/lib/test/unit/ocr-healing-tier.spec.js +122 -0
  278. package/lib/test/unit/ocr-offline.spec.js +213 -0
  279. package/lib/test/unit/ocr-text-match.spec.js +44 -0
  280. package/lib/test/unit/omni-virtual-element-store.spec.js +301 -0
  281. package/lib/test/unit/omni-vision-analyze-screen.spec.js +72 -0
  282. package/lib/test/unit/omni-vision-ios-points.spec.js +159 -0
  283. package/lib/test/unit/omni-vision-tap-text.spec.js +129 -0
  284. package/lib/test/unit/omni-vision.spec.js +6 -8
  285. package/lib/test/unit/package-engines.spec.js +27 -0
  286. package/lib/test/unit/partial-config-file.spec.js +14 -0
  287. package/lib/test/unit/passwordResetMode.test.js +10 -2
  288. package/lib/test/unit/phone-network/boot-clean-up.spec.js +64 -0
  289. package/lib/test/unit/phone-network/interceptor-options.spec.js +77 -0
  290. package/lib/test/unit/phone-network/interceptor-proxy-restore.spec.js +145 -0
  291. package/lib/test/unit/phone-network/network-conditioning.spec.js +145 -0
  292. package/lib/test/unit/phone-network/phone-network-restore.spec.js +246 -0
  293. package/lib/test/unit/phone-network/session-end-paths.spec.js +182 -0
  294. package/lib/test/unit/phone-network/session-start.spec.js +110 -0
  295. package/lib/test/unit/phone-network/xenon-proxy.spec.js +69 -0
  296. package/lib/test/unit/plugin.spec.js +3 -3
  297. package/lib/test/unit/profile-router.test.js +122 -1
  298. package/lib/test/unit/queue-requester.spec.js +1 -1
  299. package/lib/test/unit/recording-options.spec.js +181 -0
  300. package/lib/test/unit/reset-link-address.spec.js +266 -0
  301. package/lib/test/unit/reset-link.test.js +10 -4
  302. package/lib/test/unit/resilio-path-healing.spec.js +270 -0
  303. package/lib/test/unit/selector-learning-every-session.spec.js +179 -0
  304. package/lib/test/unit/selector-verification-clean-build.spec.js +130 -0
  305. package/lib/test/unit/selector-verification-job.spec.js +13 -13
  306. package/lib/test/unit/self-healing-boot.spec.js +80 -0
  307. package/lib/test/unit/self-healing-setting.spec.js +273 -0
  308. package/lib/test/unit/session-app-resolution.spec.js +5 -1
  309. package/lib/test/unit/session-attribution-wiring.spec.js +41 -13
  310. package/lib/test/unit/session-create-credential-owner.spec.js +242 -0
  311. package/lib/test/unit/session-credential-strip.spec.js +1 -1
  312. package/lib/test/unit/session-device-logs.spec.js +347 -0
  313. package/lib/test/unit/session-end-failure-analysis.spec.js +133 -0
  314. package/lib/test/unit/session-failed-webhook.spec.js +170 -0
  315. package/lib/test/unit/session-log-indexes.spec.js +64 -3
  316. package/lib/test/unit/shell-commands.spec.js +133 -0
  317. package/lib/test/unit/socketServer.scopedEmit.spec.js +2 -0
  318. package/lib/test/unit/socketServer.sessionCookie.spec.js +2 -1
  319. package/lib/test/unit/stream-start-pipelines.spec.js +264 -0
  320. package/lib/test/unit/stream-status-type.spec.js +4 -0
  321. package/lib/test/unit/token-mint-limits.spec.js +165 -0
  322. package/lib/test/unit/unexpected-shutdown-reason.spec.js +163 -0
  323. package/lib/test/unit/verify-credential.spec.js +33 -0
  324. package/lib/test/unit/vision-assertion.spec.js +119 -0
  325. package/lib/test/unit/wda-client-shell.spec.js +133 -0
  326. package/lib/test/unit/web-config-service.spec.js +98 -0
  327. package/lib/test/unit/webhook-delivery.spec.js +24 -0
  328. package/lib/test/unit/webhook-payloads.spec.js +273 -0
  329. package/lib/test/unit/xenon-execute-scripts.spec.js +138 -0
  330. package/lib/tsconfig.tsbuildinfo +1 -1
  331. package/lib/web/src/components/webhook-settings/webhookEventVariables.json +30 -0
  332. package/package.json +5 -5
  333. package/prisma/migrations/20261004140000_keep_device_settings/migration.sql +19 -0
  334. package/prisma/migrations/20261004174413_locator_etalon_path/migration.sql +2 -0
  335. package/prisma/schema.prisma +38 -7
  336. package/schema.json +23 -25
  337. package/scripts/generate-types-from-schema.js +1 -2
  338. package/scripts/lib/always-present-plugin-args.js +4 -1
  339. package/lib/public/assets/BugReportButton-BoGhlI7F.js +0 -15
  340. package/lib/public/assets/DeviceMosaicView-8J0oYqMM.js +0 -2
  341. package/lib/public/assets/ai-settings-Bce5SJob.js +0 -21
  342. package/lib/public/assets/device-explorer-C-KnhMHI.js +0 -279
  343. package/lib/public/assets/forgot-password-DnudqFFo.js +0 -1
  344. package/lib/public/assets/maintenance-settings-zDVlOMVK.js +0 -6
  345. package/lib/public/assets/recording-group-store-WVM3hoXn.js +0 -26
  346. package/lib/public/assets/runbook-page-DJTVCJX7.js +0 -124
  347. package/lib/public/assets/session-detail-page-CGn55Pvl.js +0 -4
  348. package/lib/public/assets/settings-MsVU2ukE.js +0 -6
  349. package/lib/public/assets/webhook-settings-DiS8geIm.js +0 -1
  350. /package/lib/public/assets/{BugReportButton-CPBjfiv4.css → index-CPBjfiv4.css} +0 -0
@@ -1,4 +1,4 @@
1
- import{c as ae,p as ne,r as d,j as t,A as fe,v as re,z as ve,w as ge,t as le,X as I,e as be,G as ye,b as je,P as Ne}from"./index-DI1fGIyj.js";import{P as Se}from"./page-header--aTyJXq6.js";import{a as ke}from"./SegmentedControl-Zy7suhT5.js";import{B as N}from"./button-fIW8owMI.js";import{S as we}from"./stat-tile-DV9Ix-4O.js";import{L as ie,n as Ce,C as Ae}from"./line-chart-C0zdgd0v.js";import{E as $e}from"./EmptyState-Cr17PdDv.js";import{I as Me}from"./input-BjDRKCea.js";import{S as O}from"./select-DvCSv25z.js";import{s as _,r as Y,w as Ee,P as Te,b as _e}from"./view-state-83Z1gFME.js";import{p as Le}from"./labels-C21SA4JG.js";import{M as R}from"./Modal-Cg9V5JYU.js";import{C as Ie}from"./check-BdTh1Sq7.js";import{C as oe}from"./copy-DGSbZI3u.js";import"./utils-CDN07tui.js";import"./index-HDQVe1gi.js";/**
1
+ import{c as ae,p as ne,r as d,j as t,A as fe,v as re,z as ve,w as ge,t as le,X as I,e as be,H as ye,b as je,Q as Ne}from"./index-BOxe43p1.js";import{P as Se}from"./page-header-COQZxJfR.js";import{a as ke}from"./SegmentedControl-C8HtTha-.js";import{B as N}from"./button-Cg08-EMT.js";import{S as we}from"./stat-tile-xVqAKIlI.js";import{L as ie,n as Ce,C as Ae}from"./line-chart-Gl_Dz3X_.js";import{E as $e}from"./EmptyState-DqWU2-vM.js";import{I as Me}from"./input-CZHFjbSg.js";import{S as H}from"./select-Bpyn7rWO.js";import{s as _,r as Y,w as Ee,P as Te,b as _e}from"./view-state-83Z1gFME.js";import{p as Le}from"./labels-C21SA4JG.js";import{M as R}from"./Modal-Bsvj1tm2.js";import{C as Ie}from"./check-BMTaH72W.js";import{C as oe}from"./copy-Be7LNMXV.js";import"./utils-CDN07tui.js";import"./index-CfxsUslp.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -8,4 +8,4 @@ import{c as ae,p as ne,r as d,j as t,A as fe,v as re,z as ve,w as ge,t as le,X a
8
8
  *
9
9
  * This source code is licensed under the ISC license.
10
10
  * See the LICENSE file in the root directory of this source tree.
11
- */const Pe=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],Re=ae("send",Pe),Fe=3e4,ze=5*6e4;function Oe({onShow:e}){const{on:n}=ne(),[s,l]=d.useState([]);if(d.useEffect(()=>{const o=n("selector_regressed",r=>{l(i=>{const u=Date.now()-ze;return[...i.filter(b=>b.receivedAt>=u),{strategy:(r==null?void 0:r.original_strategy)??"",selector:(r==null?void 0:r.original_selector)??"",receivedAt:Date.now()}]})});return()=>{o&&o()}},[n]),d.useEffect(()=>{if(s.length===0)return;const o=setTimeout(()=>l([]),Fe);return()=>clearTimeout(o)},[s]),s.length===0)return null;const c=s.length===1?s[0]:null;return t.jsxs("div",{role:"alert",className:"flex items-center gap-3 rounded-lg border border-[var(--color-warning)] bg-[var(--surface)] px-4 py-2.5 text-sm text-[var(--text)]",children:[t.jsx(fe,{size:14,className:"shrink-0 text-[var(--color-warning)]","aria-hidden":"true"}),t.jsx("span",{className:"min-w-0 flex-1 truncate",children:c?t.jsxs(t.Fragment,{children:["A selector you fixed broke again:"," ",t.jsx("code",{className:"font-mono text-xs",title:c.selector,children:c.selector})]}):`${s.length} selectors you fixed broke again in the last 5 minutes.`}),t.jsx(N,{variant:"secondary",size:"sm",onClick:()=>{e(s.map(({strategy:o,selector:r})=>({strategy:o,selector:r}))),l([])},children:"Show selectors to fix"}),t.jsx("button",{type:"button","aria-label":"Dismiss",onClick:()=>l([]),className:"rounded p-1 text-[var(--text-muted)] hover:text-[var(--text)]",children:t.jsx(re,{size:13})})]})}const He={"accessibility id":"Accessibility ID",xpath:"XPath",id:"ID",name:"Name","class name":"Class Name","-android uiautomator":"UiAutomator","-ios predicate string":"iOS Predicate","-ios class chain":"iOS Class Chain","xenon:visual":"Visual AI (coords)"};function Ue(e){return e?He[e]??e:"(unknown strategy)"}const Xe={fix:"To fix",verifying:"Being verified",fixed:"Fixed",muted:"Muted"},qe={heals:"Most heals",recent:"Most recent",time:"Most time spent healing"},Ve=["Resilio","Native","Fuzzy XML","OCR","Visual AI","LLM"],P={Resilio:"Found it from its saved fingerprint",Native:"Found it again with the original selector","Fuzzy XML":"Found the closest match in the screen's structure",OCR:"Found it by reading the text on screen","Visual AI":"Found it in a screenshot with AI",LLM:"Asked a language model to find it"},Ke=[{value:"android",label:"Android"},{value:"ios",label:"iOS"},{value:"tvos",label:"tvOS"}];function J(e){if(!(e>0))return"0 s";const n=e/1e3;if(n<1)return"<1 s";if(Math.round(n)<60)return`${Math.round(n)} s`;const s=n/60;if(Math.round(s)<60)return`${Math.round(s)} min`;const l=s/60;return`${l<10?l.toFixed(1):Math.round(l)} h`}function q(e,n=Date.now()){if(!e)return"—";const s=Date.parse(e);if(!Number.isFinite(s))return"—";const l=Math.floor(Math.max(0,n-s)/6e4);if(l<1)return"just now";if(l<60)return`${l} min ago`;const c=Math.floor(l/60);if(c<24)return`${c} h ago`;const o=Math.floor(c/24);return o===1?"yesterday":`${o} days ago`}function ce(e){return new Date(e).toLocaleDateString(void 0,{weekday:"short",day:"numeric",month:"short"})}function V(e){if(!e)return"—";const n=Date.parse(e);return Number.isFinite(n)?new Date(n).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"—"}function Ge(e,n,s,l){const c=`the ${s} days before`;if(e===n)return{text:`Same as ${c}`,tone:"neutral"};if(n===0)return{text:`None ${c}`,tone:"bad"};const o=e>n,r=o?"bad":"good";if(l==="count")return{text:`${Math.abs(e-n)} ${o?"more":"fewer"} than ${c}`,tone:r};if(l==="duration")return{text:`${J(Math.abs(e-n))} ${o?"more":"less"} than ${c}`,tone:r};const i=Math.round(Math.abs(e-n)/n*100);return i===0?{text:`About the same as ${c}`,tone:"neutral"}:{text:`${i}% ${o?"more":"fewer"} than ${c}`,tone:r}}function de(e){return`${Math.round(e*100)}% of heals`}function K(e){return e?Ue(e):"Unknown type"}function Je(e){switch(e==null?void 0:e.status){case"pending":return`Being verified, ${e.cleanBuilds} of 3 clean builds`;case"resolved":return"Fixed";case"muted":return"Muted";default:return"To fix"}}function G(e){return e!=null&&e.name?` by ${e.name}`:""}const We={marked_fixed:"Marked fixed",verification_cancelled:"Verification cancelled",verified:"Verified after 3 clean builds",broke_again:"Broke again",muted:"Muted",unmuted:"Unmuted"};function Ye(e){return`${We[e.action]??"Changed"}${G(e.by)}`}const H=e=>e.toLocaleString(),Qe=({summary:e,days:n})=>{const s=e==null?void 0:e.current,l=e==null?void 0:e.prior,c=[{label:"Selectors that needed healing",value:s==null?void 0:s.distinctSelectors,before:l==null?void 0:l.distinctSelectors,kind:"count",show:H},{label:"Heals",value:s==null?void 0:s.totalHeals,before:l==null?void 0:l.totalHeals,kind:"percent",show:H},{label:"Sessions affected",value:s==null?void 0:s.sessionsTouched,before:l==null?void 0:l.sessionsTouched,kind:"percent",show:H},{label:"Time spent healing",value:s==null?void 0:s.timeSpentMs,before:l==null?void 0:l.timeSpentMs,kind:"duration",show:J}];return t.jsx("div",{className:"grid grid-cols-4 gap-3",children:c.map(o=>{const r=o.value!==void 0&&o.before!==void 0?Ge(o.value,o.before,n,o.kind):null;return t.jsx(we,{label:o.label,value:o.value!==void 0?o.show(o.value):"—",note:r==null?void 0:r.text,noteTone:(r==null?void 0:r.tone)??"neutral"},o.label)})})},Q="var(--color-info)",Z="var(--color-warning)",ee=({color:e,label:n,total:s})=>t.jsxs("span",{className:"flex items-center gap-1.5",children:[t.jsx("span",{className:"inline-block h-0.5 w-3",style:{background:e}}),t.jsx("span",{children:n}),t.jsx("span",{className:"tabular-nums text-[var(--text)]",children:s.toLocaleString()})]}),Ze=({trend:e,days:n,failed:s})=>{var h;const l=d.useMemo(()=>e??[],[e]),c=((h=l[0])==null?void 0:h.t)??0,o=l.reduce((m,y)=>m+y.heals,0),r=l.reduce((m,y)=>m+y.aiHeals,0),i=d.useMemo(()=>l.map(m=>m.t-c),[l,c]),u=d.useMemo(()=>[{key:"heals",label:"All heals",color:Q,values:l.map(m=>m.heals)},{key:"ai",label:"Heals that used AI",color:Z,values:l.map(m=>m.aiHeals)}],[l]),b=l.reduce((m,y)=>Math.max(m,y.heals),0);let p;return e===null&&s?p=t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"Couldn't load heals per day. Try again in a moment."}):e===null?p=t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"Loading…"}):o===0?p=t.jsxs("div",{className:"text-xs text-[var(--text-dim)]",children:["No heals in the last ",n," days."]}):p=t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"mb-2 flex flex-wrap gap-x-4 gap-y-1 text-[11px] text-[var(--text-muted)]",children:[t.jsx(ee,{color:Q,label:"All heals",total:o}),t.jsx(ee,{color:Z,label:"Heals that used AI",total:r})]}),t.jsx(ie,{times:i,series:u,yMax:Ce(b),formatValue:m=>String(Math.round(m)),formatTime:m=>ce(c+m),ariaLabel:"Heals per day",height:120})]}),t.jsx(Ae,{header:"Heals per day",children:p})},D=({title:e,tone:n="neutral",children:s})=>t.jsx("span",{title:e,className:`inline-block max-w-full truncate rounded px-1.5 py-px text-[10px] font-medium ${n==="warning"?"border border-[var(--color-warning)] text-[var(--color-warning)]":"bg-[rgb(var(--rgb-fg)/0.06)] text-[var(--text-muted)]"}`,children:s}),te=({strategy:e,text:n,extra:s})=>t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"mb-0.5 flex min-w-0 items-center gap-1.5",children:[t.jsx(D,{children:K(e)}),s]}),t.jsx("code",{className:"line-clamp-2 break-all font-mono text-[11px] leading-snug text-[var(--text)]",title:n,children:n})]}),et=300,tt=["fix","verifying","fixed","muted"],st=["heals","recent","time"],E=e=>t.jsx("span",{className:"text-xs text-[var(--text-muted)]",children:e});function at(e,n,s){const l={key:"selector",label:"Selector",cell:r=>t.jsx(te,{strategy:r.strategy,text:r.selector,extra:e==="fix"&&r.state&&r.state.brokeAgain>0?t.jsx(D,{tone:"warning",children:"Broke again"}):null})},c=r=>({key:"heals",label:r,width:"96px",cell:i=>t.jsxs("div",{children:[t.jsx("div",{className:"font-semibold tabular-nums text-[var(--text)]",children:i.heals.toLocaleString()}),t.jsxs("div",{className:"text-[11px] text-[var(--text-muted)]",children:[i.sessions," ",i.sessions===1?"session":"sessions"]})]})}),o={key:"last",label:"Last healed",width:"104px",cell:r=>E(q(r.lastHealedAt))};switch(e){case"fix":return n?[l,c("Heals"),o]:[l,c("Heals"),o,{key:"method",label:"Healed by",width:"112px",cell:r=>r.topMethod?t.jsx(D,{title:P[r.topMethod],children:r.topMethod}):E("—")},{key:"fix",label:"Suggested fix",width:"34%",cell:r=>r.suggestion?t.jsx(te,{strategy:r.suggestion.strategy,text:r.suggestion.selector,extra:t.jsx("span",{className:"text-[10px] text-[var(--text-muted)]",children:de(r.suggestion.share)})}):E("None yet")}];case"verifying":{const r={key:"progress",label:"Progress",width:"150px",cell:i=>{var u;return t.jsxs("span",{className:"text-xs text-[var(--text)]",children:[((u=i.state)==null?void 0:u.cleanBuilds)??0," of 3 clean builds"]})}};return n?[l,r]:[l,r,{key:"marked",label:"Marked fixed",width:"180px",cell:i=>{var u,b;return E(`${q(((u=i.state)==null?void 0:u.fixedAt)??null)}${G(((b=i.state)==null?void 0:b.fixedBy)??null)}`)}},c(`Heals, ${s} days`)]}case"fixed":{const r={key:"verified",label:"Verified",width:"140px",cell:i=>{var u;return E(V(((u=i.state)==null?void 0:u.resolvedAt)??null))}};return n?[l,r]:[l,r,c(`Heals, ${s} days`)]}case"muted":{const r={key:"muted",label:"Muted",width:"180px",cell:i=>{var u,b;return E(`${V(((u=i.state)==null?void 0:u.mutedAt)??null)}${G(((b=i.state)==null?void 0:b.mutedBy)??null)}`)}};return n?[l,r]:[l,r,{key:"reason",label:"Reason",width:"26%",cell:i=>{var u;return(u=i.state)!=null&&u.muteReason?t.jsx("span",{className:"line-clamp-2 text-xs text-[var(--text)]",children:i.state.muteReason}):E("No reason given")}},c(`Heals, ${s} days`)]}}}function nt(e,n,s){if(n)return{title:`No selectors match “${n}”`,description:"Try fewer or different words."};switch(e){case"fix":return{title:`Nothing to fix in the last ${s} days`,description:"Every selector your tests used was found without healing."};case"verifying":return{title:"Nothing being verified",description:"When you mark a selector fixed, Xenon watches its next 3 clean builds here."};case"fixed":return{title:`Nothing fixed in the last ${s} days`,description:"Selectors that pass 3 clean builds after being marked fixed show here."};case"muted":return{title:"Nothing muted",description:"A muted selector is left out of this list, the CI gate and the digest."}}}const rt=({view:e,data:n,loading:s,compact:l,selectedKey:c,onView:o,onOpen:r,error:i})=>{const[u,b]=d.useState(e.q);d.useEffect(()=>b(e.q),[e.q]),d.useEffect(()=>{if(u===e.q)return;const a=setTimeout(()=>o({q:u,page:1}),et);return()=>clearTimeout(a)},[u,e.q,o]);const p=at(e.tab,l,e.days),h=n&&n.tab===e.tab?n:null,m=(h==null?void 0:h.items)??[],y=(h==null?void 0:h.total)??0,k=(h==null?void 0:h.page)??e.page,w=(h==null?void 0:h.pageSize)??50,T=Math.max(1,Math.ceil(y/w)),A=y===0?0:(k-1)*w+1,C=Math.min(y,k*w),$=nt(e.tab,e.q,e.days);return t.jsxs("section",{"aria-label":"Selectors",className:"rounded-lg border border-[var(--border)] bg-[var(--surface)]",children:[t.jsx("div",{role:"tablist","aria-label":"Selector status",className:"flex gap-1 border-b border-[var(--border)] px-3",children:tt.map(a=>{var j;const g=e.tab===a,f=(j=n==null?void 0:n.counts)==null?void 0:j[a];return t.jsxs("button",{type:"button",role:"tab","aria-selected":g,onClick:()=>{g||o({tab:a,page:1})},className:`-mb-px flex items-center gap-2 border-b-2 px-3 py-2.5 text-sm ${g?"border-[var(--color-accent)] font-medium text-[var(--text)]":"border-transparent text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:[Xe[a],t.jsx("span",{className:"rounded-full bg-[rgb(var(--rgb-fg)/0.08)] px-1.5 text-[11px] tabular-nums",children:typeof f=="number"?f.toLocaleString():"–"})]},a)})}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2 border-b border-[var(--border)] px-3 py-2.5",children:[t.jsxs("div",{className:"relative min-w-[220px] flex-1",children:[t.jsx(ve,{size:14,"aria-hidden":"true",className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--text-dim)]"}),t.jsx(Me,{type:"search","aria-label":"Search",value:u,onChange:a=>b(a.target.value),placeholder:e.tab==="fix"?"Search selectors and fixes":"Search selectors",className:"h-8 w-full pl-8 pr-2 text-xs"})]}),e.tab==="fix"&&t.jsxs(t.Fragment,{children:[t.jsxs(O,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Platform",value:e.platform,onChange:a=>o({platform:a.target.value,page:1}),children:[t.jsx("option",{value:"",children:"All platforms"}),Ke.map(a=>t.jsx("option",{value:a.value,children:a.label},a.value))]}),t.jsxs(O,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Healing method",value:e.method,onChange:a=>o({method:a.target.value,page:1}),children:[t.jsx("option",{value:"",children:"All healing methods"}),Ve.map(a=>t.jsx("option",{value:a,title:P[a],children:a},a))]}),t.jsx(O,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Sort",value:e.sort,onChange:a=>o({sort:a.target.value,page:1}),children:st.map(a=>t.jsx("option",{value:a,children:qe[a]},a))})]})]}),h?m.length===0?t.jsx($e,{title:$.title,description:$.description}):t.jsxs("table",{className:"w-full table-fixed text-left",children:[t.jsx("colgroup",{children:p.map(a=>t.jsx("col",{style:a.width?{width:a.width}:void 0},a.key))}),t.jsx("thead",{children:t.jsx("tr",{children:p.map(a=>t.jsx("th",{scope:"col",className:"px-3 py-2 text-[11px] font-medium text-[var(--text-muted)]",children:a.label},a.key))})}),t.jsx("tbody",{children:m.map(a=>{const g=_(a),f=g===c,j=()=>r({strategy:a.strategy,selector:a.selector});return t.jsx("tr",{tabIndex:0,"data-selector-row":"","data-key":g,"aria-current":f?"true":void 0,onClick:j,onKeyDown:M=>{(M.key==="Enter"||M.key===" ")&&(M.preventDefault(),j())},className:`cursor-pointer border-t border-[var(--border)] align-top outline-none hover:bg-[rgb(var(--rgb-fg)/0.03)] focus-visible:bg-[rgb(var(--rgb-fg)/0.05)] ${f?"bg-[rgb(var(--rgb-fg)/0.06)]":""}`,children:p.map(M=>t.jsx("td",{className:"px-3 py-2.5 text-xs",children:M.cell(a)},M.key))},g)})})]}):t.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:i&&!s?"Couldn't load selectors. Try again in a moment.":"Loading selectors…"}),y>0&&t.jsxs("div",{className:"flex items-center justify-between border-t border-[var(--border)] px-3 py-2 text-xs text-[var(--text-muted)]",children:[t.jsxs("span",{className:"tabular-nums",children:[A,"–",C," of ",y.toLocaleString()]}),t.jsxs("div",{className:"flex gap-2",children:[t.jsx(N,{variant:"secondary",size:"sm",disabled:k<=1,onClick:()=>o({page:k-1}),children:"Previous"}),t.jsx(N,{variant:"secondary",size:"sm",disabled:k>=T,onClick:()=>o({page:k+1}),children:"Next"})]})]})]})},lt={javascript:{"accessibility id":e=>`await driver.findElement('accessibility id', '${e}')`,xpath:e=>`await driver.findElement('xpath', '${e}')`,id:e=>`await driver.findElement('id', '${e}')`,name:e=>`await driver.findElement('name', '${e}')`,"class name":e=>`await driver.findElement('class name', '${e}')`,"-android uiautomator":e=>`await driver.findElement('-android uiautomator', '${e}')`,"-ios predicate string":e=>`await driver.findElement('-ios predicate string', '${e}')`,"-ios class chain":e=>`await driver.findElement('-ios class chain', '${e}')`},java:{"accessibility id":e=>`driver.findElement(AppiumBy.accessibilityId("${e}"))`,xpath:e=>`driver.findElement(AppiumBy.xpath("${e}"))`,id:e=>`driver.findElement(AppiumBy.id("${e}"))`,name:e=>`driver.findElement(AppiumBy.name("${e}"))`,"class name":e=>`driver.findElement(AppiumBy.className("${e}"))`,"-android uiautomator":e=>`driver.findElement(AppiumBy.androidUIAutomator("${e}"))`,"-ios predicate string":e=>`driver.findElement(AppiumBy.iOSNsPredicateString("${e}"))`,"-ios class chain":e=>`driver.findElement(AppiumBy.iOSClassChain("${e}"))`},python:{"accessibility id":e=>`driver.find_element(AppiumBy.ACCESSIBILITY_ID, '${e}')`,xpath:e=>`driver.find_element(AppiumBy.XPATH, '${e}')`,id:e=>`driver.find_element(AppiumBy.ID, '${e}')`,name:e=>`driver.find_element(AppiumBy.NAME, '${e}')`,"class name":e=>`driver.find_element(AppiumBy.CLASS_NAME, '${e}')`,"-android uiautomator":e=>`driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, '${e}')`,"-ios predicate string":e=>`driver.find_element(AppiumBy.IOS_PREDICATE, '${e}')`,"-ios class chain":e=>`driver.find_element(AppiumBy.IOS_CLASS_CHAIN, '${e}')`},csharp:{"accessibility id":e=>`driver.FindElement(MobileBy.AccessibilityId("${e}"))`,xpath:e=>`driver.FindElement(By.XPath("${e}"))`,id:e=>`driver.FindElement(By.Id("${e}"))`,name:e=>`driver.FindElement(By.Name("${e}"))`,"class name":e=>`driver.FindElement(By.ClassName("${e}"))`},ruby:{"accessibility id":e=>`driver.find_element(:accessibility_id, '${e}')`,xpath:e=>`driver.find_element(:xpath, '${e}')`,id:e=>`driver.find_element(:id, '${e}')`,name:e=>`driver.find_element(:name, '${e}')`,"class name":e=>`driver.find_element(:class_name, '${e}')`}};function it(e,n){const s=e==="java"||e==="csharp",l=n.replace(/\\/g,"\\\\");return s?l.replace(/"/g,'\\"'):l.replace(/'/g,"\\'")}function ue(e,n,s){var c;if(n==="xenon:visual")return"/* Visual AI (coordinates) — no portable Appium snippet. Use snapshot view to find a stable native locator. */";const l=(c=lt[e])==null?void 0:c[n];return l?l(it(e,s)):`${(n??"").toString().toUpperCase()}: ${s}`}const W=[{value:"javascript",short:"JS",label:"JavaScript (WebdriverIO)"},{value:"java",short:"Java",label:"Java (Appium-Java)"},{value:"python",short:"Py",label:"Python (Appium-Python)"},{value:"csharp",short:"C#",label:"C# (.NET)"},{value:"ruby",short:"Rb",label:"Ruby"}],me="xenon.copyLang";function ot(){try{const e=localStorage.getItem(me);return e&&W.find(n=>n.value===e)?e:null}catch{return null}}function ct(e){try{localStorage.setItem(me,e)}catch{}}function xe(e){var n;return((n=W.find(s=>s.value===e))==null?void 0:n.short)??e}function dt({open:e,initialLang:n,strategy:s,value:l,onCopy:c,onClose:o}){const[r,i]=d.useState(n??"javascript"),[u,b]=d.useState(!0),p=ue(r,s,l),h=async()=>{try{await navigator.clipboard.writeText(p)}catch{}u&&ct(r),c(r,p),o()};return t.jsxs(R,{open:e,onClose:o,title:"Choose your default copy language",width:520,footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:o,children:"Cancel"}),t.jsxs(N,{onClick:h,children:["Copy as ",xe(r)]})]}),children:[t.jsx("p",{className:"mb-3 text-xs text-[var(--text-muted)]",children:"Snippets will be copied in this language until you change it."}),t.jsx("ul",{className:"mb-3 space-y-1",children:W.map(m=>t.jsx("li",{children:t.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text)]",children:[t.jsx("input",{type:"radio",name:"copy-lang",value:m.value,checked:r===m.value,onChange:()=>i(m.value)}),m.label]})},m.value))}),t.jsx("div",{className:"mb-1 text-[11px] font-semibold text-[var(--text-dim)]",children:"Preview"}),t.jsx("pre",{className:"mb-3 overflow-x-auto rounded-md border border-[var(--border)] bg-[var(--surface-sunken)] p-3 font-mono text-[11px] text-[var(--text)]",children:t.jsx("code",{children:p})}),t.jsxs("label",{className:"flex items-center gap-2 text-xs text-[var(--text-muted)]",children:[t.jsx("input",{type:"checkbox",checked:u,onChange:m=>b(m.target.checked)}),"Remember my choice"]})]})}function ut({strategy:e,value:n,onCopied:s}){const[l,c]=d.useState(!1),[o,r]=d.useState(!1),i=ot(),u=e==="xenon:visual",b=async()=>{if(!i){c(!0);return}try{await navigator.clipboard.writeText(ue(i,e,n))}catch{}r(!0),s(i),setTimeout(()=>r(!1),1500)},p=i?`Copy as ${xe(i)}`:"Copy as code";return t.jsxs("span",{className:"inline-flex shrink-0",children:[t.jsxs(N,{type:"button",variant:"secondary",size:"sm",className:"rounded-r-none",onClick:h=>{h.stopPropagation(),b()},disabled:u&&!n,"aria-label":p,title:u?"Found by its place on screen: there is no selector to copy":p,children:[o?t.jsx(Ie,{size:12}):t.jsx(oe,{size:12}),t.jsx("span",{children:o?"Copied":i?p:"Copy as…"})]}),t.jsx(N,{type:"button",variant:"secondary",size:"sm",className:"rounded-l-none border-l-0 px-1.5",onClick:h=>{h.stopPropagation(),c(!0)},title:"Choose copy language","aria-label":"Choose copy language",children:t.jsx(ge,{size:12})}),t.jsx(dt,{open:l,initialLang:i??void 0,strategy:e,value:n,onCopy:h=>{r(!0),s(h),setTimeout(()=>r(!1),1500)},onClose:()=>c(!1)})]})}const se=500,mt=({open:e,busy:n,onClose:s,onConfirm:l})=>t.jsx(R,{open:e,onClose:s,title:"Mark this selector fixed?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Cancel"}),t.jsx(N,{onClick:l,disabled:n,children:"Mark fixed"})]}),children:t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"Xenon watches the next 3 clean builds. If this selector heals again, it goes back to To fix."})}),xt=({open:e,busy:n,onClose:s,onConfirm:l})=>t.jsx(R,{open:e,onClose:s,title:"Cancel verification?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Keep verifying"}),t.jsx(N,{onClick:l,disabled:n,children:"Cancel verification"})]}),children:t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"The selector goes back to To fix, and its clean builds start again from zero."})}),ht=({open:e,busy:n,onClose:s,onConfirm:l})=>{const[c,o]=d.useState("");return d.useEffect(()=>{e&&o("")},[e]),t.jsxs(R,{open:e,onClose:s,title:"Mute this selector?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Cancel"}),t.jsx(N,{onClick:()=>l(c.trim()),disabled:n,children:"Mute"})]}),children:[t.jsx("p",{className:"mb-3 text-sm text-[var(--text-muted)]",children:"A muted selector is left out of this list, the CI gate and the digest, for everyone, until someone unmutes it."}),t.jsx("label",{htmlFor:"mute-reason",className:"block text-xs font-medium text-[var(--text)]",children:"Reason (optional)"}),t.jsx("textarea",{id:"mute-reason",value:c,maxLength:se,rows:3,placeholder:"Screen being redesigned",onChange:r=>o(r.target.value),className:"mt-1 w-full rounded-md border border-[var(--border-strong)] bg-[var(--surface)] px-2 py-1.5 text-sm text-[var(--text)]"}),t.jsxs("div",{className:"mt-1 text-right text-[11px] tabular-nums text-[var(--text-dim)]",children:[c.length,"/",se]})]})},pt={mark_fixed:"Marked fixed. Xenon is watching the next 3 clean builds.",mute:"Muted.",unmute:"Unmuted.",cancel_verification:"Verification cancelled."},ft={pending:"border-[var(--color-info)] text-[var(--color-info)]",resolved:"border-[var(--color-success)] text-[var(--color-success)]",muted:"border-[var(--border-strong)] text-[var(--text-muted)]"},vt=({state:e})=>t.jsx("span",{className:`rounded-full border px-2 py-0.5 text-[11px] font-medium ${ft[(e==null?void 0:e.status)??""]??"border-[var(--color-danger)] text-[var(--color-danger)]"}`,children:Je(e)}),U=({label:e,onClick:n,children:s})=>t.jsx("button",{type:"button","aria-label":e,title:e,onClick:n,className:"rounded p-1.5 text-[var(--text-muted)] hover:bg-[rgb(var(--rgb-fg)/0.06)] hover:text-[var(--text)]",children:s}),L=({title:e,children:n})=>t.jsxs("section",{"aria-label":e,children:[t.jsx("h3",{className:"mb-2 text-xs font-semibold text-[var(--text)]",children:e}),n]}),X=({title:e,rows:n})=>n.length===0?null:t.jsxs("div",{className:"mb-3",children:[t.jsx("div",{className:"mb-1 text-[11px] text-[var(--text-dim)]",children:e}),n.map(s=>t.jsxs("div",{className:"flex justify-between gap-3 py-0.5 text-xs",children:[t.jsx("span",{className:"min-w-0 truncate text-[var(--text)]",title:s.label,children:s.label}),t.jsx("span",{className:"shrink-0 tabular-nums text-[var(--text-muted)]",children:s.count.toLocaleString()})]},s.key))]}),gt=({activity:e})=>t.jsx(L,{title:"Activity",children:e.length===0?t.jsx("p",{className:"text-xs text-[var(--text-muted)]",children:"No changes recorded yet."}):t.jsx("ul",{children:e.map((n,s)=>t.jsxs("li",{className:"flex justify-between gap-3 py-1 text-[11px]",children:[t.jsxs("span",{className:"min-w-0",children:[t.jsx("span",{className:"text-[var(--text)]",children:Ye(n)}),n.reason&&t.jsxs("span",{className:"text-[var(--text-muted)]",children:[": “",n.reason,"”"]})]}),t.jsx("span",{className:"shrink-0 text-[var(--text-dim)]",children:V(n.at)})]},`${n.at}-${s}`))})}),bt=({target:e,days:n,tz:s,refreshKey:l,onClose:c,onChanged:o})=>{var $;const{toast:r}=le(),[i,u]=d.useState(null),[b,p]=d.useState("loading"),[h,m]=d.useState(null),[y,k]=d.useState(!1);d.useEffect(()=>{u(null),p("loading")},[e.strategy,e.selector]),d.useEffect(()=>{let a=!0;return I.getSelectorPanel(e.strategy,e.selector,n,s).then(({status:g,body:f})=>{a&&(g===404?(u(null),p("missing")):g===200&&f?(u(f),p("ready")):p("failed"))}).catch(()=>{a&&p("failed")}),()=>{a=!1}},[e.strategy,e.selector,n,s,l]);const w=async(a,g)=>{k(!0);try{await I.postSelectorStateAction({original_strategy:e.strategy,original_selector:e.selector,action:a,...g?{reason:g}:{}}),r(pt[a],"success")}catch(f){const j=f.status;r(j===409?"Someone changed this selector just now. It has been refreshed.":j===404?"This selector isn't available any more.":"That didn't work. Try again.","error")}finally{k(!1),m(null),o()}},T=async(a,g)=>{try{await navigator.clipboard.writeText(a),r(g,"success")}catch{r("Couldn't copy: your browser blocked it.","error")}},A=(($=i==null?void 0:i.state)==null?void 0:$.status)??"active",C=d.useMemo(()=>{var f;const a=(i==null?void 0:i.daily)??[],g=((f=a[0])==null?void 0:f.t)??0;return{start:g,times:a.map(j=>j.t-g),values:a.map(j=>j.heals)}},[i]);return t.jsxs("aside",{"aria-label":"Selector details",className:"sticky top-4 flex max-h-[calc(100vh-7rem)] w-[480px] shrink-0 flex-col overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--surface)]",children:[t.jsxs("header",{className:"border-b border-[var(--border)] p-4",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(D,{children:K(e.strategy)}),i&&t.jsx(vt,{state:i.state}),t.jsxs("span",{className:"ml-auto flex items-center gap-0.5",children:[t.jsx(U,{label:"Copy selector",onClick:()=>void T(e.selector,"Selector copied"),children:t.jsx(oe,{size:14})}),t.jsx(U,{label:"Copy link to this selector",onClick:()=>void T(window.location.href,"Link copied"),children:t.jsx(Be,{size:14})}),t.jsx(U,{label:"Close",onClick:c,children:t.jsx(re,{size:14})})]})]}),t.jsx("code",{className:"mt-2 block break-all font-mono text-xs leading-relaxed text-[var(--text)]",children:e.selector}),(i==null?void 0:i.canAct)&&t.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[A==="active"&&e.strategy!==""&&t.jsx(N,{size:"sm",onClick:()=>m("mark_fixed"),children:"Mark fixed"}),A==="pending"&&t.jsx(N,{size:"sm",variant:"secondary",onClick:()=>m("cancel_verification"),children:"Cancel verification"}),A!=="muted"&&t.jsx(N,{size:"sm",variant:"secondary",onClick:()=>m("mute"),children:"Mute…"}),A==="muted"&&t.jsx(N,{size:"sm",variant:"secondary",disabled:y,onClick:()=>void w("unmute"),children:"Unmute"})]})]}),t.jsxs("div",{className:"min-h-0 flex-1 space-y-5 overflow-y-auto p-4",children:[b==="loading"&&t.jsx("p",{className:"text-xs text-[var(--text-dim)]",children:"Loading…"}),b==="missing"&&t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"This selector isn't available. It may belong to another team, or Xenon has no heals on record for it."}),b==="failed"&&t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"Couldn't load this selector. Try again in a moment."}),i&&i.heals===0&&t.jsxs("p",{className:"text-sm text-[var(--text-muted)]",children:["No heals in the last ",n," days."]}),i&&i.heals>0&&t.jsxs(t.Fragment,{children:[t.jsx(L,{title:"Suggested fix",children:i.suggestions.length===0?t.jsx("p",{className:"text-xs text-[var(--text-muted)]",children:"Xenon found the element without a selector it can suggest."}):t.jsx("ul",{className:"space-y-2",children:i.suggestions.map((a,g)=>t.jsx("li",{className:`rounded-md border p-2.5 ${g===0?"border-[var(--color-success)]":"border-[var(--border)]"}`,children:t.jsxs("div",{className:"flex items-start gap-2",children:[t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-1.5 text-[11px] text-[var(--text-muted)]",children:[t.jsx(D,{children:K(a.strategy)}),t.jsx("span",{children:de(a.share)}),a.methods.length>0&&t.jsxs("span",{title:a.methods.map(f=>P[f]??f).join(". "),children:["· ",a.methods.join(", ")]}),a.averageConfidence!==null&&t.jsxs("span",{children:["· ",Math.round(a.averageConfidence*100),"% confidence"]})]}),t.jsx("code",{className:"mt-1 block break-all font-mono text-[11px] text-[var(--text)]",children:a.selector})]}),t.jsx(ut,{strategy:a.strategy??e.strategy,value:a.selector,onCopied:f=>r(`Copied as ${f}`,"success")})]})},`${a.strategy??""}\0${a.selector}`))})}),t.jsxs(L,{title:`In the last ${n} days`,children:[t.jsx("div",{className:"grid grid-cols-3 gap-2",children:[{label:i.heals===1?"heal":"heals",value:i.heals.toLocaleString()},{label:i.sessions===1?"session":"sessions",value:i.sessions.toLocaleString()},{label:"spent healing",value:J(i.timeSpentMs)}].map(a=>t.jsxs("div",{className:"rounded-md bg-[rgb(var(--rgb-fg)/0.04)] px-2.5 py-2",children:[t.jsx("div",{className:"text-sm font-semibold tabular-nums text-[var(--text)]",children:a.value}),t.jsx("div",{className:"text-[11px] text-[var(--text-muted)]",children:a.label})]},a.label))}),C.times.length>1&&t.jsx("div",{className:"mt-3",children:t.jsx(ie,{times:C.times,series:[{key:"heals",label:"Heals",color:"var(--color-info)",values:C.values}],formatValue:a=>String(Math.round(a)),formatTime:a=>ce(C.start+a),ariaLabel:"Heals per day for this selector",height:56})})]}),t.jsxs(L,{title:"Where it happens",children:[t.jsx(X,{title:"Platforms",rows:i.platforms.map(a=>({key:a.name,label:Le(a.name),count:a.count}))}),t.jsx(X,{title:"Builds",rows:i.builds.map(a=>({key:a.id??"",label:a.name,count:a.count}))}),t.jsx(X,{title:"Devices",rows:i.devices.map(a=>({key:a.udid,label:a.name,count:a.count}))})]}),t.jsx(L,{title:"Recent heals",children:t.jsx("ul",{className:"divide-y divide-[var(--border)]",children:i.recent.map(a=>t.jsxs("li",{className:"py-2 text-[11px]",children:[t.jsxs("div",{className:"flex items-center gap-1.5 text-[var(--text-muted)]",children:[t.jsx("span",{children:q(a.at)}),a.device&&t.jsxs("span",{className:"min-w-0 truncate",children:["· ",a.device]}),a.method&&t.jsxs("span",{title:P[a.method],children:["· ",a.method,a.confidence!==null?` ${Math.round(a.confidence*100)}%`:""]}),t.jsx(be,{className:"ml-auto shrink-0 text-[var(--color-accent)] hover:underline",to:`/builds/${encodeURIComponent(a.buildId??"none")}/sessions/${encodeURIComponent(a.sessionId)}`,children:"Session"})]}),a.healedSelector&&t.jsx("code",{className:"mt-0.5 block truncate font-mono text-[var(--text)]",title:a.healedSelector,children:a.healedSelector})]},a.id))})})]}),i&&t.jsx(gt,{activity:i.activity})]}),t.jsx(mt,{open:h==="mark_fixed",busy:y,onClose:()=>m(null),onConfirm:()=>void w("mark_fixed")}),t.jsx(xt,{open:h==="cancel_verification",busy:y,onClose:()=>m(null),onConfirm:()=>void w("cancel_verification")}),t.jsx(ht,{open:h==="mute",busy:y,onClose:()=>m(null),onConfirm:a=>void w("mute",a||void 0)})]})},yt=1e3,jt=["healing_event","selector_fixed","selector_resolved","selector_regressed","selector_cancelled","selector_muted","selector_unmuted","selector_progress"],Nt=e=>!!e&&(["INPUT","TEXTAREA","SELECT"].includes(e.tagName)||e.isContentEditable),Ft=()=>{const[e,n]=ye(),s=d.useMemo(()=>Y(e),[e]),l=d.useMemo(()=>-new Date().getTimezoneOffset(),[]),{on:c}=ne(),{toast:o}=le(),{me:r}=je(),i=!!r&&(r.role==="ADMIN"||r.role==="SUPER_ADMIN"||!!r.authDisabled),[u,b]=d.useState(null),[p,h]=d.useState(null),[m,y]=d.useState(!1),[k,w]=d.useState(!1),[T,A]=d.useState(!0),[C,$]=d.useState(0),[a,g]=d.useState(!1),f=d.useCallback((x,v=!1)=>n(Ee({...Y(e),...x}),{replace:v}),[e,n]);d.useEffect(()=>{let x=!0;return I.getHealingSummary(s.days,l).then(v=>{x&&(b(v??null),w(!1))}).catch(()=>{x&&w(!0)}),()=>{x=!1}},[s.days,l,C]),d.useEffect(()=>{let x=!0;return A(!0),I.getHealingSelectors({tab:s.tab,days:s.days,q:s.q,platform:s.platform,method:s.method,sort:s.sort,page:s.page}).then(v=>{x&&(h(v??null),y(!1))}).catch(()=>{x&&y(!0)}).finally(()=>{x&&A(!1)}),()=>{x=!1}},[s.tab,s.days,s.q,s.platform,s.method,s.sort,s.page,C]);const j=d.useRef(null);d.useEffect(()=>{const x=()=>{j.current||(j.current=setTimeout(()=>{j.current=null,$(S=>S+1)},yt))},v=jt.map(S=>c(S,x));return()=>{v.forEach(S=>S&&S()),j.current&&clearTimeout(j.current),j.current=null}},[c]);const M=d.useCallback(x=>f({open:x}),[f]),F=d.useCallback(()=>{const x=s.open?_(s.open):null;f({open:null}),setTimeout(()=>{var S;(S=Array.from(document.querySelectorAll("[data-selector-row]")).find(B=>B.dataset.key===x))==null||S.focus()},0)},[s.open,f]),z=d.useCallback(x=>{const v=(p==null?void 0:p.items)??[];if(v.length===0)return;const S=s.open?v.findIndex(pe=>_(pe)===_(s.open)):-1,B=v[S<0?0:Math.min(v.length-1,Math.max(0,S+x))];f({open:{strategy:B.strategy,selector:B.selector}},!0)},[p,s.open,f]);d.useEffect(()=>{if(!s.open)return;const x=v=>{v.defaultPrevented||Nt(document.activeElement)||document.querySelector('[role="dialog"]')||(v.key==="Escape"?(v.preventDefault(),F()):v.key==="ArrowDown"?(v.preventDefault(),z(1)):v.key==="ArrowUp"&&(v.preventDefault(),z(-1)))};return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[s.open,F,z]);const he=async()=>{g(!0);try{const x=await I.sendHealingDigest({windowDays:s.days,limit:5,minHealCount:2}),v=(x==null?void 0:x.sent)??0;v===0?o("No webhook gets the digest yet. Add one in Notifications.","error"):o(`Digest sent to ${v} webhook${v===1?"":"s"}.`,"success")}catch{o("Couldn't send the digest. Try again.","error")}finally{g(!1)}};return t.jsxs("div",{children:[t.jsx(Se,{icon:Ne,eyebrow:"Test quality",title:"Selector health",subtitle:"Selectors your tests could only find with self-healing. Fix the ones that heal most.",action:t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(ke,{size:"sm",label:"Period",value:String(s.days),onChange:x=>f({days:Number(x),page:1}),segments:Te.map(x=>({value:String(x),label:`${x} days`}))}),i&&t.jsxs(N,{variant:"secondary",size:"sm",onClick:()=>void he(),disabled:a,children:[t.jsx(Re,{size:14})," Send digest"]})]})}),t.jsxs("div",{className:"space-y-4 px-6 pb-8 pt-4",children:[t.jsx(Oe,{onShow:x=>f(_e(x))}),t.jsx(Qe,{summary:u,days:s.days}),t.jsx(Ze,{trend:u?u.trend??[]:null,days:s.days,failed:k&&!u}),t.jsxs("div",{className:"flex items-start gap-4",children:[t.jsx("div",{className:"min-w-0 flex-1",children:t.jsx(rt,{view:s,data:p,loading:T,compact:!!s.open,selectedKey:s.open?_(s.open):null,onView:f,onOpen:M,error:m})}),s.open&&t.jsx(bt,{target:s.open,days:s.days,tz:l,refreshKey:C,onClose:F,onChanged:()=>$(x=>x+1)})]})]})]})};export{yt as LIVE_REFRESH_MS,Ft as default};
11
+ */const Pe=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],Re=ae("send",Pe),Fe=3e4,ze=5*6e4;function He({onShow:e}){const{on:n}=ne(),[s,l]=d.useState([]);if(d.useEffect(()=>{const o=n("selector_regressed",r=>{l(i=>{const u=Date.now()-ze;return[...i.filter(b=>b.receivedAt>=u),{strategy:(r==null?void 0:r.original_strategy)??"",selector:(r==null?void 0:r.original_selector)??"",receivedAt:Date.now()}]})});return()=>{o&&o()}},[n]),d.useEffect(()=>{if(s.length===0)return;const o=setTimeout(()=>l([]),Fe);return()=>clearTimeout(o)},[s]),s.length===0)return null;const c=s.length===1?s[0]:null;return t.jsxs("div",{role:"alert",className:"flex items-center gap-3 rounded-lg border border-[var(--color-warning)] bg-[var(--surface)] px-4 py-2.5 text-sm text-[var(--text)]",children:[t.jsx(fe,{size:14,className:"shrink-0 text-[var(--color-warning)]","aria-hidden":"true"}),t.jsx("span",{className:"min-w-0 flex-1 truncate",children:c?t.jsxs(t.Fragment,{children:["A selector you fixed broke again:"," ",t.jsx("code",{className:"font-mono text-xs",title:c.selector,children:c.selector})]}):`${s.length} selectors you fixed broke again in the last 5 minutes.`}),t.jsx(N,{variant:"secondary",size:"sm",onClick:()=>{e(s.map(({strategy:o,selector:r})=>({strategy:o,selector:r}))),l([])},children:"Show selectors to fix"}),t.jsx("button",{type:"button","aria-label":"Dismiss",onClick:()=>l([]),className:"rounded p-1 text-[var(--text-muted)] hover:text-[var(--text)]",children:t.jsx(re,{size:13})})]})}const Oe={"accessibility id":"Accessibility ID",xpath:"XPath",id:"ID",name:"Name","class name":"Class Name","-android uiautomator":"UiAutomator","-ios predicate string":"iOS Predicate","-ios class chain":"iOS Class Chain","xenon:visual":"Visual AI (coords)"};function Ue(e){return e?Oe[e]??e:"(unknown strategy)"}const Xe={fix:"To fix",verifying:"Being verified",fixed:"Fixed",muted:"Muted"},qe={heals:"Most heals",recent:"Most recent",time:"Most time spent healing"},Ve=["Resilio","Native","Fuzzy XML","OCR","Visual AI","LLM"],P={Resilio:"Found it from its saved fingerprint",Native:"Found it again with the original selector","Fuzzy XML":"Found the closest match in the screen's structure",OCR:"Found it by reading the text on screen","Visual AI":"Found it in a screenshot with AI",LLM:"Asked a language model to find it"},Ke=[{value:"android",label:"Android"},{value:"ios",label:"iOS"},{value:"tvos",label:"tvOS"}];function J(e){if(!(e>0))return"0 s";const n=e/1e3;if(n<1)return"<1 s";if(Math.round(n)<60)return`${Math.round(n)} s`;const s=n/60;if(Math.round(s)<60)return`${Math.round(s)} min`;const l=s/60;return`${l<10?l.toFixed(1):Math.round(l)} h`}function q(e,n=Date.now()){if(!e)return"—";const s=Date.parse(e);if(!Number.isFinite(s))return"—";const l=Math.floor(Math.max(0,n-s)/6e4);if(l<1)return"just now";if(l<60)return`${l} min ago`;const c=Math.floor(l/60);if(c<24)return`${c} h ago`;const o=Math.floor(c/24);return o===1?"yesterday":`${o} days ago`}function ce(e){return new Date(e).toLocaleDateString(void 0,{weekday:"short",day:"numeric",month:"short"})}function V(e){if(!e)return"—";const n=Date.parse(e);return Number.isFinite(n)?new Date(n).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}):"—"}function Ge(e,n,s,l){const c=`the ${s} days before`;if(e===n)return{text:`Same as ${c}`,tone:"neutral"};if(n===0)return{text:`None ${c}`,tone:"bad"};const o=e>n,r=o?"bad":"good";if(l==="count")return{text:`${Math.abs(e-n)} ${o?"more":"fewer"} than ${c}`,tone:r};if(l==="duration")return{text:`${J(Math.abs(e-n))} ${o?"more":"less"} than ${c}`,tone:r};const i=Math.round(Math.abs(e-n)/n*100);return i===0?{text:`About the same as ${c}`,tone:"neutral"}:{text:`${i}% ${o?"more":"fewer"} than ${c}`,tone:r}}function de(e){return`${Math.round(e*100)}% of heals`}function K(e){return e?Ue(e):"Unknown type"}function Je(e){switch(e==null?void 0:e.status){case"pending":return`Being verified, ${e.cleanBuilds} of 3 clean builds`;case"resolved":return"Fixed";case"muted":return"Muted";default:return"To fix"}}function G(e){return e!=null&&e.name?` by ${e.name}`:""}const We={marked_fixed:"Marked fixed",verification_cancelled:"Verification cancelled",verified:"Verified after 3 clean builds",broke_again:"Broke again",muted:"Muted",unmuted:"Unmuted"};function Ye(e){return`${We[e.action]??"Changed"}${G(e.by)}`}const O=e=>e.toLocaleString(),Qe=({summary:e,days:n})=>{const s=e==null?void 0:e.current,l=e==null?void 0:e.prior,c=[{label:"Selectors that needed healing",value:s==null?void 0:s.distinctSelectors,before:l==null?void 0:l.distinctSelectors,kind:"count",show:O},{label:"Heals",value:s==null?void 0:s.totalHeals,before:l==null?void 0:l.totalHeals,kind:"percent",show:O},{label:"Sessions affected",value:s==null?void 0:s.sessionsTouched,before:l==null?void 0:l.sessionsTouched,kind:"percent",show:O},{label:"Time spent healing",value:s==null?void 0:s.timeSpentMs,before:l==null?void 0:l.timeSpentMs,kind:"duration",show:J}];return t.jsx("div",{className:"grid grid-cols-4 gap-3",children:c.map(o=>{const r=o.value!==void 0&&o.before!==void 0?Ge(o.value,o.before,n,o.kind):null;return t.jsx(we,{label:o.label,value:o.value!==void 0?o.show(o.value):"—",note:r==null?void 0:r.text,noteTone:(r==null?void 0:r.tone)??"neutral"},o.label)})})},Q="var(--color-info)",Z="var(--color-warning)",ee=({color:e,label:n,total:s})=>t.jsxs("span",{className:"flex items-center gap-1.5",children:[t.jsx("span",{className:"inline-block h-0.5 w-3",style:{background:e}}),t.jsx("span",{children:n}),t.jsx("span",{className:"tabular-nums text-[var(--text)]",children:s.toLocaleString()})]}),Ze=({trend:e,days:n,failed:s})=>{var h;const l=d.useMemo(()=>e??[],[e]),c=((h=l[0])==null?void 0:h.t)??0,o=l.reduce((m,y)=>m+y.heals,0),r=l.reduce((m,y)=>m+y.aiHeals,0),i=d.useMemo(()=>l.map(m=>m.t-c),[l,c]),u=d.useMemo(()=>[{key:"heals",label:"All heals",color:Q,values:l.map(m=>m.heals)},{key:"ai",label:"Heals that used AI",color:Z,values:l.map(m=>m.aiHeals)}],[l]),b=l.reduce((m,y)=>Math.max(m,y.heals),0);let p;return e===null&&s?p=t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"Couldn't load heals per day. Try again in a moment."}):e===null?p=t.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"Loading…"}):o===0?p=t.jsxs("div",{className:"text-xs text-[var(--text-dim)]",children:["No heals in the last ",n," days."]}):p=t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"mb-2 flex flex-wrap gap-x-4 gap-y-1 text-[11px] text-[var(--text-muted)]",children:[t.jsx(ee,{color:Q,label:"All heals",total:o}),t.jsx(ee,{color:Z,label:"Heals that used AI",total:r})]}),t.jsx(ie,{times:i,series:u,yMax:Ce(b),formatValue:m=>String(Math.round(m)),formatTime:m=>ce(c+m),ariaLabel:"Heals per day",height:120})]}),t.jsx(Ae,{header:"Heals per day",children:p})},D=({title:e,tone:n="neutral",children:s})=>t.jsx("span",{title:e,className:`inline-block max-w-full truncate rounded px-1.5 py-px text-[10px] font-medium ${n==="warning"?"border border-[var(--color-warning)] text-[var(--color-warning)]":"bg-[rgb(var(--rgb-fg)/0.06)] text-[var(--text-muted)]"}`,children:s}),te=({strategy:e,text:n,extra:s})=>t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"mb-0.5 flex min-w-0 items-center gap-1.5",children:[t.jsx(D,{children:K(e)}),s]}),t.jsx("code",{className:"line-clamp-2 break-all font-mono text-[11px] leading-snug text-[var(--text)]",title:n,children:n})]}),et=300,tt=["fix","verifying","fixed","muted"],st=["heals","recent","time"],E=e=>t.jsx("span",{className:"text-xs text-[var(--text-muted)]",children:e});function at(e,n,s){const l={key:"selector",label:"Selector",cell:r=>t.jsx(te,{strategy:r.strategy,text:r.selector,extra:e==="fix"&&r.state&&r.state.brokeAgain>0?t.jsx(D,{tone:"warning",children:"Broke again"}):null})},c=r=>({key:"heals",label:r,width:"96px",cell:i=>t.jsxs("div",{children:[t.jsx("div",{className:"font-semibold tabular-nums text-[var(--text)]",children:i.heals.toLocaleString()}),t.jsxs("div",{className:"text-[11px] text-[var(--text-muted)]",children:[i.sessions," ",i.sessions===1?"session":"sessions"]})]})}),o={key:"last",label:"Last healed",width:"104px",cell:r=>E(q(r.lastHealedAt))};switch(e){case"fix":return n?[l,c("Heals"),o]:[l,c("Heals"),o,{key:"method",label:"Healed by",width:"112px",cell:r=>r.topMethod?t.jsx(D,{title:P[r.topMethod],children:r.topMethod}):E("—")},{key:"fix",label:"Suggested fix",width:"34%",cell:r=>r.suggestion?t.jsx(te,{strategy:r.suggestion.strategy,text:r.suggestion.selector,extra:t.jsx("span",{className:"text-[10px] text-[var(--text-muted)]",children:de(r.suggestion.share)})}):E("None yet")}];case"verifying":{const r={key:"progress",label:"Progress",width:"150px",cell:i=>{var u;return t.jsxs("span",{className:"text-xs text-[var(--text)]",children:[((u=i.state)==null?void 0:u.cleanBuilds)??0," of 3 clean builds"]})}};return n?[l,r]:[l,r,{key:"marked",label:"Marked fixed",width:"180px",cell:i=>{var u,b;return E(`${q(((u=i.state)==null?void 0:u.fixedAt)??null)}${G(((b=i.state)==null?void 0:b.fixedBy)??null)}`)}},c(`Heals, ${s} days`)]}case"fixed":{const r={key:"verified",label:"Verified",width:"140px",cell:i=>{var u;return E(V(((u=i.state)==null?void 0:u.resolvedAt)??null))}};return n?[l,r]:[l,r,c(`Heals, ${s} days`)]}case"muted":{const r={key:"muted",label:"Muted",width:"180px",cell:i=>{var u,b;return E(`${V(((u=i.state)==null?void 0:u.mutedAt)??null)}${G(((b=i.state)==null?void 0:b.mutedBy)??null)}`)}};return n?[l,r]:[l,r,{key:"reason",label:"Reason",width:"26%",cell:i=>{var u;return(u=i.state)!=null&&u.muteReason?t.jsx("span",{className:"line-clamp-2 text-xs text-[var(--text)]",children:i.state.muteReason}):E("No reason given")}},c(`Heals, ${s} days`)]}}}function nt(e,n,s){if(n)return{title:`No selectors match “${n}”`,description:"Try fewer or different words."};switch(e){case"fix":return{title:`Nothing to fix in the last ${s} days`,description:"Every selector your tests used was found without healing."};case"verifying":return{title:"Nothing being verified",description:"When you mark a selector fixed, Xenon watches its next 3 clean builds here."};case"fixed":return{title:`Nothing fixed in the last ${s} days`,description:"Selectors that pass 3 clean builds after being marked fixed show here."};case"muted":return{title:"Nothing muted",description:"A muted selector is left out of this list, the CI gate and the digest."}}}const rt=({view:e,data:n,loading:s,compact:l,selectedKey:c,onView:o,onOpen:r,error:i})=>{const[u,b]=d.useState(e.q);d.useEffect(()=>b(e.q),[e.q]),d.useEffect(()=>{if(u===e.q)return;const a=setTimeout(()=>o({q:u,page:1}),et);return()=>clearTimeout(a)},[u,e.q,o]);const p=at(e.tab,l,e.days),h=n&&n.tab===e.tab?n:null,m=(h==null?void 0:h.items)??[],y=(h==null?void 0:h.total)??0,k=(h==null?void 0:h.page)??e.page,w=(h==null?void 0:h.pageSize)??50,T=Math.max(1,Math.ceil(y/w)),A=y===0?0:(k-1)*w+1,C=Math.min(y,k*w),$=nt(e.tab,e.q,e.days);return t.jsxs("section",{"aria-label":"Selectors",className:"rounded-lg border border-[var(--border)] bg-[var(--surface)]",children:[t.jsx("div",{role:"tablist","aria-label":"Selector status",className:"flex gap-1 border-b border-[var(--border)] px-3",children:tt.map(a=>{var j;const g=e.tab===a,f=(j=n==null?void 0:n.counts)==null?void 0:j[a];return t.jsxs("button",{type:"button",role:"tab","aria-selected":g,onClick:()=>{g||o({tab:a,page:1})},className:`-mb-px flex items-center gap-2 border-b-2 px-3 py-2.5 text-sm ${g?"border-[var(--color-accent)] font-medium text-[var(--text)]":"border-transparent text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:[Xe[a],t.jsx("span",{className:"rounded-full bg-[rgb(var(--rgb-fg)/0.08)] px-1.5 text-[11px] tabular-nums",children:typeof f=="number"?f.toLocaleString():"–"})]},a)})}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2 border-b border-[var(--border)] px-3 py-2.5",children:[t.jsxs("div",{className:"relative min-w-[220px] flex-1",children:[t.jsx(ve,{size:14,"aria-hidden":"true",className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--text-dim)]"}),t.jsx(Me,{type:"search","aria-label":"Search",value:u,onChange:a=>b(a.target.value),placeholder:e.tab==="fix"?"Search selectors and fixes":"Search selectors",className:"h-8 w-full pl-8 pr-2 text-xs"})]}),e.tab==="fix"&&t.jsxs(t.Fragment,{children:[t.jsxs(H,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Platform",value:e.platform,onChange:a=>o({platform:a.target.value,page:1}),children:[t.jsx("option",{value:"",children:"All platforms"}),Ke.map(a=>t.jsx("option",{value:a.value,children:a.label},a.value))]}),t.jsxs(H,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Healing method",value:e.method,onChange:a=>o({method:a.target.value,page:1}),children:[t.jsx("option",{value:"",children:"All healing methods"}),Ve.map(a=>t.jsx("option",{value:a,title:P[a],children:a},a))]}),t.jsx(H,{selectSize:"sm",className:"!w-auto shrink-0","aria-label":"Sort",value:e.sort,onChange:a=>o({sort:a.target.value,page:1}),children:st.map(a=>t.jsx("option",{value:a,children:qe[a]},a))})]})]}),h?m.length===0?t.jsx($e,{title:$.title,description:$.description}):t.jsxs("table",{className:"w-full table-fixed text-left",children:[t.jsx("colgroup",{children:p.map(a=>t.jsx("col",{style:a.width?{width:a.width}:void 0},a.key))}),t.jsx("thead",{children:t.jsx("tr",{children:p.map(a=>t.jsx("th",{scope:"col",className:"px-3 py-2 text-[11px] font-medium text-[var(--text-muted)]",children:a.label},a.key))})}),t.jsx("tbody",{children:m.map(a=>{const g=_(a),f=g===c,j=()=>r({strategy:a.strategy,selector:a.selector});return t.jsx("tr",{tabIndex:0,"data-selector-row":"","data-key":g,"aria-current":f?"true":void 0,onClick:j,onKeyDown:M=>{(M.key==="Enter"||M.key===" ")&&(M.preventDefault(),j())},className:`cursor-pointer border-t border-[var(--border)] align-top outline-none hover:bg-[rgb(var(--rgb-fg)/0.03)] focus-visible:bg-[rgb(var(--rgb-fg)/0.05)] ${f?"bg-[rgb(var(--rgb-fg)/0.06)]":""}`,children:p.map(M=>t.jsx("td",{className:"px-3 py-2.5 text-xs",children:M.cell(a)},M.key))},g)})})]}):t.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:i&&!s?"Couldn't load selectors. Try again in a moment.":"Loading selectors…"}),y>0&&t.jsxs("div",{className:"flex items-center justify-between border-t border-[var(--border)] px-3 py-2 text-xs text-[var(--text-muted)]",children:[t.jsxs("span",{className:"tabular-nums",children:[A,"–",C," of ",y.toLocaleString()]}),t.jsxs("div",{className:"flex gap-2",children:[t.jsx(N,{variant:"secondary",size:"sm",disabled:k<=1,onClick:()=>o({page:k-1}),children:"Previous"}),t.jsx(N,{variant:"secondary",size:"sm",disabled:k>=T,onClick:()=>o({page:k+1}),children:"Next"})]})]})]})},lt={javascript:{"accessibility id":e=>`await driver.findElement('accessibility id', '${e}')`,xpath:e=>`await driver.findElement('xpath', '${e}')`,id:e=>`await driver.findElement('id', '${e}')`,name:e=>`await driver.findElement('name', '${e}')`,"class name":e=>`await driver.findElement('class name', '${e}')`,"-android uiautomator":e=>`await driver.findElement('-android uiautomator', '${e}')`,"-ios predicate string":e=>`await driver.findElement('-ios predicate string', '${e}')`,"-ios class chain":e=>`await driver.findElement('-ios class chain', '${e}')`},java:{"accessibility id":e=>`driver.findElement(AppiumBy.accessibilityId("${e}"))`,xpath:e=>`driver.findElement(AppiumBy.xpath("${e}"))`,id:e=>`driver.findElement(AppiumBy.id("${e}"))`,name:e=>`driver.findElement(AppiumBy.name("${e}"))`,"class name":e=>`driver.findElement(AppiumBy.className("${e}"))`,"-android uiautomator":e=>`driver.findElement(AppiumBy.androidUIAutomator("${e}"))`,"-ios predicate string":e=>`driver.findElement(AppiumBy.iOSNsPredicateString("${e}"))`,"-ios class chain":e=>`driver.findElement(AppiumBy.iOSClassChain("${e}"))`},python:{"accessibility id":e=>`driver.find_element(AppiumBy.ACCESSIBILITY_ID, '${e}')`,xpath:e=>`driver.find_element(AppiumBy.XPATH, '${e}')`,id:e=>`driver.find_element(AppiumBy.ID, '${e}')`,name:e=>`driver.find_element(AppiumBy.NAME, '${e}')`,"class name":e=>`driver.find_element(AppiumBy.CLASS_NAME, '${e}')`,"-android uiautomator":e=>`driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, '${e}')`,"-ios predicate string":e=>`driver.find_element(AppiumBy.IOS_PREDICATE, '${e}')`,"-ios class chain":e=>`driver.find_element(AppiumBy.IOS_CLASS_CHAIN, '${e}')`},csharp:{"accessibility id":e=>`driver.FindElement(MobileBy.AccessibilityId("${e}"))`,xpath:e=>`driver.FindElement(By.XPath("${e}"))`,id:e=>`driver.FindElement(By.Id("${e}"))`,name:e=>`driver.FindElement(By.Name("${e}"))`,"class name":e=>`driver.FindElement(By.ClassName("${e}"))`},ruby:{"accessibility id":e=>`driver.find_element(:accessibility_id, '${e}')`,xpath:e=>`driver.find_element(:xpath, '${e}')`,id:e=>`driver.find_element(:id, '${e}')`,name:e=>`driver.find_element(:name, '${e}')`,"class name":e=>`driver.find_element(:class_name, '${e}')`}};function it(e,n){const s=e==="java"||e==="csharp",l=n.replace(/\\/g,"\\\\");return s?l.replace(/"/g,'\\"'):l.replace(/'/g,"\\'")}function ue(e,n,s){var c;if(n==="xenon:visual")return"/* Visual AI (coordinates) — no portable Appium snippet. Use snapshot view to find a stable native locator. */";const l=(c=lt[e])==null?void 0:c[n];return l?l(it(e,s)):`${(n??"").toString().toUpperCase()}: ${s}`}const W=[{value:"javascript",short:"JS",label:"JavaScript (WebdriverIO)"},{value:"java",short:"Java",label:"Java (Appium-Java)"},{value:"python",short:"Py",label:"Python (Appium-Python)"},{value:"csharp",short:"C#",label:"C# (.NET)"},{value:"ruby",short:"Rb",label:"Ruby"}],me="xenon.copyLang";function ot(){try{const e=localStorage.getItem(me);return e&&W.find(n=>n.value===e)?e:null}catch{return null}}function ct(e){try{localStorage.setItem(me,e)}catch{}}function xe(e){var n;return((n=W.find(s=>s.value===e))==null?void 0:n.short)??e}function dt({open:e,initialLang:n,strategy:s,value:l,onCopy:c,onClose:o}){const[r,i]=d.useState(n??"javascript"),[u,b]=d.useState(!0),p=ue(r,s,l),h=async()=>{try{await navigator.clipboard.writeText(p)}catch{}u&&ct(r),c(r,p),o()};return t.jsxs(R,{open:e,onClose:o,title:"Choose your default copy language",width:520,footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:o,children:"Cancel"}),t.jsxs(N,{onClick:h,children:["Copy as ",xe(r)]})]}),children:[t.jsx("p",{className:"mb-3 text-xs text-[var(--text-muted)]",children:"Snippets will be copied in this language until you change it."}),t.jsx("ul",{className:"mb-3 space-y-1",children:W.map(m=>t.jsx("li",{children:t.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text)]",children:[t.jsx("input",{type:"radio",name:"copy-lang",value:m.value,checked:r===m.value,onChange:()=>i(m.value)}),m.label]})},m.value))}),t.jsx("div",{className:"mb-1 text-[11px] font-semibold text-[var(--text-dim)]",children:"Preview"}),t.jsx("pre",{className:"mb-3 overflow-x-auto rounded-md border border-[var(--border)] bg-[var(--surface-sunken)] p-3 font-mono text-[11px] text-[var(--text)]",children:t.jsx("code",{children:p})}),t.jsxs("label",{className:"flex items-center gap-2 text-xs text-[var(--text-muted)]",children:[t.jsx("input",{type:"checkbox",checked:u,onChange:m=>b(m.target.checked)}),"Remember my choice"]})]})}function ut({strategy:e,value:n,onCopied:s}){const[l,c]=d.useState(!1),[o,r]=d.useState(!1),i=ot(),u=e==="xenon:visual",b=async()=>{if(!i){c(!0);return}try{await navigator.clipboard.writeText(ue(i,e,n))}catch{}r(!0),s(i),setTimeout(()=>r(!1),1500)},p=i?`Copy as ${xe(i)}`:"Copy as code";return t.jsxs("span",{className:"inline-flex shrink-0",children:[t.jsxs(N,{type:"button",variant:"secondary",size:"sm",className:"rounded-r-none",onClick:h=>{h.stopPropagation(),b()},disabled:u&&!n,"aria-label":p,title:u?"Found by its place on screen: there is no selector to copy":p,children:[o?t.jsx(Ie,{size:12}):t.jsx(oe,{size:12}),t.jsx("span",{children:o?"Copied":i?p:"Copy as…"})]}),t.jsx(N,{type:"button",variant:"secondary",size:"sm",className:"rounded-l-none border-l-0 px-1.5",onClick:h=>{h.stopPropagation(),c(!0)},title:"Choose copy language","aria-label":"Choose copy language",children:t.jsx(ge,{size:12})}),t.jsx(dt,{open:l,initialLang:i??void 0,strategy:e,value:n,onCopy:h=>{r(!0),s(h),setTimeout(()=>r(!1),1500)},onClose:()=>c(!1)})]})}const se=500,mt=({open:e,busy:n,onClose:s,onConfirm:l})=>t.jsx(R,{open:e,onClose:s,title:"Mark this selector fixed?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Cancel"}),t.jsx(N,{onClick:l,disabled:n,children:"Mark fixed"})]}),children:t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"Xenon watches the next 3 clean builds. If this selector heals again, it goes back to To fix."})}),xt=({open:e,busy:n,onClose:s,onConfirm:l})=>t.jsx(R,{open:e,onClose:s,title:"Cancel verification?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Keep verifying"}),t.jsx(N,{onClick:l,disabled:n,children:"Cancel verification"})]}),children:t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"The selector goes back to To fix, and its clean builds start again from zero."})}),ht=({open:e,busy:n,onClose:s,onConfirm:l})=>{const[c,o]=d.useState("");return d.useEffect(()=>{e&&o("")},[e]),t.jsxs(R,{open:e,onClose:s,title:"Mute this selector?",footer:t.jsxs(t.Fragment,{children:[t.jsx(N,{variant:"secondary",onClick:s,children:"Cancel"}),t.jsx(N,{onClick:()=>l(c.trim()),disabled:n,children:"Mute"})]}),children:[t.jsx("p",{className:"mb-3 text-sm text-[var(--text-muted)]",children:"A muted selector is left out of this list, the CI gate and the digest, for everyone, until someone unmutes it."}),t.jsx("label",{htmlFor:"mute-reason",className:"block text-xs font-medium text-[var(--text)]",children:"Reason (optional)"}),t.jsx("textarea",{id:"mute-reason",value:c,maxLength:se,rows:3,placeholder:"Screen being redesigned",onChange:r=>o(r.target.value),className:"mt-1 w-full rounded-md border border-[var(--border-strong)] bg-[var(--surface)] px-2 py-1.5 text-sm text-[var(--text)]"}),t.jsxs("div",{className:"mt-1 text-right text-[11px] tabular-nums text-[var(--text-dim)]",children:[c.length,"/",se]})]})},pt={mark_fixed:"Marked fixed. Xenon is watching the next 3 clean builds.",mute:"Muted.",unmute:"Unmuted.",cancel_verification:"Verification cancelled."},ft={pending:"border-[var(--color-info)] text-[var(--color-info)]",resolved:"border-[var(--color-success)] text-[var(--color-success)]",muted:"border-[var(--border-strong)] text-[var(--text-muted)]"},vt=({state:e})=>t.jsx("span",{className:`rounded-full border px-2 py-0.5 text-[11px] font-medium ${ft[(e==null?void 0:e.status)??""]??"border-[var(--color-danger)] text-[var(--color-danger)]"}`,children:Je(e)}),U=({label:e,onClick:n,children:s})=>t.jsx("button",{type:"button","aria-label":e,title:e,onClick:n,className:"rounded p-1.5 text-[var(--text-muted)] hover:bg-[rgb(var(--rgb-fg)/0.06)] hover:text-[var(--text)]",children:s}),L=({title:e,children:n})=>t.jsxs("section",{"aria-label":e,children:[t.jsx("h3",{className:"mb-2 text-xs font-semibold text-[var(--text)]",children:e}),n]}),X=({title:e,rows:n})=>n.length===0?null:t.jsxs("div",{className:"mb-3",children:[t.jsx("div",{className:"mb-1 text-[11px] text-[var(--text-dim)]",children:e}),n.map(s=>t.jsxs("div",{className:"flex justify-between gap-3 py-0.5 text-xs",children:[t.jsx("span",{className:"min-w-0 truncate text-[var(--text)]",title:s.label,children:s.label}),t.jsx("span",{className:"shrink-0 tabular-nums text-[var(--text-muted)]",children:s.count.toLocaleString()})]},s.key))]}),gt=({activity:e})=>t.jsx(L,{title:"Activity",children:e.length===0?t.jsx("p",{className:"text-xs text-[var(--text-muted)]",children:"No changes recorded yet."}):t.jsx("ul",{children:e.map((n,s)=>t.jsxs("li",{className:"flex justify-between gap-3 py-1 text-[11px]",children:[t.jsxs("span",{className:"min-w-0",children:[t.jsx("span",{className:"text-[var(--text)]",children:Ye(n)}),n.reason&&t.jsxs("span",{className:"text-[var(--text-muted)]",children:[": “",n.reason,"”"]})]}),t.jsx("span",{className:"shrink-0 text-[var(--text-dim)]",children:V(n.at)})]},`${n.at}-${s}`))})}),bt=({target:e,days:n,tz:s,refreshKey:l,onClose:c,onChanged:o})=>{var $;const{toast:r}=le(),[i,u]=d.useState(null),[b,p]=d.useState("loading"),[h,m]=d.useState(null),[y,k]=d.useState(!1);d.useEffect(()=>{u(null),p("loading")},[e.strategy,e.selector]),d.useEffect(()=>{let a=!0;return I.getSelectorPanel(e.strategy,e.selector,n,s).then(({status:g,body:f})=>{a&&(g===404?(u(null),p("missing")):g===200&&f?(u(f),p("ready")):p("failed"))}).catch(()=>{a&&p("failed")}),()=>{a=!1}},[e.strategy,e.selector,n,s,l]);const w=async(a,g)=>{k(!0);try{await I.postSelectorStateAction({original_strategy:e.strategy,original_selector:e.selector,action:a,...g?{reason:g}:{}}),r(pt[a],"success")}catch(f){const j=f.status;r(j===409?"Someone changed this selector just now. It has been refreshed.":j===404?"This selector isn't available any more.":"That didn't work. Try again.","error")}finally{k(!1),m(null),o()}},T=async(a,g)=>{try{await navigator.clipboard.writeText(a),r(g,"success")}catch{r("Couldn't copy: your browser blocked it.","error")}},A=(($=i==null?void 0:i.state)==null?void 0:$.status)??"active",C=d.useMemo(()=>{var f;const a=(i==null?void 0:i.daily)??[],g=((f=a[0])==null?void 0:f.t)??0;return{start:g,times:a.map(j=>j.t-g),values:a.map(j=>j.heals)}},[i]);return t.jsxs("aside",{"aria-label":"Selector details",className:"sticky top-4 flex max-h-[calc(100vh-7rem)] w-[480px] shrink-0 flex-col overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--surface)]",children:[t.jsxs("header",{className:"border-b border-[var(--border)] p-4",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(D,{children:K(e.strategy)}),i&&t.jsx(vt,{state:i.state}),t.jsxs("span",{className:"ml-auto flex items-center gap-0.5",children:[t.jsx(U,{label:"Copy selector",onClick:()=>void T(e.selector,"Selector copied"),children:t.jsx(oe,{size:14})}),t.jsx(U,{label:"Copy link to this selector",onClick:()=>void T(window.location.href,"Link copied"),children:t.jsx(Be,{size:14})}),t.jsx(U,{label:"Close",onClick:c,children:t.jsx(re,{size:14})})]})]}),t.jsx("code",{className:"mt-2 block break-all font-mono text-xs leading-relaxed text-[var(--text)]",children:e.selector}),(i==null?void 0:i.canAct)&&t.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[A==="active"&&e.strategy!==""&&t.jsx(N,{size:"sm",onClick:()=>m("mark_fixed"),children:"Mark fixed"}),A==="pending"&&t.jsx(N,{size:"sm",variant:"secondary",onClick:()=>m("cancel_verification"),children:"Cancel verification"}),A!=="muted"&&t.jsx(N,{size:"sm",variant:"secondary",onClick:()=>m("mute"),children:"Mute…"}),A==="muted"&&t.jsx(N,{size:"sm",variant:"secondary",disabled:y,onClick:()=>void w("unmute"),children:"Unmute"})]})]}),t.jsxs("div",{className:"min-h-0 flex-1 space-y-5 overflow-y-auto p-4",children:[b==="loading"&&t.jsx("p",{className:"text-xs text-[var(--text-dim)]",children:"Loading…"}),b==="missing"&&t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"This selector isn't available. It may belong to another team, or Xenon has no heals on record for it."}),b==="failed"&&t.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"Couldn't load this selector. Try again in a moment."}),i&&i.heals===0&&t.jsxs("p",{className:"text-sm text-[var(--text-muted)]",children:["No heals in the last ",n," days."]}),i&&i.heals>0&&t.jsxs(t.Fragment,{children:[t.jsx(L,{title:"Suggested fix",children:i.suggestions.length===0?t.jsx("p",{className:"text-xs text-[var(--text-muted)]",children:"Xenon found the element without a selector it can suggest."}):t.jsx("ul",{className:"space-y-2",children:i.suggestions.map((a,g)=>t.jsx("li",{className:`rounded-md border p-2.5 ${g===0?"border-[var(--color-success)]":"border-[var(--border)]"}`,children:t.jsxs("div",{className:"flex items-start gap-2",children:[t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-1.5 text-[11px] text-[var(--text-muted)]",children:[t.jsx(D,{children:K(a.strategy)}),t.jsx("span",{children:de(a.share)}),a.methods.length>0&&t.jsxs("span",{title:a.methods.map(f=>P[f]??f).join(". "),children:["· ",a.methods.join(", ")]}),a.averageConfidence!==null&&t.jsxs("span",{children:["· ",Math.round(a.averageConfidence*100),"% confidence"]})]}),t.jsx("code",{className:"mt-1 block break-all font-mono text-[11px] text-[var(--text)]",children:a.selector})]}),t.jsx(ut,{strategy:a.strategy??e.strategy,value:a.selector,onCopied:f=>r(`Copied as ${f}`,"success")})]})},`${a.strategy??""}\0${a.selector}`))})}),t.jsxs(L,{title:`In the last ${n} days`,children:[t.jsx("div",{className:"grid grid-cols-3 gap-2",children:[{label:i.heals===1?"heal":"heals",value:i.heals.toLocaleString()},{label:i.sessions===1?"session":"sessions",value:i.sessions.toLocaleString()},{label:"spent healing",value:J(i.timeSpentMs)}].map(a=>t.jsxs("div",{className:"rounded-md bg-[rgb(var(--rgb-fg)/0.04)] px-2.5 py-2",children:[t.jsx("div",{className:"text-sm font-semibold tabular-nums text-[var(--text)]",children:a.value}),t.jsx("div",{className:"text-[11px] text-[var(--text-muted)]",children:a.label})]},a.label))}),C.times.length>1&&t.jsx("div",{className:"mt-3",children:t.jsx(ie,{times:C.times,series:[{key:"heals",label:"Heals",color:"var(--color-info)",values:C.values}],formatValue:a=>String(Math.round(a)),formatTime:a=>ce(C.start+a),ariaLabel:"Heals per day for this selector",height:56})})]}),t.jsxs(L,{title:"Where it happens",children:[t.jsx(X,{title:"Platforms",rows:i.platforms.map(a=>({key:a.name,label:Le(a.name),count:a.count}))}),t.jsx(X,{title:"Builds",rows:i.builds.map(a=>({key:a.id??"",label:a.name,count:a.count}))}),t.jsx(X,{title:"Devices",rows:i.devices.map(a=>({key:a.udid,label:a.name,count:a.count}))})]}),t.jsx(L,{title:"Recent heals",children:t.jsx("ul",{className:"divide-y divide-[var(--border)]",children:i.recent.map(a=>t.jsxs("li",{className:"py-2 text-[11px]",children:[t.jsxs("div",{className:"flex items-center gap-1.5 text-[var(--text-muted)]",children:[t.jsx("span",{children:q(a.at)}),a.device&&t.jsxs("span",{className:"min-w-0 truncate",children:["· ",a.device]}),a.method&&t.jsxs("span",{title:P[a.method],children:["· ",a.method,a.confidence!==null?` ${Math.round(a.confidence*100)}%`:""]}),t.jsx(be,{className:"ml-auto shrink-0 text-[var(--color-accent)] hover:underline",to:`/builds/${encodeURIComponent(a.buildId??"none")}/sessions/${encodeURIComponent(a.sessionId)}`,children:"Session"})]}),a.healedSelector&&t.jsx("code",{className:"mt-0.5 block truncate font-mono text-[var(--text)]",title:a.healedSelector,children:a.healedSelector})]},a.id))})})]}),i&&t.jsx(gt,{activity:i.activity})]}),t.jsx(mt,{open:h==="mark_fixed",busy:y,onClose:()=>m(null),onConfirm:()=>void w("mark_fixed")}),t.jsx(xt,{open:h==="cancel_verification",busy:y,onClose:()=>m(null),onConfirm:()=>void w("cancel_verification")}),t.jsx(ht,{open:h==="mute",busy:y,onClose:()=>m(null),onConfirm:a=>void w("mute",a||void 0)})]})},yt=1e3,jt=["healing_event","selector_fixed","selector_resolved","selector_regressed","selector_cancelled","selector_muted","selector_unmuted","selector_progress"],Nt=e=>!!e&&(["INPUT","TEXTAREA","SELECT"].includes(e.tagName)||e.isContentEditable),Ft=()=>{const[e,n]=ye(),s=d.useMemo(()=>Y(e),[e]),l=d.useMemo(()=>-new Date().getTimezoneOffset(),[]),{on:c}=ne(),{toast:o}=le(),{me:r}=je(),i=!!r&&(r.role==="ADMIN"||r.role==="SUPER_ADMIN"||!!r.authDisabled),[u,b]=d.useState(null),[p,h]=d.useState(null),[m,y]=d.useState(!1),[k,w]=d.useState(!1),[T,A]=d.useState(!0),[C,$]=d.useState(0),[a,g]=d.useState(!1),f=d.useCallback((x,v=!1)=>n(Ee({...Y(e),...x}),{replace:v}),[e,n]);d.useEffect(()=>{let x=!0;return I.getHealingSummary(s.days,l).then(v=>{x&&(b(v??null),w(!1))}).catch(()=>{x&&w(!0)}),()=>{x=!1}},[s.days,l,C]),d.useEffect(()=>{let x=!0;return A(!0),I.getHealingSelectors({tab:s.tab,days:s.days,q:s.q,platform:s.platform,method:s.method,sort:s.sort,page:s.page}).then(v=>{x&&(h(v??null),y(!1))}).catch(()=>{x&&y(!0)}).finally(()=>{x&&A(!1)}),()=>{x=!1}},[s.tab,s.days,s.q,s.platform,s.method,s.sort,s.page,C]);const j=d.useRef(null);d.useEffect(()=>{const x=()=>{j.current||(j.current=setTimeout(()=>{j.current=null,$(S=>S+1)},yt))},v=jt.map(S=>c(S,x));return()=>{v.forEach(S=>S&&S()),j.current&&clearTimeout(j.current),j.current=null}},[c]);const M=d.useCallback(x=>f({open:x}),[f]),F=d.useCallback(()=>{const x=s.open?_(s.open):null;f({open:null}),setTimeout(()=>{var S;(S=Array.from(document.querySelectorAll("[data-selector-row]")).find(B=>B.dataset.key===x))==null||S.focus()},0)},[s.open,f]),z=d.useCallback(x=>{const v=(p==null?void 0:p.items)??[];if(v.length===0)return;const S=s.open?v.findIndex(pe=>_(pe)===_(s.open)):-1,B=v[S<0?0:Math.min(v.length-1,Math.max(0,S+x))];f({open:{strategy:B.strategy,selector:B.selector}},!0)},[p,s.open,f]);d.useEffect(()=>{if(!s.open)return;const x=v=>{v.defaultPrevented||Nt(document.activeElement)||document.querySelector('[role="dialog"]')||(v.key==="Escape"?(v.preventDefault(),F()):v.key==="ArrowDown"?(v.preventDefault(),z(1)):v.key==="ArrowUp"&&(v.preventDefault(),z(-1)))};return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[s.open,F,z]);const he=async()=>{g(!0);try{const x=await I.sendHealingDigest({windowDays:s.days,limit:5,minHealCount:2}),v=(x==null?void 0:x.sent)??0;v===0?o("No webhook gets the digest yet. Add one in Notifications.","error"):o(`Digest sent to ${v} webhook${v===1?"":"s"}.`,"success")}catch{o("Couldn't send the digest. Try again.","error")}finally{g(!1)}};return t.jsxs("div",{children:[t.jsx(Se,{icon:Ne,eyebrow:"Test quality",title:"Selector health",subtitle:"Selectors your tests could only find with self-healing. Fix the ones that heal most.",action:t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(ke,{size:"sm",label:"Period",value:String(s.days),onChange:x=>f({days:Number(x),page:1}),segments:Te.map(x=>({value:String(x),label:`${x} days`}))}),i&&t.jsxs(N,{variant:"secondary",size:"sm",onClick:()=>void he(),disabled:a,children:[t.jsx(Re,{size:14})," Send digest"]})]})}),t.jsxs("div",{className:"space-y-4 px-6 pb-8 pt-4",children:[t.jsx(He,{onShow:x=>f(_e(x))}),t.jsx(Qe,{summary:u,days:s.days}),t.jsx(Ze,{trend:u?u.trend??[]:null,days:s.days,failed:k&&!u}),t.jsxs("div",{className:"flex items-start gap-4",children:[t.jsx("div",{className:"min-w-0 flex-1",children:t.jsx(rt,{view:s,data:p,loading:T,compact:!!s.open,selectedKey:s.open?_(s.open):null,onView:f,onOpen:M,error:m})}),s.open&&t.jsx(bt,{target:s.open,days:s.days,tz:l,refreshKey:C,onClose:F,onChanged:()=>$(x=>x+1)})]})]})]})};export{yt as LIVE_REFRESH_MS,Ft as default};
@@ -0,0 +1,4 @@
1
+ import{r as x,X as S,j as e,e as te,f as Ae,t as I,y as Ee,R as Le,p as De,i as Me,u as Oe}from"./index-BOxe43p1.js";import{C as Fe,d as Pe,p as Ne,e as He,r as ye,f as Ie,j as we,k as X,c as Be,h as re,u as Ue,b as Ve,q as ze}from"./use-builds-data-NeQOFEoy.js";import{A as Je}from"./arrow-left-BWfCbeHP.js";import{C as K}from"./chevron-right-B2QOv9Nx.js";import{s as We}from"./labels-C21SA4JG.js";import{B as Ke,S as ke,u as qe,P as $}from"./index-B9KQ6LsY.js";import{C as Xe}from"./circle-x-DTwnSAnl.js";import{C as Ge}from"./circle-check-CYXBoUqT.js";import{S as F}from"./stat-tile-xVqAKIlI.js";import{h as G,p as Ye,a as se,b as ae}from"./derive-UnLRp4r3.js";import{C as Y}from"./copy-Be7LNMXV.js";import{A as Qe}from"./arrow-up-right-BOjwybDk.js";import{A as Ze}from"./arrow-right-DC7UGf_n.js";import{f as et,a as ne,C as Se,b as tt,s as rt,L as st,n as ie}from"./line-chart-Gl_Dz3X_.js";import{E as M}from"./EmptyState-DqWU2-vM.js";import{A as at}from"./activity-CJ8LwZq9.js";import{V as nt}from"./video-off-OK1lNZQn.js";import{D as _e}from"./download-B56lwxWP.js";import{T as it,a as ot,b as oe,c as E,d as lt,e as L}from"./Table-zNTX92Pn.js";import{M as ct}from"./Modal-Bsvj1tm2.js";import{N as dt}from"./network-Dii9qdvk.js";import"./time-D-gjmE1o.js";import"./index-CfxsUslp.js";const xt=4e3,le=t=>!!t&&typeof t=="object"&&typeof t.id=="string"&&typeof t.status=="string";function mt(t){const[r,s]=x.useState(null),[a,n]=x.useState([]),[o,l]=x.useState([]),[i,c]=x.useState([]),[m,b]=x.useState([]),[f,j]=x.useState(!0),[p,g]=x.useState(null),[y,w]=x.useState(!1),[R,A]=x.useState(0),_=x.useRef(null);x.useEffect(()=>{if(!t){s(null),n([]),l([]),c([]),b([]),w(!1),j(!1);return}let v=!0;return _.current!==t&&j(!0),Promise.all([S.getSession(t),S.getSessionLogs(t),S.getDeviceLogs(t),S.getDebugLogs(t),S.getProfilingData(t).catch(()=>[])]).then(([h,C,d,N,D])=>{if(!v)return;const O=le(h);s(O?h:null),O?(_.current=t,w(!1),g(null)):(w(!!h&&typeof h=="object"&&(h.error===!0||typeof h.message=="string")),g(typeof(h==null?void 0:h.message)=="string"?h.message:"Session not found")),n(Array.isArray(C)?C:[]),l(Array.isArray(d)?d:[]),c(Array.isArray(N)?N:[]),b(Array.isArray(D)?D:[])}).catch(h=>{v&&g(h instanceof Error?h.message:String(h))}).finally(()=>{v&&j(!1)}),()=>{v=!1}},[t,R]);const u=(r==null?void 0:r.status)==="running";return x.useEffect(()=>{if(!t||!u)return;let v=!0;const h=setInterval(async()=>{try{const[C,d]=await Promise.all([S.getSession(t),S.getSessionLogs(t)]);if(!v||!le(C))return;s(C),Array.isArray(d)&&n(d),C.status!=="running"&&A(N=>N+1)}catch{}},xt);return()=>{v=!1,clearInterval(h)}},[t,u]),{session:r,sessionLogs:a,deviceLogs:o,debugLogs:i,profiling:m,loading:f,error:p,notFound:y,refresh:()=>A(v=>v+1)}}const ce=({buildId:t,buildName:r,sessionId:s})=>e.jsxs("nav",{"aria-label":"Breadcrumb",className:"flex items-center gap-2 px-4 py-2 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs(te,{to:"/builds",className:"inline-flex items-center gap-1.5 text-xs text-[var(--text-muted)] hover:text-[var(--text)] transition-colors",children:[e.jsx(Je,{className:"h-3.5 w-3.5"}),"Sessions"]}),e.jsx(K,{className:"h-3 w-3 text-[var(--text-dim)]"}),r&&e.jsxs(e.Fragment,{children:[e.jsx(te,{to:`/builds/${t}`,className:"text-[11px] text-[var(--color-accent)] hover:underline",children:r}),e.jsx(K,{className:"h-3 w-3 text-[var(--text-dim)]"})]}),e.jsxs("span",{className:"font-mono text-[11px] text-[var(--text-muted)]",title:s,children:["#",s.slice(0,8)]})]}),ut={passed:{label:"Passed",Icon:Ge,cls:"text-[var(--color-success)]"},failed:{label:"Failed",Icon:Xe,cls:"text-[var(--color-danger)]"},running:{label:"Running",Icon:Ae,cls:"text-[var(--color-warning)]"},other:{Icon:Fe,cls:"text-[var(--text-dim)]"}};function Q(t){const r=Be(t),s=ut[r];return{bucket:r,...s,label:s.label??We(t||"unknown")}}const ht=({session:t})=>{var o,l;const r=Q(t.status),s=Pe(t),a=[Ne(t),t.device_version].filter(i=>i&&i!=="—").join(" "),n=[[He(t),a].filter(Boolean).join(" · "),ye(t.ranOn),(o=t.owner)==null?void 0:o.name,Ie(t.startTime),we(X(t))].filter(i=>i&&i!=="—");return e.jsxs("header",{className:"flex items-start justify-between gap-4 px-4 py-4 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsxs("span",{className:`inline-flex items-center gap-1.5 text-xs font-medium shrink-0 ${r.cls}`,children:[e.jsx(r.Icon,{className:`h-3.5 w-3.5 ${r.bucket==="running"?"animate-spin":""}`,"aria-hidden":"true"}),r.label]}),e.jsx("h1",{className:`text-lg font-semibold truncate ${s.source==="name"?"text-[var(--text)]":"text-[var(--text-muted)]"}`,title:s.source==="name"?s.text:`${s.text}
2
+ Unnamed session. Set xe:options.name in its capabilities to name it.`,children:s.text})]}),e.jsx("p",{"data-testid":"outcome-meta",className:"mt-1 text-xs text-[var(--text-muted)] tabular-nums truncate",title:((l=t.owner)==null?void 0:l.email)??void 0,children:n.join(" · ")})]}),e.jsx("div",{className:"shrink-0",children:e.jsx(Ke,{sessionId:t.id,mode:"full",variant:"inline"})})]})},B=t=>t.command_name||t.title||"command",q=t=>{const r=t.createdAt?Date.parse(t.createdAt):NaN;return Number.isFinite(r)?r:0},Z=t=>[...t].sort((r,s)=>q(r)-q(s));function U(t){return t.is_success===!1||t.is_error===!0}function Ce(t){const r=[];let s=null;for(const a of Z(t))a.is_healed&&a.healing_tier&&!r.includes(a.healing_tier)&&r.push(a.healing_tier),typeof a.duration=="number"&&(!s||a.duration>s.ms)&&(s={name:B(a),ms:a.duration});return{total:t.length,failed:t.filter(U).length,healed:t.filter(a=>a.is_healed).length,healedTiers:r,slowest:s,screenshots:t.filter(a=>a.screenshot).length}}const de=(t,r)=>r?t?`${t}=${r}`:r:null;function ft(t){return Z(t.filter(r=>r.is_healed)).map(r=>({id:r.id,command:B(r),original:de(r.original_strategy,r.original_selector),healed:de(r.healed_strategy,r.healed_selector),tier:r.healing_tier??null,confidence:typeof r.healing_confidence=="number"?Math.round(r.healing_confidence*100):null,at:r.createdAt}))}function pt(t){var r;if(!t.response)return null;try{const s=(r=JSON.parse(t.response))==null?void 0:r.value;if(!s||typeof s!="object")return null;const a=typeof s.message=="string"?s.message.trim():"";return a||(typeof s.error=="string"&&s.error?s.error:null)}catch{return null}}function vt(t){if(t.length===0)return{spanMs:0,bars:[]};const r=t.map(n=>{const o=q(n),l=typeof n.duration=="number"&&n.duration>0?n.duration:0;return{l:n,start:o-l,end:o,durationMs:l}}),s=Math.min(...r.map(n=>n.start)),a=Math.max(...r.map(n=>n.end));return{spanMs:Math.max(1,a-s),bars:r.sort((n,o)=>n.start-o.start).map(({l:n,start:o,durationMs:l})=>({id:n.id,label:B(n),startMs:o-s,durationMs:l,failed:U(n),healed:!!n.is_healed}))}}function bt(t){return Z(t.filter(r=>r.screenshot)).map(r=>({id:r.id,path:r.screenshot,command:B(r),at:r.createdAt,failed:U(r)}))}function H(t){if(t==null||!Number.isFinite(t)||t<0)return"—";if(t<1e3)return`${Math.round(t)}ms`;if(t<6e4)return`${(t/1e3).toFixed(1)}s`;const r=Math.round(t/1e3);return`${Math.floor(r/60)}m ${r%60}s`}const gt=({session:t,commands:r})=>{var l,i;const s=Q(t.status),a=Ce(r),n=we(X(t)),o=s.bucket==="failed"?G(t.failure_category)||"No category recorded":s.bucket==="running"?`Running for ${n}`:`Ran ${n}`;return e.jsxs("div",{className:"grid grid-cols-4 gap-3",children:[e.jsx(F,{label:"Result",value:s.label,valueCls:s.cls,note:o,noteTone:s.bucket==="failed"?"bad":"neutral"}),e.jsx(F,{label:"Commands",value:a.total,note:a.failed>0?`${a.failed} failed`:"None failed",noteTone:a.failed>0?"bad":"neutral"}),e.jsx(F,{label:"Self-healing",value:a.healed>0?`${a.healed} healed`:"None",note:a.healed>0?a.healedTiers.join(", ")||"Tier not recorded":"No selector needed healing"}),e.jsx(F,{label:"Slowest command",value:H((l=a.slowest)==null?void 0:l.ms),note:((i=a.slowest)==null?void 0:i.name)??"No timings recorded"})]})};function jt(t){const r=t.filter(U),s=r[r.length-1];return s?{command:s.command_name||s.title||"command",message:pt(s)}:null}function Nt(t,r,s,a,n){var m;const o=G(t.failure_category),l=((m=t.device_name)==null?void 0:m.trim())||"Unknown Device",i=t.device_version?` ${t.device_version}`:"",c=n?`${n.command}${n.message?`: ${n.message}`:""}`:"(no failed command recorded)";return[`**Session:** ${t.id}`,`**Build:** ${r} (#${s})`,`**Device:** ${l} (${t.node_id||"unknown-node"}) · ${t.device_platform||"unknown"}${i}`,`**Duration:** ${a}`,`**Failure category:** ${o||"(uncategorized)"}`,`**Failure reason:** ${t.failure_reason||"(not set)"}`,`**First failed command:** ${c}`,...t.ai_analysis?[`**AI analysis:** ${t.ai_analysis}`]:[]].join(`
3
+ `)}function yt({text:t}){return e.jsx(e.Fragment,{children:t.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).map((r,s)=>/^\*\*[^*]+\*\*$/.test(r)?e.jsx("strong",{children:r.slice(2,-2)},s):/^`[^`]+`$/.test(r)?e.jsx("code",{className:"font-mono text-[11px] px-1 rounded bg-[var(--surface-2)]",children:r.slice(1,-1)},s):e.jsx(Le.Fragment,{children:r},s))})}const P=({children:t})=>e.jsx("div",{className:"text-[11px] font-semibold text-[var(--text-dim)] mb-1",children:t}),wt=({session:t,buildName:r,buildId:s,commands:a,durationText:n})=>{var y;const{toast:o}=I(),[l,i]=x.useState(!1),c=G(t.failure_category),m=jt(a),b=Ye(t.failure_reason),f=(y=t.ai_analysis)==null?void 0:y.trim(),j=!!f&&f.length>480,p=async()=>{const w=Nt(t,r,s,n,m);try{await navigator.clipboard.writeText(w),o("Failure report copied","success")}catch{o("Clipboard unavailable","error")}},g=t.failure_category?`/xenon/runbooks/${encodeURIComponent(t.failure_category.toLowerCase())}`:void 0;return e.jsxs("section",{className:"rounded-lg border border-[var(--red)]/30 bg-[var(--surface)] overflow-hidden",children:[e.jsxs("header",{className:"flex items-center justify-between gap-4 px-4 py-3 border-b border-[var(--border)] bg-[var(--red)]/5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ee,{className:"h-4 w-4 text-[var(--red)]","aria-hidden":"true"}),e.jsx("h2",{className:"text-sm font-semibold text-[var(--red)]",children:"Why it failed"}),c&&e.jsx("span",{className:"text-[11px] text-[var(--text-dim)] ml-2",children:c})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{type:"button",onClick:p,className:"inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors",children:[e.jsx(Y,{className:"h-3 w-3"}),"Copy"]}),e.jsxs("a",{...g?{href:g,target:"_blank",rel:"noreferrer"}:{"aria-disabled":!0,onClick:w=>w.preventDefault()},className:`inline-flex items-center gap-1.5 h-7 px-2.5 rounded-md border border-[var(--border)] text-xs text-[var(--text)] hover:border-[var(--border-strong)] hover:bg-[var(--surface-2)] transition-colors ${g?"":"opacity-50 cursor-not-allowed"}`,title:g?"Open runbook in new tab":"No runbook — failure category not set",children:[e.jsx(Qe,{className:"h-3 w-3"}),"Open runbook"]})]})]}),e.jsxs("div",{className:"px-4 py-4 space-y-4",children:[e.jsxs("div",{children:[e.jsx(P,{children:"Reason"}),e.jsx("div",{className:"text-sm text-[var(--text)] break-words",children:t.failure_reason||e.jsx("span",{className:"text-[var(--text-dim)]",children:"(not set)"})})]}),e.jsxs("div",{children:[e.jsx(P,{children:"First failed command"}),m?e.jsxs("div",{className:"flex items-baseline gap-2 min-w-0 text-sm",children:[e.jsx("span",{className:"font-mono text-xs text-[var(--color-danger)] shrink-0",children:m.command}),m.message&&e.jsx("span",{className:"text-[var(--text-muted)] break-words min-w-0",children:m.message})]}):e.jsx("span",{className:"text-sm text-[var(--text-dim)]",children:"No failed command recorded."})]}),f&&e.jsxs("div",{"data-testid":"ai-analysis",children:[e.jsx(P,{children:e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(ke,{className:"h-3 w-3","aria-hidden":"true"}),"AI analysis"]})}),e.jsx("div",{className:`text-sm text-[var(--text)] whitespace-pre-wrap break-words ${j&&!l?"line-clamp-6":""}`,children:e.jsx(yt,{text:f})}),j&&e.jsx("button",{type:"button",onClick:()=>i(w=>!w),"aria-expanded":l,className:"mt-1 text-xs text-[var(--color-accent)] hover:underline",children:l?"Show less":"Show all"})]}),b.length>0&&e.jsxs("div",{children:[e.jsx(P,{children:"Stack trace"}),e.jsx("pre",{className:"rounded-md border border-[var(--border)] bg-[var(--bg)] p-3 font-mono text-[11px] leading-relaxed text-[var(--color-accent)] overflow-x-auto",children:b.join(`
4
+ `)})]})]})]})};function kt(t){return t>=1e3?`${(t/1e3).toFixed(1).replace(/\.0$/,"")}k`:String(t)}function V(t){const r=t;return typeof r.message=="string"&&!r.command_name&&!r.title}const St=/^\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+\s+\d+\s+\d+\s+([VDIWEF])\s/,_t=/^([VDIWEF])\/[^(:]*[(:]/,Ct=/<(Error|Fault|Warning)>/;function Re(t){var a,n,o;const r=((a=St.exec(t))==null?void 0:a[1])??((n=_t.exec(t))==null?void 0:n[1]);if(r)return r==="E"||r==="F"?"error":r==="W"?"warn":null;const s=(o=Ct.exec(t))==null?void 0:o[1];return s?s==="Warning"?"warn":"error":null}function z(t){const r=t.timestamp;if(!r){const l=t.createdAt;return l?z({timestamp:l}):"--:--:--"}const s=typeof r=="number"?new Date(r):new Date(String(r));if(Number.isNaN(s.getTime()))return"--:--:--";const a=String(s.getHours()).padStart(2,"0"),n=String(s.getMinutes()).padStart(2,"0"),o=String(s.getSeconds()).padStart(2,"0");return`${a}:${n}:${o}`}function Rt(t){if(V(t)){const s=Re(t.message);return s==="error"?{label:"error",tone:"red"}:s==="warn"?{label:"warn",tone:"amber"}:{label:"",tone:"neutral"}}if(t.is_healed===!0)return{label:String(t.command_name||"healed"),tone:"amber"};if(t.is_success===!1||t.is_error===!0)return{label:String(t.command_name||t.title||"error"),tone:"red"};if(t.is_success===!0)return{label:String(t.command_name||t.title||"ok"),tone:"green"};const r=t.title||t.event||t.command_name;return typeof r=="string"?/stop|fail|error/i.test(r)?{label:r,tone:"red"}:/start|begin|init/i.test(r)?{label:r,tone:"green"}:{label:r,tone:"blue"}:{label:"log",tone:"neutral"}}function Tt(t){if(t==null)return"";if(typeof t=="string")try{return JSON.stringify(JSON.parse(t),null,2)}catch{return t}try{return JSON.stringify(t,null,2)}catch{return String(t)}}function $t(t){if(!t||typeof t!="string")return[{text:String(t??""),kind:"plain"}];const r=[],s=/("(?:\\.|[^"\\])*")(\s*:)|("(?:\\.|[^"\\])*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|\b(true|false)\b|\b(null)\b|([{}[\],])/g;let a=0,n;for(;(n=s.exec(t))!==null;)n.index>a&&r.push({text:t.slice(a,n.index),kind:"plain"}),n[1]&&n[2]!==void 0?(r.push({text:n[1],kind:"key"}),r.push({text:n[2],kind:"punct"})):n[3]?r.push({text:n[3],kind:"string"}):n[4]?r.push({text:n[4],kind:"number"}):n[5]?r.push({text:n[5],kind:"boolean"}):n[6]?r.push({text:n[6],kind:"null"}):n[7]&&r.push({text:n[7],kind:"punct"}),a=s.lastIndex;return a<t.length&&r.push({text:t.slice(a),kind:"plain"}),r}function At(t){if(V(t))return t.message.split(/\r?\n/,1)[0].trimEnd();const r=t,s=typeof r.title=="string"&&r.title.trim()?r.title.trim():null,a=typeof r.command_name=="string"&&r.command_name.trim()?r.command_name.trim():null;return s??a??"Command"}function xe(t){const r=t.subtitle;return typeof r=="string"&&r.trim()?r.trim():null}function Et(t,r){return r?t.filter(s=>s.is_success===!1||s.is_error===!0||V(s)&&Re(s.message)==="error"):t}const Lt=({commands:t})=>{const r=ft(t);return r.length===0?null:e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsxs("header",{className:"flex items-center gap-2 px-4 py-3 border-b border-[var(--border)]",children:[e.jsx(ke,{className:"h-4 w-4 text-[var(--color-warning)]","aria-hidden":"true"}),e.jsx("h2",{className:"text-sm font-semibold text-[var(--text)]",children:"Self-healing"}),e.jsxs("span",{className:"text-[11px] text-[var(--text-muted)]",children:[r.length," selector",r.length===1?"":"s"," healed. Update the test so the next run doesn't need to."]})]}),e.jsxs("table",{className:"w-full table-fixed text-left",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[var(--border)] text-[11px] text-[var(--text-dim)]",children:[e.jsx("th",{className:"px-4 py-2 font-medium w-[88px]",children:"Time"}),e.jsx("th",{className:"px-3 py-2 font-medium w-[128px]",children:"Command"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Asked for"}),e.jsx("th",{className:"w-[28px]",children:e.jsx("span",{className:"sr-only",children:"healed to"})}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Healed to"}),e.jsx("th",{className:"px-3 py-2 font-medium w-[112px]",children:"Tier"}),e.jsx("th",{className:"px-4 py-2 font-medium w-[96px] text-right",children:"Confidence"})]})}),e.jsx("tbody",{children:r.map((s,a)=>e.jsxs("tr",{className:"border-b border-[var(--border)] last:border-b-0 align-top",children:[e.jsx("td",{className:"px-4 py-2 text-xs text-[var(--text-muted)] tabular-nums",children:z({timestamp:s.at??null})}),e.jsx("td",{className:"px-3 py-2 text-xs text-[var(--text)] truncate",children:s.command}),e.jsx("td",{className:"px-3 py-2 font-mono text-[11px] text-[var(--text-muted)] break-all",children:s.original??"—"}),e.jsx("td",{className:"py-2 text-[var(--text-dim)]",children:e.jsx(Ze,{className:"h-3.5 w-3.5","aria-hidden":"true"})}),e.jsx("td",{className:"px-3 py-2 font-mono text-[11px] text-[var(--text)] break-all",children:s.healed??"—"}),e.jsx("td",{className:"px-3 py-2 text-xs text-[var(--text)]",children:s.tier??"—"}),e.jsx("td",{className:"px-4 py-2 text-xs text-[var(--text)] tabular-nums text-right",children:s.confidence===null?"—":`${s.confidence}%`})]},s.id??a))})]})]})},Dt=1e4,me="var(--color-info)",ue="var(--color-accent)",Mt="var(--border-strong)";function he(t){return t>=1024?ie(t/1024)*1024:ie(t)}const fe=t=>{let r=0;for(const s of t)for(const a of s.values)a!==null&&a>r&&(r=a);return r},W=({title:t,series:r,times:s,yMax:a,format:n,ariaLabel:o})=>e.jsxs("section",{"aria-label":t,children:[e.jsxs("div",{className:"mb-2 flex flex-wrap items-baseline gap-x-4 gap-y-1",children:[e.jsx("h3",{className:"text-xs font-semibold text-[var(--text)]",children:t}),r.map(l=>{const i=rt(l.values);return e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5 text-[11px] tabular-nums text-[var(--text-muted)]",children:[e.jsx("span",{className:"inline-block h-0.5 w-3 shrink-0",style:{background:l.color}}),e.jsx("span",{className:"max-w-[16rem] truncate",title:l.label,children:l.label}),i&&(l.dashed?e.jsx("span",{children:n(i.peak)}):e.jsxs("span",{children:["peak ",n(i.peak)," · avg ",n(i.average)]}))]},l.key)})]}),e.jsx(st,{times:s,series:r,yMax:a,formatValue:n,ariaLabel:o})]}),Ot=({sessionId:t,running:r,hasTrace:s})=>{const[a,n]=x.useState(null),[o,l]=x.useState(!1);x.useEffect(()=>{let u=!0;const v=()=>S.getSessionMetrics(t).then(C=>{u&&(n(tt(C)),l(!0))}).catch(()=>{u&&l(!0)});if(v(),!r)return()=>{u=!1};const h=setInterval(()=>void v(),Dt);return()=>{u=!1,clearInterval(h)}},[t,r]);const i=(a==null?void 0:a.samples)??[],c=x.useMemo(()=>i.map(u=>{var v;return u.t-(((v=i[0])==null?void 0:v.t)??0)}),[i]),m=new Set(i.map(u=>u.app).filter(u=>!!u)),b=m.size>1?"Foreground app":Array.from(m)[0]??(a==null?void 0:a.appId)??"App",f=i.map(u=>u.app??null),j=u=>u>0&&!!f[u]&&!!f[u-1]&&f[u]!==f[u-1],p=[],g=[],y=[];a&&(a.series.deviceCpu&&p.push({key:"deviceCpu",label:"Device",color:me,values:i.map(u=>u.deviceCpu)}),a.series.appCpu&&p.push({key:"appCpu",label:b,color:ue,values:i.map((u,v)=>j(v)?null:u.appCpu),pointLabels:f}),a.series.appMem&&g.push({key:"appMem",label:b,color:ue,values:i.map((u,v)=>j(v)?null:u.appMemMb),pointLabels:f}),a.series.deviceMem&&(y.push({key:"deviceMem",label:"Device used",color:me,values:i.map(u=>u.deviceMemMb)}),y.push({key:"deviceTotal",label:"Device total",color:Mt,values:i.map(u=>u.deviceMemTotalMb),dashed:!0})));const w=r&&(a==null?void 0:a.recording)==="off",R=(a==null?void 0:a.recording)==="stopped",A="Recording stopped: the device stopped responding.";let _;return o?w?_=e.jsx(M,{title:"Performance isn't recorded for this session",description:"CPU and memory are recorded for Android devices and iPhones. This session runs on an iOS simulator or on a machine that needs updating, or recording is turned off."}):i.length===0&&!r?_=e.jsx(M,{title:"No performance data for this session",description:"CPU and memory are recorded for Android devices and iPhones. This session ran on an iOS simulator or on a machine that needed updating, before recording was available, or with recording turned off."}):i.length<2?_=e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:R?A:r?"Collecting… The first figures appear within 10 seconds.":"Too few figures were recorded to draw a chart."}):_=e.jsxs("div",{className:"space-y-4",children:[R&&e.jsxs("p",{className:"text-xs text-[var(--color-warning)]",children:[A," The data ends there."]}),(a==null?void 0:a.platform)==="ios"&&e.jsxs("p",{className:"text-xs text-[var(--text-dim)]",children:["On iPhones, only the device's overall CPU is recorded.",s?" For more detail, download the Performance trace under Details.":""]}),p.length>0&&e.jsx(W,{title:"CPU",series:p,times:c,yMax:100,format:et,ariaLabel:"CPU over the session"}),g.length>0&&e.jsx(W,{title:"App memory",series:g,times:c,yMax:he(fe(g)),format:ne,ariaLabel:"App memory over the session"}),y.length>0&&e.jsx(W,{title:"Device memory",series:y,times:c,yMax:he(fe(y)),format:ne,ariaLabel:"Device memory over the session"})]}):_=e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"Loading performance…"}),e.jsx(Se,{header:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(at,{size:14})," Performance"]}),children:_})};function Ft(t){const r=t.status==="running";return t.video_recording_enabled===!1?r?"Recording is off for this session.":"Recording was off for this session.":r?"Any video appears here after the session ends.":"No video was saved for this session."}const Pt=({session:t})=>{const r=t.status==="running",s=!!t.video_recording;return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsxs("header",{className:"px-3 py-2 border-b border-[var(--border)] flex items-center justify-between",children:[e.jsx("span",{className:"text-[11px] font-semibold text-[var(--text-dim)]",children:"Recording"}),r&&e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-[11px] text-[var(--red)]",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-[var(--red)] pulse-dot"}),"Live"]})]}),e.jsx("div",{className:"aspect-video bg-[var(--bg)] flex items-center justify-center",children:r&&t.has_live_video?e.jsx("img",{src:S.getSessionLiveVideoUrl(t.id),alt:`Live view of session ${t.id}`,className:"w-full h-full object-contain"}):s?e.jsx("video",{controls:!0,src:S.getAssetUrl(t.video_recording),className:"w-full h-full object-contain"}):e.jsxs("div",{className:"flex flex-col items-center text-center px-6 py-8 gap-2",children:[e.jsx("div",{className:"h-10 w-10 rounded-full bg-[var(--surface-2)] border border-[var(--border)] flex items-center justify-center",children:e.jsx(nt,{className:"h-5 w-5 text-[var(--text-dim)]"})}),e.jsx("div",{className:"text-sm text-[var(--text)] font-medium",children:"No video available"}),e.jsx("div",{className:"text-xs text-[var(--text-dim)] max-w-xs",children:Ft(t)})]})})]})},T=({label:t,children:r,title:s,mono:a})=>e.jsxs("div",{className:"flex items-baseline justify-between gap-3 px-3 py-2",children:[e.jsx("dt",{className:"text-xs text-[var(--text-muted)] shrink-0",children:t}),e.jsx("dd",{className:`text-xs text-[var(--text)] text-right min-w-0 break-all ${a?"font-mono text-[11px]":""}`,title:s,children:r})]}),Ht=({session:t,buildName:r})=>{var l,i;const{toast:s}=I(),a=ye(t.ranOn),n=t.performance_trace?S.getAssetUrl(t.performance_trace):"",o=async()=>{try{await navigator.clipboard.writeText(t.id),s("Session ID copied","success")}catch{s("Clipboard unavailable","error")}};return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsx("header",{className:"px-3 py-2 border-b border-[var(--border)]",children:e.jsx("h2",{className:"text-[11px] font-semibold text-[var(--text-dim)]",children:"Details"})}),e.jsxs("dl",{className:"divide-y divide-[var(--border)]",children:[e.jsx(T,{label:"Session ID",mono:!0,children:e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx("span",{children:t.id}),e.jsx("button",{type:"button",onClick:o,"aria-label":"Copy session ID",className:"p-0.5 rounded text-[var(--text-dim)] hover:text-[var(--text)]",children:e.jsx(Y,{className:"h-3 w-3"})})]})}),r&&e.jsx(T,{label:"Build",children:r}),e.jsx(T,{label:"Device UDID",mono:!0,children:t.device_udid||"—"}),e.jsx(T,{label:"Platform",children:[Ne(t),t.device_version].filter(c=>c&&c!=="—").join(" ")||"—"}),e.jsx(T,{label:"Ran on",title:t.node_id?`Node ${t.node_id}`:void 0,children:a??"Not known"}),e.jsx(T,{label:"Run by",title:(l=t.owner)==null?void 0:l.email,children:((i=t.owner)==null?void 0:i.name)??"Not recorded"}),e.jsx(T,{label:"Started",children:re(t.startTime)}),e.jsx(T,{label:"Ended",children:t.endTime?re(t.endTime):"—"}),t.tags&&e.jsx(T,{label:"Tags",children:t.tags}),n&&e.jsx(T,{label:"iOS trace",children:e.jsxs("a",{href:n,className:"inline-flex items-center gap-1 text-[var(--color-accent)] hover:underline",children:[e.jsx(_e,{className:"h-3 w-3","aria-hidden":"true"}),"Performance trace"]})})]})]})},pe={desired:"Requested",session:"Actual"},It=({session:t})=>{const[r,s]=x.useState("desired"),a=se(t.desired_capabilities),n=se(t.session_capabilities),l=Object.entries(r==="desired"?a:n);return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] overflow-hidden",children:[e.jsx("header",{className:"flex items-center border-b border-[var(--border)]",children:["desired","session"].map(i=>e.jsx("button",{type:"button",onClick:()=>s(i),"aria-pressed":r===i,className:`flex-1 h-9 text-[11px] font-semibold transition-colors border-b-2 ${r===i?"border-[var(--color-accent)] text-[var(--text)]":"border-transparent text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:pe[i]},i))}),l.length===0?e.jsxs("div",{className:"px-3 py-6 text-center text-xs text-[var(--text-dim)]",children:["No ",pe[r].toLowerCase()," capabilities recorded for this session."]}):e.jsx("dl",{className:"divide-y divide-[var(--border)]",children:l.map(([i,c])=>e.jsxs("div",{className:"grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] items-baseline gap-3 px-3 py-2",children:[e.jsx("dt",{className:"text-xs text-[var(--text-muted)] break-all",children:i}),e.jsx("dd",{className:"font-mono text-xs text-[var(--text)] truncate text-right min-w-0",title:ae(c,500),children:ae(c)})]},i))})]})},Bt=({tabs:t,active:r,onChange:s,errorsOnly:a,onErrorsOnlyChange:n,showErrorsOnly:o=!0})=>{const l=t.filter(i=>!(i.hideWhenEmpty&&i.count===0));return e.jsxs("div",{className:"flex items-center justify-between gap-4 px-3 border-b border-[var(--border)] bg-[var(--surface)]",children:[e.jsx("div",{className:"flex items-center gap-1 overflow-x-auto",children:l.map(i=>{const c=i.key===r;return e.jsxs("button",{type:"button",onClick:()=>s(i.key),"aria-pressed":c,"data-empty":i.count===0?"true":"false",className:`relative inline-flex items-center gap-1.5 h-9 px-3 text-xs whitespace-nowrap transition-colors ${c?"text-[var(--text)]":i.count===0?"text-[var(--text-dim)] hover:text-[var(--text-muted)]":"text-[var(--text-muted)] hover:text-[var(--text)]"}`,children:[e.jsx("span",{children:i.label}),i.count>0&&e.jsx("span",{className:`text-[10px] tabular-nums ${c?"text-[var(--text-muted)]":"text-[var(--text-dim)]"}`,children:kt(i.count)}),c&&e.jsx("span",{className:"absolute left-2 right-2 bottom-0 h-[2px] bg-[var(--color-accent)] rounded-t"})]},i.key)})}),o&&e.jsxs("label",{className:"inline-flex items-center gap-2 text-[11px] text-[var(--text-muted)] cursor-pointer select-none whitespace-nowrap",children:[e.jsx("input",{type:"checkbox",checked:a,onChange:i=>n(i.target.checked),"aria-label":"Show only error rows"}),"Errors only"]})]})},Ut={key:"text-[var(--blue)]",string:"text-[var(--color-accent)]",number:"text-[var(--amber)]",boolean:"text-[var(--amber)]",null:"text-[var(--text-dim)] italic",punct:"text-[var(--text-muted)]",plain:"text-[var(--text)]"},Vt=({value:t,maxHeightPx:r})=>{const s=Tt(t);if(!s)return e.jsx("span",{className:"text-[var(--text-dim)] text-xs",children:"(empty)"});let a;try{a=$t(s)}catch{a=[{text:s,kind:"plain"}]}return e.jsx("pre",{className:"font-mono text-[11px] leading-relaxed bg-[var(--bg)] border border-[var(--border)] rounded-md p-3 overflow-x-auto whitespace-pre",style:r?{maxHeight:r,overflowY:"auto"}:void 0,children:a.map((n,o)=>e.jsx("span",{className:Ut[n.kind],children:n.text},o))})},zt={green:"bg-[var(--color-success)]",red:"bg-[var(--red)]",amber:"bg-[var(--amber)]",blue:"bg-[var(--blue)]",neutral:"bg-[var(--text-dim)]"},Jt={green:"text-[var(--color-success)]",red:"text-[var(--red)]",amber:"text-[var(--amber)]",blue:"text-[var(--blue)]",neutral:"text-[var(--text-muted)]"},Te=({log:t})=>{const[r,s]=x.useState(!1),{toast:a}=I(),n=z(t),o=Rt(t),l=V(t),i=l?String(t.message):"",c=async m=>{m.stopPropagation();try{const b=l?i:t.body??t,f=typeof b=="string"?b:JSON.stringify(b,null,2);await navigator.clipboard.writeText(f),a("Log entry copied","success")}catch{a("Clipboard unavailable","error")}};return e.jsxs("div",{className:"border-b border-[var(--border)] last:border-b-0",children:[e.jsxs("button",{type:"button",onClick:()=>s(m=>!m),"aria-expanded":r,className:"group w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-[var(--surface-2)]/60 transition-colors",children:[e.jsx(K,{className:`h-3 w-3 text-[var(--text-dim)] transition-transform shrink-0 ${r?"rotate-90":""}`}),e.jsx("span",{className:"font-mono text-[11px] text-[var(--text-muted)] w-[64px] shrink-0",children:n}),e.jsx("span",{className:`h-1.5 w-1.5 rounded-full shrink-0 ${zt[o.tone]}`}),o.label&&e.jsx("span",{className:`font-mono text-[11px] font-medium shrink-0 ${Jt[o.tone]}`,children:o.label}),e.jsxs("span",{className:"min-w-0 flex-1 flex items-baseline gap-2 truncate",children:[e.jsx("span",{className:l?"font-mono text-[11px] text-[var(--text)] truncate min-w-0":"text-[12px] text-[var(--text)] shrink-0",children:At(t)}),xe(t)&&e.jsx("span",{className:"font-mono text-[11px] text-[var(--text-dim)] truncate min-w-0",children:xe(t)})]}),typeof t.duration=="number"&&e.jsx("span",{className:"text-[11px] tabular-nums text-[var(--text-muted)] shrink-0",children:H(t.duration)}),e.jsx("span",{role:"button",tabIndex:0,onClick:c,onKeyDown:m=>{(m.key==="Enter"||m.key===" ")&&c(m)},"aria-label":"Copy log entry",className:"opacity-0 group-hover:opacity-100 p-1 rounded text-[var(--text-dim)] hover:text-[var(--text)] transition-opacity shrink-0",children:e.jsx(Y,{className:"h-3 w-3"})})]}),r&&e.jsx("div",{className:"px-3 pb-3 pl-9",children:l?e.jsx("pre",{className:"font-mono text-[11px] leading-relaxed text-[var(--text)] bg-[var(--bg)] border border-[var(--border)] rounded-md p-3 max-h-[400px] overflow-auto whitespace-pre-wrap break-words",children:i}):e.jsx(Vt,{value:t.body??t,maxHeightPx:400})})]})},Wt=(t,r)=>t?"bg-[var(--color-danger)]":r?"bg-[var(--color-warning)]":"bg-[var(--color-success)]",Kt=({commands:t})=>{const{spanMs:r,bars:s}=vt(t);return s.length===0?e.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:"No commands recorded for this session."}):e.jsxs("div",{className:"px-3 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between pb-2 text-[11px] text-[var(--text-dim)] tabular-nums",children:[e.jsxs("span",{children:[s.length," command",s.length===1?"":"s"," over ",H(r)]}),e.jsxs("span",{className:"inline-flex items-center gap-3",children:[e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx("span",{className:"h-2 w-2 rounded-sm bg-[var(--color-danger)]"})," Failed"]}),e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx("span",{className:"h-2 w-2 rounded-sm bg-[var(--color-warning)]"})," Healed"]})]})]}),e.jsx("ol",{className:"space-y-1",children:s.map((a,n)=>e.jsxs("li",{"data-testid":"timeline-bar","data-command":a.label,"data-failed":a.failed?"true":"false",className:"grid grid-cols-[128px_minmax(0,1fr)_64px] items-center gap-2",children:[e.jsx("span",{className:"truncate text-[11px] font-mono text-[var(--text-muted)]",title:a.label,children:a.label}),e.jsx("span",{className:"relative h-3 rounded-sm bg-[rgb(var(--rgb-fg)/0.05)]",children:e.jsx("span",{className:`absolute inset-y-0 rounded-sm ${Wt(a.failed,a.healed)}`,style:{left:`${a.startMs/r*100}%`,width:`max(2px, ${a.durationMs/r*100}%)`}})}),e.jsx("span",{className:"text-right text-[11px] tabular-nums text-[var(--text-muted)]",children:a.durationMs>0?H(a.durationMs):"—"})]},a.id??n))})]})},qt=({commands:t})=>{const r=bt(t);return r.length===0?e.jsxs("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:["No screenshots were kept. A failed command keeps one unless"," ",e.jsx("code",{className:"font-mono",children:"xe:options.screenshotOnFailure"})," is false; set"," ",e.jsx("code",{className:"font-mono",children:"xe:options.screenshotOnEveryCommand"})," to keep one for every command."]}):e.jsx("ul",{className:"grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-3 p-3",children:r.map((s,a)=>{const n=S.getAssetUrl(s.path),o=z({timestamp:s.at??null});return e.jsx("li",{children:e.jsxs("a",{href:n,target:"_blank",rel:"noreferrer",className:`block rounded-md border overflow-hidden hover:border-[var(--border-strong)] ${s.failed?"border-[var(--color-danger)]":"border-[var(--border)]"}`,children:[e.jsx("img",{src:n,alt:`${s.command} at ${o}`,loading:"lazy",className:"block w-full aspect-[9/16] object-contain bg-[rgb(var(--rgb-fg)/0.03)]"}),e.jsxs("span",{className:"flex items-center justify-between gap-2 px-2 py-1 text-[11px]",children:[e.jsx("span",{className:`truncate font-mono ${s.failed?"text-[var(--color-danger)]":"text-[var(--text)]"}`,children:s.command}),e.jsx("span",{className:"tabular-nums text-[var(--text-dim)] shrink-0",children:o})]})]})},s.id??a)})})},ve=["commands","device","debug","profiling"],Xt=500,Gt=33,Yt=({rows:t,scroller:r})=>{const s=qe({count:t.length,getScrollElement:()=>r.current,estimateSize:()=>Gt,getItemKey:a=>t[a].id??a,overscan:20});return e.jsx("div",{className:"relative",style:{height:s.getTotalSize()},children:s.getVirtualItems().map(a=>e.jsx("div",{"data-index":a.index,ref:s.measureElement,className:`absolute left-0 top-0 w-full${a.index<t.length-1?" border-b border-[var(--border)]":""}`,style:{transform:`translateY(${a.start}px)`},children:e.jsx(Te,{log:t[a.index]})},String(a.key)))})},Qt=({sessionLogs:t,deviceLogs:r,debugLogs:s,profiling:a})=>{const[n,o]=x.useState("commands"),[l,i]=x.useState(!1),c=x.useRef(null),m=t,b=x.useMemo(()=>Ce(m).screenshots,[m]),f=x.useMemo(()=>[{key:"commands",label:"Commands",count:t.length},{key:"timeline",label:"Timeline",count:t.length},{key:"screenshots",label:"Screenshots",count:b},{key:"device",label:"Device logs",count:r.length},{key:"debug",label:"Debug logs",count:s.length},{key:"profiling",label:"System profiling",count:a.length,hideWhenEmpty:!0}],[t.length,b,r.length,s.length,a.length]),j=x.useMemo(()=>{let p=[];return n==="commands"?p=t:n==="device"?p=r:n==="debug"?p=s:n==="profiling"&&(p=a),Et(p,l)},[n,t,r,s,a,l]);return e.jsxs("section",{className:"rounded-lg border border-[var(--border)] bg-[var(--surface)] flex flex-col min-h-[280px] max-h-[640px]",children:[e.jsx(Bt,{tabs:f,active:n,onChange:o,errorsOnly:l,onErrorsOnlyChange:i,showErrorsOnly:ve.includes(n)}),e.jsxs("div",{ref:c,className:"flex-1 overflow-y-auto","data-log-scroller":"",children:[n==="timeline"&&e.jsx(Kt,{commands:m}),n==="screenshots"&&e.jsx(qt,{commands:m}),ve.includes(n)&&(j.length===0?e.jsx("div",{className:"px-4 py-10 text-center text-xs text-[var(--text-dim)]",children:l?"No error rows in this tab.":"No log entries in this tab."}):j.length>=Xt?e.jsx(Yt,{rows:j,scroller:c},n):j.map((p,g)=>e.jsx(Te,{log:p},p.id??g)))]})]})};function $e(t){if(!t)return"failed";switch(t){case"HTTPS_CLIENT_ERROR":case"HTTPS_SERVER_ERROR":case"OPEN_HTTPS_SERVER_ERROR":case"ON_CONNECT_ERROR":return"tls";case"PROXY_TO_SERVER_REQUEST_ERROR":return"net";default:return"failed"}}const ee="/xenon/api/interceptor";async function be(t){const r=await fetch(`${ee}/sessions/${encodeURIComponent(t)}/requests`);if(r.status===403)return{active:!1,forbidden:!0};if(r.status===404){const a=await r.json().catch(()=>({}));return{active:!1,error:a==null?void 0:a.error}}return r.ok?{active:!0,requests:(await r.json()).requests||[]}:{active:!1,error:`request failed (${r.status})`}}async function Zt(t,r){const s=await fetch(`${ee}/sessions/${encodeURIComponent(t)}/requests/${encodeURIComponent(r)}`);return s.ok?s.json():null}function er(t){return`${ee}/sessions/${encodeURIComponent(t)}/har`}function tr(t){return t>=200&&t<300?"ready":t>=300&&t<400?"neutral":t>=400&&t<500?"busy":t>=500?"error":"neutral"}const ge=({headers:t})=>{const r=Object.entries(t||{});return r.length===0?e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No headers"}):e.jsx("div",{className:"space-y-0.5 font-mono text-xs",children:r.map(([s,a])=>e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("span",{className:"text-[var(--text-dim)] shrink-0",children:[s,":"]}),e.jsx("span",{className:"break-all",children:a})]},s))})},je=({body:t})=>{if(t==null||t==="")return e.jsx("div",{className:"text-xs text-[var(--text-dim)]",children:"No body"});let r=t;try{r=JSON.stringify(JSON.parse(t),null,2)}catch{}return e.jsx("pre",{className:"font-mono text-xs whitespace-pre-wrap break-all bg-[var(--surface-2,var(--surface))] rounded p-2 max-h-64 overflow-auto",children:r})},rr=({request:t,onClose:r})=>{if(!t)return null;const s=e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx($,{tone:"accent",children:t.method}),t.failed?e.jsx($,{tone:"error",children:$e(t.failureKind)}):e.jsx($,{tone:tr(t.resStatus),children:t.resStatus||"—"}),e.jsx("span",{className:"font-mono text-xs truncate",title:t.url,children:t.url})]});return e.jsx(ct,{open:!!t,title:s,onClose:r,width:720,children:e.jsxs("div",{className:"space-y-4 text-xs",children:[t.failed&&e.jsxs("div",{className:"border border-[var(--red)] rounded p-2 bg-[rgb(var(--rgb-red-600)/0.08)]",children:[e.jsx("div",{className:"text-[var(--red)] text-[11px] mb-1",children:"Failure"}),e.jsx("div",{className:"text-xs",children:t.failureReason||"Request failed"}),t.failureKind&&e.jsx("div",{className:"font-mono text-[10px] text-[var(--text-dim)] mt-1",children:t.failureKind})]}),!t.failed&&e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Duration"}),e.jsxs("div",{className:"font-mono",children:[t.durationMs," ms"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Flags"}),e.jsxs("div",{className:"flex gap-1",children:[t.mocked&&e.jsx($,{tone:"accent",children:"mocked"}),t.modified&&e.jsx($,{tone:"busy",children:"modified"}),!t.mocked&&!t.modified&&e.jsx("span",{className:"text-[var(--text-dim)]",children:"passthrough"})]})]})]}),t.commandHint&&e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Triggered by"}),e.jsx("div",{className:"font-mono",children:t.commandHint.commandName})]}),!t.failed&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Headers"}),e.jsx(ge,{headers:t.reqHeaders})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Request Body"}),e.jsx(je,{body:t.reqBody})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Headers"}),e.jsx(ge,{headers:t.resHeaders})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[var(--text-dim)] text-[11px] mb-1",children:"Response Body"}),e.jsx(je,{body:t.resBody})]})]})]})})};function sr(t){return t?new Date(t).toLocaleTimeString(void 0,{hour12:!1}):"—"}function ar(t){return t>=200&&t<300?"ready":t>=300&&t<400?"neutral":t>=400&&t<500?"busy":t>=500?"error":"neutral"}const nr=({sessionId:t,sessionEnded:r})=>{const[s,a]=x.useState(null),[n,o]=x.useState(!1),[l,i]=x.useState(null),[c,m]=x.useState([]),[b,f]=x.useState(!0),[j,p]=x.useState(null),g=x.useRef(new Set),{on:y,isConnected:w}=De(),R=x.useCallback(d=>{o(!!d.forbidden),a(d.active),i(d.error||null);const N=d.requests||[];m(N),g.current=new Set(N.map(D=>D.id))},[]);x.useEffect(()=>{let d=!0;return f(!0),be(t).then(N=>{d&&R(N)}).catch(()=>{d&&R({active:!1,error:"the server could not be reached"})}).finally(()=>{d&&f(!1)}),()=>{d=!1}},[t,R]),x.useEffect(()=>{if(r)return;let d=!0;const N=y("interceptor_request",k=>{!k||k.sessionId!==t||g.current.has(k.id)||(g.current.add(k.id),m(J=>[k,...J]),a(!0))}),D=y("interceptor_session_started",k=>{(k==null?void 0:k.sessionId)===t&&a(!0)}),O=y("interceptor_session_stopped",k=>{(k==null?void 0:k.sessionId)===t&&be(t).then(J=>{d&&R(J)}).catch(()=>{})});return()=>{d=!1,N(),D(),O()}},[y,t,r,w,R]);const A=x.useMemo(()=>[...c].sort((d,N)=>N.ts-d.ts),[c]),_=async d=>{if(p(d),s){const N=await Zt(t,d.id);N&&p(N)}},u=s&&c.length>0?e.jsxs("a",{href:er(t),className:"inline-flex items-center gap-1 text-xs text-[var(--text-dim)] hover:text-[var(--text)]",title:"Download HAR",children:[e.jsx(_e,{className:"h-3 w-3"}),"HAR"]}):null,v=e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(dt,{className:"h-3.5 w-3.5 text-[var(--text-dim)]"}),e.jsx("span",{children:"Network"}),s&&c.length>0&&e.jsxs("span",{className:"text-xs text-[var(--text-dim)]",children:["(",c.length,")"]})]});let h;const C=s===!1&&(!l||l==="interceptor inactive");return b?h=e.jsx("div",{className:"p-4 text-xs text-[var(--text-dim)]",children:"Loading…"}):n?h=e.jsx(M,{title:"Only admins can see network requests",description:"Captured requests can carry sign-in details and personal data, so only admins can open them. Ask an admin to look at this session's requests."}):C&&r?h=e.jsx(M,{title:"No network capture",description:"This session didn't capture its network requests."}):C?h=e.jsx(M,{title:"Network capture is off",description:"This session isn't capturing its network requests. Android sessions capture them when the test turns network capture on in its capabilities, or when it is on for every session in the server settings."}):l?h=e.jsxs("div",{className:"p-4 text-xs text-[var(--red)]",children:["Failed to load requests: ",l]}):A.length===0?h=e.jsx(M,{title:"Waiting for requests",description:r?"No HTTP traffic was captured during this session.":"Captured requests will appear here as the device makes calls."}):h=e.jsx("div",{className:"overflow-auto max-h-96",children:e.jsxs(it,{children:[e.jsx(ot,{children:e.jsxs(oe,{children:[e.jsx(E,{style:{width:80},children:"Time"}),e.jsx(E,{style:{width:70},children:"Method"}),e.jsx(E,{style:{width:70},children:"Status"}),e.jsx(E,{children:"Host"}),e.jsx(E,{children:"Path"}),e.jsx(E,{style:{width:80},children:"Duration"}),e.jsx(E,{style:{width:90},children:"Flags"})]})}),e.jsx(lt,{children:A.map(d=>e.jsxs(oe,{onClick:()=>_(d),style:{cursor:"pointer"},title:d.failed?d.failureReason:void 0,children:[e.jsx(L,{className:"font-mono text-[11px]",children:sr(d.ts)}),e.jsx(L,{children:e.jsx($,{tone:"accent",children:d.method})}),e.jsx(L,{children:d.failed?e.jsx($,{tone:"error",children:$e(d.failureKind)}):e.jsx($,{tone:ar(d.resStatus),children:d.resStatus||"—"})}),e.jsx(L,{className:"font-mono text-[11px] truncate",title:d.host,children:d.host}),e.jsx(L,{className:"font-mono text-[11px] truncate",title:d.path,children:d.failed?"—":d.path}),e.jsx(L,{className:"font-mono text-[11px]",children:d.failed?"—":`${d.durationMs}ms`}),e.jsx(L,{children:e.jsxs("div",{className:"flex gap-1",children:[d.mocked&&e.jsx($,{tone:"accent",children:"mock"}),d.modified&&e.jsx($,{tone:"busy",children:"mod"})]})})]},d.id))})]})}),e.jsxs(e.Fragment,{children:[e.jsx(Se,{header:v,action:u,padded:!1,children:h}),e.jsx(rr,{request:j,onClose:()=>p(null)})]})},Tr=()=>{const{buildId:t="",sessionId:r=""}=Me(),{toast:s}=I(),a=Oe(),n=Ue(),o=mt(r||null),l=x.useMemo(()=>n.builds.find(f=>f.id===t)??null,[n.builds,t]),i=l?Ve(l):"Build";if(x.useEffect(()=>{!o.loading&&o.notFound&&(s("Session not available — it may belong to a team you are not on.","info"),a("/builds",{replace:!0}))},[o.loading,o.notFound,a,s]),o.loading)return e.jsx("div",{className:"p-6 text-xs text-[var(--text-dim)]",children:"Loading session…"});if(o.error||!o.session)return e.jsxs("div",{className:"p-6 space-y-2",children:[e.jsx(ce,{buildId:t,buildName:l?i:null,sessionId:r}),e.jsx("div",{className:"mt-6 rounded-md border border-[var(--red)]/30 bg-[var(--surface)] p-4 text-xs text-[var(--red)]",children:o.error||"Session not found."})]});const c=o.session,m=o.sessionLogs,b=Q(c.status).bucket==="failed";return e.jsxs("div",{className:"flex flex-col h-full min-h-0",children:[e.jsx(ce,{buildId:t,buildName:l?i:null,sessionId:c.id}),e.jsx(ht,{session:c}),e.jsx("div",{className:"flex-1 overflow-y-auto overflow-x-hidden",children:e.jsxs("div",{className:"px-4 py-4 space-y-4",children:[e.jsx(gt,{session:c,commands:m}),b&&e.jsx(wt,{session:c,buildName:i,buildId:t,commands:m,durationText:ze(X(c))}),e.jsx(Lt,{commands:m}),e.jsx(Ot,{sessionId:c.id,running:c.status==="running",hasTrace:!!c.performance_trace}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_340px] gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx(Qt,{sessionLogs:o.sessionLogs,deviceLogs:o.deviceLogs,debugLogs:o.debugLogs,profiling:o.profiling})}),e.jsxs("div",{className:"flex flex-col gap-4 min-w-0",children:[e.jsx(Pt,{session:c}),e.jsx(Ht,{session:c,buildName:l?i:null}),e.jsx(It,{session:c})]})]}),e.jsx(nr,{sessionId:c.id,sessionEnded:c.status!=="running"})]})})]})};export{Tr as SessionDetailPage,Tr as default};
@@ -0,0 +1,6 @@
1
+ import{c as X,t as G,r as h,p as O,X as g,j as e,A as W,C as E,V as K,e as U,W as Y,Y as J}from"./index-BOxe43p1.js";/* empty css */import{S as x,A as Q}from"./SettingCard-D8K1LZNo.js";import{M as Z}from"./Modal-Bsvj1tm2.js";import{B as j}from"./button-Cg08-EMT.js";import{P as ee}from"./page-header-COQZxJfR.js";import{C as w}from"./circle-check-CYXBoUqT.js";import{C as ae}from"./clock-C8_HViQP.js";import{M as se}from"./mouse-pointer-2-CtOrk4M8.js";import{C as te}from"./check-BMTaH72W.js";import{A as le}from"./activity-CJ8LwZq9.js";import{C as ne}from"./calendar-CA1ikLJs.js";import{A as re}from"./arrow-up-right-BOjwybDk.js";import"./index-CfxsUslp.js";import"./utils-CDN07tui.js";/**
2
+ * @license lucide-react v0.555.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const ie=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],ce=X("file-text",ie),he=t=>({healthCheckIntervalMs:t.healthCheckIntervalMs,healthCheckSchedule:"",enableSelfHealing:t.enableSelfHealing??!0}),S=5e3,oe=[{label:"Battery saver (2 AM)",value:"0 2 * * *"},{label:"Standard (hourly)",value:"0 * * * *"},{label:"Operational coverage (30m)",value:"*/30 * * * *"},{label:"High performance (10m)",value:"*/10 * * * *"}],C=5;function de(t){const a=Date.parse(t);if(!Number.isFinite(a))return"";const n=Math.max(0,Date.now()-a),l=Math.floor(n/1e3);if(l<60)return`${l}s ago`;const d=Math.floor(l/60);if(d<60)return`${d}m ago`;const i=Math.floor(d/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function z(t){var i,m;const a=(i=t.originalSelector)==null?void 0:i.trim(),n=(m=t.healedSelector)==null?void 0:m.trim(),l=t.tier&&t.commandName?`${t.commandName}: `:"";if(a&&n&&a!==n)return`${l}${a} → ${n}`;if(n)return`${l}Recovered locator ${n}`;if(a)return`${l}Recovered locator ${a}`;const d=typeof t.confidence=="number"?` (${Math.round(t.confidence*100)}%)`:"";return`${l||""}Self-healed${d}`}function ue(t){return t.tier?t.tier:t.commandName?t.commandName:t.deviceName?t.deviceName:"Self-heal"}const me=(t,a)=>t.healthCheckIntervalMs===a.healthCheckIntervalMs&&t.healthCheckSchedule===a.healthCheckSchedule&&t.enableSelfHealing===a.enableSelfHealing,fe=(t,a)=>{const n={};return t.healthCheckIntervalMs!==a.healthCheckIntervalMs&&(n.healthCheckIntervalMs=t.healthCheckIntervalMs),t.healthCheckSchedule!==a.healthCheckSchedule&&(n.healthCheckSchedule=t.healthCheckSchedule),t.enableSelfHealing!==a.enableSelfHealing&&(n.enableSelfHealing=t.enableSelfHealing),n},Ae=()=>{const{toast:t}=G(),[a,n]=h.useState(null),[l,d]=h.useState(null),[i,m]=h.useState(null),[$,N]=h.useState(!0),[R,y]=h.useState(!1),[k,b]=h.useState(!1),[L,f]=h.useState(!1),[M,I]=h.useState([]),[D,F]=h.useState(!1),{on:_}=O();h.useEffect(()=>{H()},[]),h.useEffect(()=>{let s=!1;return g.getRecentHealingEvents(C).then(r=>{if(s||!r)return;const c=Array.isArray(r.events)?r.events.slice(0,C):[];I(c)}).catch(()=>{}).finally(()=>{s||F(!0)}),()=>{s=!0}},[]),h.useEffect(()=>{const s=_("healing_event",r=>{const c=r;!c||!c.id||I(u=>u.some(P=>P.id===c.id)?u:[c,...u].slice(0,C))});return()=>{s&&s()}},[_]);const H=async()=>{N(!0),y(!1);try{const s=await g.getGlobalConfig();if(!s||!s.defaults)throw new Error((s==null?void 0:s.message)||"No settings in the answer");const r=he(s.defaults),c={healthCheckIntervalMs:s.healthCheckIntervalMs??r.healthCheckIntervalMs,healthCheckSchedule:s.healthCheckSchedule||"",enableSelfHealing:s.enableSelfHealing??r.enableSelfHealing};m(r),n(c),d(c)}catch(s){console.error("Failed to load settings",s),y(!0),t("Failed to access infrastructure parameters.","error")}finally{N(!1)}},v=a!==null&&l!==null&&!me(a,l),o=a!==null&&(Number.isNaN(a.healthCheckIntervalMs)||a.healthCheckIntervalMs<S)?`Below minimum safe value of ${S}ms.`:null,T=v&&!o,p={interval:(a==null?void 0:a.healthCheckIntervalMs)!==(l==null?void 0:l.healthCheckIntervalMs),schedule:(a==null?void 0:a.healthCheckSchedule)!==(l==null?void 0:l.healthCheckSchedule),healing:(a==null?void 0:a.enableSelfHealing)!==(l==null?void 0:l.enableSelfHealing)},A=async s=>{if(!a||!l)return;if(!s&&o){t(o,"error");return}const r=s??fe(a,l),c=s??a;b(!0);try{await g.updateGlobalConfig(r),d(c),n(c),t("Infrastructure parameters synchronized across fleet.","success")}catch(u){console.error("Failed to save settings",u),J(t,u)}finally{b(!1)}},q=async()=>{if(i){n(i),await A(i);try{await g.resetMetrics()}catch(s){console.error("Failed to reset metrics",s)}}},B=()=>{n(l)};if($)return e.jsxs("div",{className:"settings-loading",children:[e.jsx(W,{className:"animate-spin",size:32}),e.jsx("span",{children:"Synchronizing Global Infrastructure..."})]});if(R||!a||!i)return e.jsxs("div",{className:"settings-loading",role:"alert",children:[e.jsx(E,{size:32}),e.jsx("span",{children:"Couldn't load the settings from the server."}),e.jsx(j,{variant:"secondary",onClick:()=>H(),children:"Try again"})]});const V=a.healthCheckSchedule!=="";return e.jsxs("div",{className:"settings-container",children:[e.jsx(ee,{icon:K,title:"Settings",subtitle:"Manage core farm parameters, heartbeat frequency, and maintenance orchestrations across the global registry."}),e.jsx("div",{className:"settings-content",children:e.jsxs("div",{className:"settings-grid settings-grid--three",children:[e.jsxs(x,{icon:e.jsx(ae,{size:16}),title:e.jsxs("span",{className:"card-title-row",children:["Idle health frequency",p.interval&&e.jsx("span",{className:"modified-dot","aria-label":"Modified"})]}),description:"Frequency of passive health pings when the system is in idle state.",hint:"Minimum safe value: 5000ms. Note: This frequency is overridden when a schedule is active.",children:[e.jsx("div",{className:"card-spacer"}),e.jsxs("div",{className:`input-group ${o?"has-error":""}`,children:[e.jsx("input",{type:"number",value:a.healthCheckIntervalMs,onChange:s=>n({...a,healthCheckIntervalMs:parseInt(s.target.value,10)}),min:S,step:5e3,"aria-invalid":!!o,"aria-describedby":o?"interval-error":"interval-status"}),e.jsx("span",{className:"code-font",children:"MS"})]}),o?e.jsxs("div",{id:"interval-error",className:"input-status input-status--error",role:"alert",children:[e.jsx(E,{size:12}),e.jsx("span",{children:o})]}):e.jsxs("div",{id:"interval-status",className:"input-status input-status--ok",children:[e.jsx(w,{size:12}),e.jsx("span",{children:"Valid frequency"})]})]}),e.jsxs(x,{icon:e.jsx(ne,{size:16}),title:e.jsxs("span",{className:"card-title-row",children:["Deep diagnostic schedule",p.schedule&&e.jsx("span",{className:"modified-dot","aria-label":"Modified"})]}),titleExtra:V?e.jsxs("span",{className:"active-pill",children:[e.jsx(le,{size:11}),e.jsx("span",{children:"Active"})]}):null,description:"Execute intensive reliability bursts (WDA restarts, Cache purges) using standardized Cron syntax.",children:[e.jsx("div",{className:"setting-input-wrapper",children:e.jsx("input",{type:"text",placeholder:"e.g. 0 * * * * (hourly, at minute 0)",value:a.healthCheckSchedule,onChange:s=>n({...a,healthCheckSchedule:s.target.value})})}),e.jsxs("div",{className:"cron-presets",children:[e.jsxs("div",{className:"presets-label",children:[e.jsx(se,{size:12}),e.jsx("span",{children:"Intent-based presets"})]}),e.jsx("div",{className:"presets-grid presets-grid--stacked",children:oe.map(s=>{const r=a.healthCheckSchedule===s.value;return e.jsxs("button",{type:"button",className:`preset-chip ${r?"active":""}`,onClick:()=>n({...a,healthCheckSchedule:s.value}),"aria-pressed":r,children:[r&&e.jsx(te,{size:11,className:"preset-chip__check"}),e.jsx("span",{children:s.label})]},s.label)})})]})]}),e.jsxs(x,{icon:e.jsx(Y,{size:16}),title:e.jsxs("span",{className:"card-title-row",children:["AI self-healing",p.healing&&e.jsx("span",{className:"modified-dot","aria-label":"Modified"})]}),titleExtra:e.jsxs("label",{className:"switch switch--header",children:[e.jsx("input",{type:"checkbox",checked:a.enableSelfHealing,onChange:s=>n({...a,enableSelfHealing:s.target.checked}),"aria-label":"Toggle AI self-healing"}),e.jsx("span",{className:"slider round"})]}),children:[e.jsx("div",{className:`healing-state ${a.enableSelfHealing?"is-on":"is-off"}`,children:a.enableSelfHealing?"Enabled":"Disabled"}),e.jsx("p",{className:"setting-card-description",children:"Automatically intercept and recover from failing locators using Xenon's 6-tier strategy: etalon recovery, native retry, fuzzy XML, OCR, visual AI, and LLM — before failing a test."}),a.enableSelfHealing&&e.jsxs("div",{className:"healing-events",children:[e.jsxs("div",{className:"healing-events__header",children:[e.jsx(ce,{size:11}),e.jsx("span",{children:"Recent healing events"}),e.jsxs(U,{to:"/selector-health",className:"healing-events__link",children:["Selector health ",e.jsx(re,{size:10})]})]}),M.length>0?e.jsx("ul",{className:"healing-events__list",children:M.map(s=>e.jsxs("li",{className:"healing-event",children:[e.jsx(w,{size:14,className:"healing-event__icon"}),e.jsxs("div",{className:"healing-event__body",children:[e.jsxs("div",{className:"healing-event__row",children:[e.jsx("span",{className:"healing-event__kind",children:ue(s)}),e.jsx("span",{className:"healing-event__when",children:de(s.createdAt)})]}),e.jsx("div",{className:"healing-event__message",title:z(s),children:z(s)})]})]},s.id))}):e.jsx("div",{className:"healing-events__empty",children:D?"No healing events recorded yet — the dashboard will populate as locators are recovered.":"Loading recent events…"})]})]})]})}),(v||k)&&e.jsx(Q,{onSave:()=>A(),onDiscard:B,onRestoreDefaults:()=>f(!0),isSaving:k,isValidating:!!o,isDirty:v,saveLabel:T?"Save Configuration":"Resolve errors to save"}),e.jsxs(Z,{open:L,onClose:()=>f(!1),title:"Restore default settings?",footer:e.jsxs(e.Fragment,{children:[e.jsx(j,{variant:"secondary",onClick:()=>f(!1),children:"Cancel"}),e.jsx(j,{variant:"danger",onClick:async()=>{f(!1),await q()},children:"Restore defaults"})]}),children:[e.jsx("p",{className:"text-sm text-[var(--text-muted)]",children:"This saves immediately and can't be undone:"}),e.jsxs("ul",{className:"mt-2 list-disc pl-5 text-sm text-[var(--text)] space-y-1",children:[e.jsxs("li",{children:["Idle health frequency goes back to ",i.healthCheckIntervalMs.toLocaleString()," ms"]}),e.jsx("li",{children:"The diagnostic schedule is cleared"}),e.jsx("li",{children:"AI self-healing is turned on"}),e.jsx("li",{children:"Every device's healed-selector count is reset to zero"})]})]})]})};export{Ae as Settings};
@@ -1 +1 @@
1
- .settings-container{padding:24px 32px;max-width:1440px;margin:0 auto;color:var(--text);animation:fadeIn .3s ease;min-height:calc(100vh - 40px);display:flex;flex-direction:column;font-family:Inter,-apple-system,sans-serif;position:relative;background:var(--bg);width:100%}.settings-container>header{padding-left:0;padding-right:0}.settings-header{margin-bottom:24px;padding-bottom:20px;border-bottom:1px solid var(--border)}.settings-header h2{margin:0;font-size:1.75rem;font-weight:700;font-family:Outfit,sans-serif;color:var(--text)}.settings-title-group{display:flex;align-items:center;gap:12px}.settings-title-group .settings-icon{color:var(--text-muted);flex-shrink:0}.settings-subtitle{color:var(--text-muted);font-size:.85rem;margin-top:6px;line-height:1.5}.settings-subtitle span{font-family:JetBrains Mono,monospace;font-size:.75rem;color:var(--text-dim)}.badge-elite{font-size:11px;padding:3px 8px;border-radius:4px;background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);border:1px solid rgb(var(--rgb-accent) / .25);font-weight:500}.status-pill{display:inline-flex;align-items:center;gap:8px;padding:4px 12px;border-radius:6px;font-size:11px;font-weight:800;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border:1px solid var(--border)}.status-pill.success{border-color:rgb(var(--rgb-success) / .3);color:var(--color-success)}.status-pill.error{border-color:#ff44444d;color:var(--status-error-fg)}.locked-indicator{display:flex;align-items:center;gap:8px;font-size:.75rem;color:var(--text-dim);font-family:JetBrains Mono,monospace;margin-top:var(--space-4)}.locked-indicator code{background:rgb(var(--rgb-fg) / .05);color:var(--text-muted);padding:2px 6px;border-radius:4px}.settings-content{display:flex;flex-direction:column;gap:var(--space-8);flex-grow:1}.settings-section h3{display:flex;align-items:center;gap:var(--space-2);font-size:1.125rem;color:var(--text);font-weight:700;margin-bottom:var(--space-2)}.settings-content{display:flex;flex-direction:column;gap:var(--space-8);flex-grow:1;position:relative}.settings-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--space-6);margin-bottom:var(--space-6)}.settings-grid>*{grid-column:span 12}@media (min-width: 1024px){.settings-grid{grid-template-columns:repeat(3,1fr)}.settings-grid>*{grid-column:span 1}}.settings-grid--three{display:grid;grid-template-columns:1fr;gap:var(--space-5);margin-bottom:var(--space-6);align-items:stretch}.settings-grid--three>*{grid-column:auto}@media (min-width: 1024px){.settings-grid--three{grid-template-columns:repeat(3,minmax(0,1fr))}}.settings-grid--two-equal{display:grid;grid-template-columns:1fr;gap:var(--space-5);margin-bottom:var(--space-6);align-items:stretch}.settings-grid--two-equal>*{grid-column:auto}@media (min-width: 1024px){.settings-grid--two-equal{grid-template-columns:repeat(2,minmax(0,1fr))}}.card-spacer{flex-grow:1;min-height:24px}.section-description{color:var(--text-muted);font-size:.875rem;margin-bottom:var(--space-6);max-width:640px;line-height:1.6}.input-group{display:flex;align-items:center;gap:8px;background:var(--bg);border-radius:6px;padding:0 12px;height:42px;border:1px solid var(--border);transition:all .2s ease;position:relative}.input-group:hover{border-color:var(--border-strong)}.mesh-gradient-infra .input-group:focus-within,.mesh-gradient-ai .input-group:focus-within{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .03);box-shadow:0 0 0 1px var(--color-accent)}.input-group input,.input-group select{background:transparent;border:none;color:var(--text);font-size:.95rem;width:100%;height:100%;outline:none;font-family:JetBrains Mono,monospace;font-weight:500}.input-group input::placeholder{color:var(--text-dim);opacity:.5}.input-group select{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 0 center;padding-right:2rem}.input-group .code-font{color:var(--text-dim);font-size:.7rem;font-weight:500;letter-spacing:1px;font-family:JetBrains Mono,monospace}.health-monitor-alert{display:flex;align-items:center;gap:12px;background:rgb(var(--rgb-amber-alt) / .06);border:1px solid rgb(var(--rgb-amber-alt) / .2);padding:12px 16px;border-radius:6px;color:var(--status-busy-fg);font-size:11px;font-weight:500}.status-banner{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:6px;font-size:11px;animation:slideIn .3s ease;margin-top:16px;font-weight:500}@keyframes slideIn{0%{opacity:0;transform:translate(-20px)}to{opacity:1;transform:translate(0)}}.status-banner.success{background:rgb(var(--rgb-success) / .06);border:1px solid rgb(var(--rgb-success) / .25);color:var(--color-success)}.status-banner.error{background:#ff44440f;border:1px solid rgba(255,68,68,.25);color:var(--status-error-fg)}.cron-presets{margin-top:24px;padding-top:16px;border-top:1px solid var(--border)}.presets-label{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:500;color:var(--text-dim);margin-bottom:10px}.preset-chip{padding:5px 12px;margin:2px;background:var(--bg);border:1px solid var(--border);color:var(--text-muted);font-size:11px;font-weight:500;border-radius:4px;cursor:pointer;transition:all .2s ease;white-space:nowrap}.preset-chip:hover{background:var(--surface-2);color:var(--text);border-color:var(--border-strong)}.preset-chip.active{background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .3)}.settings-footer{position:sticky;bottom:0;background:var(--surface);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border-top:1px solid var(--border-strong);padding:16px 32px;display:flex;justify-content:space-between;align-items:center;margin-top:auto;z-index:1000}.footer-left{display:flex;align-items:center;gap:16px}.footer-right{display:flex;gap:16px}.footer-dirty{display:inline-flex;align-items:center;gap:8px;color:var(--amber);font-family:Inter,sans-serif;font-size:13px;font-weight:500}.footer-dirty__dot{width:8px;height:8px;border-radius:50%;background:var(--amber);box-shadow:none;animation:dirty-pulse 2s ease-in-out infinite}@keyframes dirty-pulse{0%,to{opacity:1}50%{opacity:.55}}.footer-divider{width:1px;height:18px;background:var(--border-strong)}.save-btn{background:var(--color-accent);color:var(--bg);padding:10px 24px;border-radius:6px;font-weight:600;font-size:11px;border:none;transition:all .2s;display:flex;align-items:center;gap:6px}.save-btn:hover:not(:disabled){background:var(--color-accent-strong);transform:translateY(-1px);box-shadow:none}.save-btn:active:not(:disabled){transform:translateY(0)}.reset-btn{background:transparent;border:1px solid var(--border);color:var(--text-muted);padding:9px 20px;border-radius:6px;font-weight:500;font-size:11px;transition:all .2s}.reset-btn:hover:not(:disabled){background:var(--surface-2);color:var(--text);border-color:var(--border-strong)}.reset-to-defaults-btn{background:transparent;border:1px solid rgba(255,68,68,.2);color:#f44;padding:9px 20px;border-radius:6px;font-size:11px;font-weight:500;display:flex;align-items:center;gap:6px;transition:all .2s}.reset-to-defaults-btn:hover:not(:disabled){background:rgb(var(--rgb-red-alt) / .05);border-color:var(--red-alt)}.save-btn:disabled,.reset-btn:disabled,.reset-to-defaults-btn:disabled{opacity:.5;cursor:not-allowed;box-shadow:none;filter:grayscale(.2)}.setting-field{display:flex;flex-direction:column;gap:var(--space-2);width:100%}.setting-input-wrapper{display:flex;align-items:center;gap:var(--space-4);background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:8px 12px;transition:border-color .15s,box-shadow .15s}.setting-input-wrapper:focus-within{border-color:var(--color-accent);box-shadow:0 0 0 2px #3fb95066}.setting-input-wrapper input,.setting-input-wrapper select{background:transparent;border:none;color:var(--text);font-size:.875rem;width:100%;outline:none}.settings-loading{height:400px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-4);color:var(--text-muted)}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 640px){.settings-container{padding:var(--space-6)}.settings-footer{flex-direction:column;gap:var(--space-3);padding:var(--space-6)}.footer-left,.footer-right{width:100%;display:flex;flex-direction:column;gap:var(--space-2)}.reset-btn,.save-btn,.reset-to-defaults-btn{width:100%;justify-content:center;white-space:nowrap}}.save-btn,.reset-btn,.reset-to-defaults-btn{white-space:nowrap}.glow-error{box-shadow:none;border-color:rgb(var(--rgb-red) / .4)!important;animation:pulse-error 2s infinite}@keyframes pulse-error{0%{box-shadow:none}50%{box-shadow:none}to{box-shadow:none}}.critical-alert-card{background:#7f1d1d4d;border:2px solid var(--status-error-fg);border-radius:var(--radius-lg);overflow:hidden;margin-top:var(--space-8);box-shadow:none;animation:shake-entry .4s ease-out}@keyframes shake-entry{0%{transform:translate(0)}25%{transform:translate(-5px)}50%{transform:translate(5px)}75%{transform:translate(-5px)}to{transform:translate(0)}}.critical-header{background:var(--status-error-fg);color:var(--text);padding:16px 24px;display:flex;align-items:center;gap:12px;font-weight:700;font-size:1.1rem;letter-spacing:.02em}.setting-input-wrapper select{background:transparent;color:var(--text);font-family:Inter,sans-serif;font-weight:500;cursor:pointer;padding-right:32px;-moz-appearance:none;appearance:none;-webkit-appearance:none;color-scheme:dark}.setting-input-wrapper{position:relative}.setting-input-wrapper:after{content:"";position:absolute;right:12px;top:50%;transform:translateY(-50%);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid var(--text-dim);pointer-events:none}.setting-input-wrapper:hover:after{border-top-color:var(--color-accent)}.setting-input-wrapper select option{background-color:var(--surface);color:var(--text);padding:12px}.critical-body{padding:24px;color:#fca5a5}.critical-body p{margin:0 0 16px;line-height:1.6;font-size:.95rem}.terminal-block-critical{background:var(--bg);border:1px solid rgba(127,29,29,.6);border-radius:8px;padding:16px;font-family:JetBrains Mono,monospace;font-size:.85rem;color:var(--white);display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:16px}.terminal-block-critical code{color:#a5f3fc;font-weight:600}.copy-btn-critical{background:rgb(var(--rgb-fg) / .1);border:1px solid rgb(var(--rgb-fg) / .2);color:var(--white);width:32px;height:32px;border-radius:6px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.copy-btn-critical:hover{background:rgb(var(--rgb-fg) / .2);transform:scale(1.05)}.setting-input-wrapper:focus-within{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .03);box-shadow:0 0 0 1px var(--color-accent),inset 0 0 0 1px rgb(var(--rgb-accent) / .1);transform:translateY(-1px)}.live-signal{width:6px;height:6px;background-color:var(--color-success);border-radius:50%;margin-right:6px;position:relative}.live-signal:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:var(--color-success);animation:ping-signal 1.5s cubic-bezier(0,0,.2,1) infinite}@keyframes ping-signal{75%,to{transform:scale(2.5);opacity:0}}.input-container{background:rgb(var(--rgb-fg) / .05);border:1px solid rgb(var(--rgb-fg) / .1);height:42px}.status-pill{height:42px;background:rgb(var(--rgb-fg) / .05);border:1px solid rgb(var(--rgb-fg) / .1)}.card-header-dense{border-bottom:1px solid rgb(var(--rgb-fg) / .05);padding-bottom:16px;margin-bottom:24px}.form-field{display:flex;flex-direction:column;gap:10px}.field-label{font-size:.75rem;font-weight:700;color:var(--text-muted);padding-left:2px}.status-badge{display:flex;align-items:center;gap:8px;padding:0 16px;border-radius:6px;font-size:.8rem;font-weight:600;font-family:JetBrains Mono,monospace;height:42px;width:100%;transition:all .2s}.status-badge.success-filled{background:rgb(var(--rgb-success) / .15);color:var(--color-success-soft);border:1px solid rgb(var(--rgb-success) / .2)}.status-badge.error-filled{background:rgb(var(--rgb-red) / .15);color:var(--red-400);border:1px solid rgb(var(--rgb-red) / .2)}.ghost-btn{background:transparent;border:1px solid rgb(var(--rgb-fg) / .1);color:var(--text-muted);padding:0 20px;height:40px;border-radius:6px;font-weight:600;font-size:.85rem;transition:all .2s;display:flex;align-items:center;gap:8px}.ghost-btn:hover{background:rgb(var(--rgb-fg) / .05);color:var(--text);border-color:rgb(var(--rgb-fg) / .2)}.save-btn.primary{height:40px;box-shadow:none}.ai-provider-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--space-4)}.ai-provider-card{display:flex;flex-direction:column;gap:12px;padding:16px 20px;border-radius:8px;border:1px solid rgb(var(--rgb-fg) / .08);background:rgb(var(--rgb-fg) / .03);cursor:pointer;transition:all .2s ease;text-align:left;color:var(--text)}.ai-provider-card:hover:not(.disabled){border-color:rgb(var(--rgb-fg) / .2);background:rgb(var(--rgb-fg) / .06)}.ai-provider-card.active{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);box-shadow:0 0 0 1px var(--color-accent)}.ai-provider-card.disabled{opacity:.4;cursor:not-allowed;filter:grayscale(.5)}.ai-provider-card-header{display:flex;align-items:center;gap:12px}.ai-provider-icon{width:36px;height:36px;border-radius:8px;background:rgb(var(--rgb-fg) / .06);display:flex;align-items:center;justify-content:center;color:var(--text-muted);flex-shrink:0}.ai-provider-card.active .ai-provider-icon{background:rgb(var(--rgb-accent) / .15);color:var(--color-accent)}.ai-provider-info{display:flex;flex-direction:column;gap:2px;min-width:0}.ai-provider-name{font-weight:700;font-size:.95rem;color:var(--text)}.ai-provider-desc{font-size:.75rem;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ai-provider-status{display:flex;align-items:center}.ai-config-display{display:flex;flex-direction:column;gap:1px;background:rgb(var(--rgb-fg) / .04);border-radius:8px;overflow:hidden;border:1px solid rgb(var(--rgb-fg) / .06)}.ai-config-row{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#02061780}.ai-config-row+.ai-config-row{border-top:1px solid rgb(var(--rgb-fg) / .04)}.ai-config-label{font-size:.8rem;font-weight:600;color:var(--text-muted)}.ai-config-value{font-size:.9rem;font-weight:500;color:var(--text);display:flex;align-items:center;gap:8px}.ai-config-value.mono{font-family:JetBrains Mono,monospace;font-size:.85rem;color:var(--text)}.ai-config-default{font-size:11px;background:rgb(var(--rgb-fg) / .06);color:var(--text-dim);padding:2px 6px;border-radius:4px}.toggle-group{display:flex;align-items:center;gap:12px}.switch{position:relative;display:inline-block;width:38px;height:22px;flex-shrink:0}.switch input{opacity:0;width:0;height:0}.slider{position:absolute;top:0;right:0;bottom:0;left:0;background:rgb(var(--rgb-fg) / .08);border:1px solid var(--border);transition:all .2s ease;cursor:pointer;border-radius:999px}.slider:before{content:"";position:absolute;width:16px;height:16px;left:2px;top:50%;transform:translateY(-50%);background:var(--text-muted);border-radius:50%;transition:all .2s ease}.switch input:checked+.slider{background:rgb(var(--rgb-accent) / .15);border-color:var(--color-accent);box-shadow:none}.switch input:checked+.slider:before{left:calc(100% - 18px);background:var(--color-accent)}.switch input:focus-visible+.slider{outline:2px solid var(--color-accent);outline-offset:2px}.toggle-label{font-size:11px;font-weight:700;color:var(--text-muted)}.cron-preview{margin-top:12px;padding:10px 12px;background:rgb(var(--rgb-well) / calc(.25 * var(--well-k)));border:1px solid var(--border);border-radius:6px;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px}.cron-preview .preview-label{font-size:11px;font-weight:700;color:var(--text-dim)}.cron-preview .preview-value{font-size:13px;color:var(--text);font-weight:500}.cron-presets{margin-top:12px}.presets-label{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--text-dim);margin-bottom:8px}.presets-grid{display:flex;flex-wrap:wrap;gap:8px}.preset-chip{padding:6px 12px;border-radius:6px;border:1px solid var(--border);background:rgb(var(--rgb-fg) / .03);color:var(--text-muted);font-size:11px;font-weight:600;cursor:pointer;transition:all .2s ease}.preset-chip:hover{border-color:var(--border);color:var(--text)}.preset-chip.active{background:rgb(var(--rgb-accent) / .18);border-color:var(--color-accent);color:var(--color-accent);box-shadow:inset 0 0 0 1px rgb(var(--rgb-accent) / .35)}.preset-chip__check{color:var(--color-accent)}.active-pill{display:inline-flex;align-items:center;gap:5px;margin-left:auto;padding:4px 10px;border-radius:999px;font-family:Inter,sans-serif;font-size:11px;font-weight:600;color:var(--color-accent);background:rgb(var(--rgb-accent) / .1);border:1px solid rgb(var(--rgb-accent) / .3);letter-spacing:.01em}.card-title-row{display:inline-flex;align-items:center;gap:6px}.modified-dot{width:6px;height:6px;border-radius:50%;background:var(--amber);box-shadow:none;display:inline-block}.input-group.has-error{border-color:rgb(var(--rgb-red) / .55);background:rgb(var(--rgb-red) / .04)}.input-group.has-error:focus-within{border-color:var(--red);box-shadow:0 0 0 1px var(--red);background:rgb(var(--rgb-red) / .06)}.input-status{display:flex;align-items:center;gap:6px;margin-top:4px;font-family:Inter,sans-serif;font-size:12px;font-weight:500;letter-spacing:.01em}.input-status--ok{color:var(--color-success)}.input-status--error{color:var(--status-error-fg)}.presets-grid--stacked{display:flex;flex-direction:column;gap:8px;align-items:stretch}.presets-grid--stacked .preset-chip{justify-content:flex-start;width:100%}.switch--header{margin-left:auto}.healing-state{font-size:11px;font-weight:700;margin-top:-4px}.healing-state.is-on{color:var(--color-accent)}.healing-state.is-off{color:var(--text-dim)}.healing-events{margin-top:auto;padding:12px;border-radius:var(--radius-md);background:rgb(var(--rgb-fg) / .025);border:1px solid var(--border);display:flex;flex-direction:column;gap:10px}.healing-events__link{margin-left:auto;display:inline-flex;align-items:center;gap:3px;text-decoration:none;color:var(--color-accent);font-family:JetBrains Mono,monospace;font-size:9.5px;font-weight:600;letter-spacing:.06em;padding:2px 6px;border-radius:4px;border:1px solid rgb(var(--rgb-accent) / .25);background:rgb(var(--rgb-accent) / .06);transition:all .15s ease;text-transform:none}.healing-events__link:hover{background:rgb(var(--rgb-accent) / .12);border-color:rgb(var(--rgb-accent) / .4)}.healing-events__header{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:700;color:var(--text-dim)}.healing-events__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}.healing-events__empty{font-size:11.5px;color:var(--text-dim);line-height:1.45;padding:6px 2px}.healing-event{display:flex;gap:10px;align-items:flex-start}.healing-event__icon{color:var(--color-accent);flex-shrink:0;margin-top:1px}.healing-event__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.healing-event__row{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.healing-event__kind{font-size:12px;font-weight:700;color:var(--text)}.healing-event__when{font-family:JetBrains Mono,monospace;font-size:10px;color:var(--text-dim);white-space:nowrap}.healing-event__message{font-size:11.5px;color:var(--text-muted);line-height:1.4}.settings-footer{animation:dirty-slide-up .2s cubic-bezier(.2,0,0,1)}@keyframes dirty-slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.page-header-subnote{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-dim);margin-left:8px}.provider-count-pill{display:inline-flex;align-items:center;margin-left:auto;padding:4px 10px;border-radius:6px;font-size:11px;font-weight:700}.provider-count-pill.is-ok{background:rgb(var(--rgb-success) / .1);color:var(--color-success);border:1px solid rgb(var(--rgb-success) / .3)}.provider-count-pill.is-empty{background:#8a938f14;color:var(--text-muted);border:1px solid var(--border-strong)}.provider-list{display:flex;flex-direction:column;gap:10px}.provider-row{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:var(--radius-md);border:1px solid var(--border);background:rgb(var(--rgb-fg) / .02);color:var(--text);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,box-shadow .15s;width:100%}.provider-row:hover:not(:disabled):not(.is-active){border-color:var(--border-strong);background:rgb(var(--rgb-fg) / .04)}.provider-row.is-active{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);box-shadow:inset 0 0 0 1px rgb(var(--rgb-accent) / .4)}.provider-row.is-disabled{cursor:not-allowed;opacity:.55}.provider-row__icon{width:36px;height:36px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;background:rgb(var(--rgb-fg) / .05);color:var(--text-muted);flex-shrink:0;font-family:Outfit,sans-serif;font-weight:700;font-size:16px}.provider-row.is-active .provider-row__icon{background:rgb(var(--rgb-accent) / .18);color:var(--color-accent)}.ai-provider-glyph{font-family:Outfit,sans-serif;font-weight:700;font-size:18px;line-height:1}.provider-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.provider-row__name{font-weight:700;font-size:14px;color:var(--text)}.provider-row__desc{font-size:12px;color:var(--text-muted);line-height:1.4}.provider-row__status{margin-top:6px}.provider-status{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:4px;font-size:11px;font-weight:700;border:1px solid transparent}.provider-status--active{color:var(--color-accent);background:rgb(var(--rgb-accent) / .12);border-color:rgb(var(--rgb-accent) / .35)}.provider-status--off{color:var(--text-dim);background:rgb(var(--rgb-fg) / .04);border-color:var(--border-strong)}.provider-status--ready{color:var(--text-muted);background:rgb(var(--rgb-fg) / .04);border-color:var(--border)}.model-params{display:flex;flex-direction:column;gap:14px;margin-top:8px;padding:14px;border-radius:var(--radius-md);background:rgb(var(--rgb-fg) / .025);border:1px solid var(--border)}.model-params__header{display:flex;align-items:center;gap:8px;color:var(--text);font-family:Outfit,sans-serif;font-size:13px;font-weight:700;letter-spacing:.01em}.model-param{display:flex;flex-direction:column;gap:6px}.model-param__label-row{display:flex;justify-content:space-between;align-items:baseline}.model-param__label-row label{font-size:11px;font-weight:700;color:var(--text-dim)}.model-param__value{font-family:JetBrains Mono,monospace;font-size:13px;font-weight:700;color:var(--text)}.model-param__slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:4px;background:rgb(var(--rgb-fg) / .08);border-radius:999px;outline:none;cursor:pointer}.model-param__slider::-webkit-slider-runnable-track{height:4px;background:linear-gradient(to right,var(--color-accent) 0%,var(--color-accent) var(--slider-pct, 50%),rgb(var(--rgb-fg) / .08) var(--slider-pct, 50%),rgb(var(--rgb-fg) / .08) 100%);border-radius:999px}.model-param__slider::-moz-range-track{height:4px;background:rgb(var(--rgb-fg) / .08);border-radius:999px}.model-param__slider::-moz-range-progress{height:4px;background:var(--color-accent);border-radius:999px}.model-param__slider::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:14px;height:14px;border-radius:50%;background:var(--color-accent);cursor:pointer;margin-top:-5px;box-shadow:none;border:2px solid var(--bg)}.model-param__slider::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--color-accent);cursor:pointer;box-shadow:none;border:2px solid var(--bg)}.test-connection-btn{margin-top:auto;display:flex;align-items:center;justify-content:center;gap:8px;padding:12px 16px;border-radius:var(--radius-md);background:rgb(var(--rgb-fg) / .04);border:1px solid var(--border-strong);color:var(--text);font-family:Inter,sans-serif;font-size:13px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s;width:100%}.test-connection-btn:hover:not(:disabled){background:rgb(var(--rgb-accent) / .06);border-color:rgb(var(--rgb-accent) / .4);color:var(--color-accent)}.test-connection-btn:disabled{opacity:.5;cursor:not-allowed}.ai-config-row .ai-config-default{margin-left:auto}.maintenance-notice{background:rgb(var(--rgb-blue) / .05)!important;border-color:rgb(var(--rgb-blue) / .25)!important;color:var(--blue)!important;text-transform:none!important;letter-spacing:normal!important}.stat-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--space-4);margin-bottom:var(--space-5)}.stat-strip__cell{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:16px 20px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:4px}.stat-strip__value{font-family:Outfit,sans-serif;font-size:28px;font-weight:700;line-height:1.1;color:var(--text);letter-spacing:-.02em}.stat-strip__value--accent{color:var(--color-accent)}.stat-strip__label{font-size:11px;font-weight:600;color:var(--text-dim)}.data-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);overflow:hidden}.data-card .table-row:hover{background:rgb(var(--rgb-fg) / .03)}.pill-chip{display:inline-flex;align-items:center;padding:3px 9px;border-radius:999px;font-family:JetBrains Mono,monospace;font-size:10.5px;font-weight:600;letter-spacing:.04em;border:1px solid transparent;line-height:1.4}.pill-chip--shared{background:rgb(var(--rgb-fg) / .04);color:var(--text-muted);border-color:var(--border-strong)}.pill-chip--team{background:rgb(var(--rgb-accent) / .1);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .3)}.pill-chip--scope{background:rgb(var(--rgb-blue) / .1);color:var(--blue);border-color:rgb(var(--rgb-blue) / .3)}.pill-chip--admin{background:rgb(var(--rgb-amber) / .12);color:var(--amber);border-color:rgb(var(--rgb-amber) / .35)}.scope-chips{display:inline-flex;flex-wrap:wrap;gap:4px}.row-meta-mono{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);margin-top:2px}.row-mono{font-family:JetBrains Mono,monospace;font-size:12px;color:var(--text-muted)}.row-action{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:var(--radius-md);background:transparent;border:1px solid var(--border-strong);color:var(--text-muted);font-size:11px;font-weight:600;cursor:pointer;transition:all .15s ease}.row-action:hover:not(:disabled){background:rgb(var(--rgb-fg) / .04);border-color:rgb(var(--rgb-fg) / .2);color:var(--text)}.row-action--danger{color:var(--status-error-fg);border-color:rgb(var(--rgb-red) / .25)}.row-action--danger:hover:not(:disabled){background:rgb(var(--rgb-red) / .06);border-color:rgb(var(--rgb-red) / .5);color:#fca5a5}.row-action:disabled{opacity:.4;cursor:not-allowed}.empty-state{background:var(--surface);border:1px dashed var(--border-strong);border-radius:var(--radius-lg);padding:56px 32px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}.empty-state__icon{width:56px;height:56px;border-radius:50%;background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);display:flex;align-items:center;justify-content:center;margin-bottom:4px;border:1px solid rgb(var(--rgb-accent) / .18)}.empty-state__title{margin:0;font-family:Outfit,sans-serif;font-size:18px;font-weight:700;color:var(--text);letter-spacing:-.005em}.empty-state__copy{margin:0;font-size:13px;color:var(--text-muted);line-height:1.55;max-width:480px}.empty-state__action{margin-top:12px}.team-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-4)}.team-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:18px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:14px;text-align:left;cursor:pointer;transition:border-color .15s,transform .15s,box-shadow .15s;color:var(--text);width:100%}.team-card:hover{border-color:rgb(var(--rgb-accent) / .4);transform:translateY(-1px);box-shadow:var(--shadow-md)}.team-card__header{display:flex;align-items:flex-start;gap:12px}.team-card__icon{width:36px;height:36px;border-radius:var(--radius-md);background:rgb(var(--rgb-accent) / .1);color:var(--color-accent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.team-card__title{flex:1;min-width:0}.team-card__name{font-family:Outfit,sans-serif;font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.team-card__id{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);margin-top:2px}.team-card__delete{flex-shrink:0}.team-card__metrics{display:flex;gap:20px;border-top:1px dashed var(--border);padding-top:12px}.team-card__metric{display:flex;align-items:center;gap:6px;color:var(--text-muted);font-size:12px}.team-card__metric svg{color:var(--text-dim)}.team-card__metric-value{font-family:Outfit,sans-serif;font-size:16px;font-weight:700;color:var(--text)}.team-card__metric-label{color:var(--text-dim);font-size:11px;letter-spacing:.02em}.team-card__footer{margin-top:auto;font-family:JetBrains Mono,monospace;font-size:10.5px;color:var(--text-dim);letter-spacing:.04em}:root[data-theme=light] .ai-config-row{background:var(--surface-2)}:root[data-theme=light] .setting-input-wrapper select{color-scheme:light}:root[data-theme=light] .reset-to-defaults-btn{border-color:rgb(var(--rgb-red) / .3);color:var(--red)}:root[data-theme=light] .row-action--danger:hover:not(:disabled){color:var(--red-100)}
1
+ .settings-container{padding:24px 32px;max-width:1440px;margin:0 auto;color:var(--text);animation:fadeIn .3s ease;min-height:calc(100vh - 40px);display:flex;flex-direction:column;font-family:Inter,-apple-system,sans-serif;position:relative;background:var(--bg);width:100%}.settings-container>header{padding-left:0;padding-right:0}.settings-header{margin-bottom:24px;padding-bottom:20px;border-bottom:1px solid var(--border)}.settings-header h2{margin:0;font-size:1.75rem;font-weight:700;font-family:Outfit,sans-serif;color:var(--text)}.settings-title-group{display:flex;align-items:center;gap:12px}.settings-title-group .settings-icon{color:var(--text-muted);flex-shrink:0}.settings-subtitle{color:var(--text-muted);font-size:.85rem;margin-top:6px;line-height:1.5}.settings-subtitle span{font-family:JetBrains Mono,monospace;font-size:.75rem;color:var(--text-dim)}.badge-elite{font-size:11px;padding:3px 8px;border-radius:4px;background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);border:1px solid rgb(var(--rgb-accent) / .25);font-weight:500}.status-pill{display:inline-flex;align-items:center;gap:8px;padding:4px 12px;border-radius:6px;font-size:11px;font-weight:800;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border:1px solid var(--border)}.status-pill.success{border-color:rgb(var(--rgb-success) / .3);color:var(--color-success)}.status-pill.error{border-color:#ff44444d;color:var(--status-error-fg)}.locked-indicator{display:flex;align-items:center;gap:8px;font-size:.75rem;color:var(--text-dim);font-family:JetBrains Mono,monospace;margin-top:var(--space-4)}.locked-indicator code{background:rgb(var(--rgb-fg) / .05);color:var(--text-muted);padding:2px 6px;border-radius:4px}.settings-content{display:flex;flex-direction:column;gap:var(--space-8);flex-grow:1}.settings-section h3{display:flex;align-items:center;gap:var(--space-2);font-size:1.125rem;color:var(--text);font-weight:700;margin-bottom:var(--space-2)}.settings-content{display:flex;flex-direction:column;gap:var(--space-8);flex-grow:1;position:relative}.settings-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--space-6);margin-bottom:var(--space-6)}.settings-grid>*{grid-column:span 12}@media (min-width: 1024px){.settings-grid{grid-template-columns:repeat(3,1fr)}.settings-grid>*{grid-column:span 1}}.settings-grid--three{display:grid;grid-template-columns:1fr;gap:var(--space-5);margin-bottom:var(--space-6);align-items:stretch}.settings-grid--three>*{grid-column:auto}@media (min-width: 1024px){.settings-grid--three{grid-template-columns:repeat(3,minmax(0,1fr))}}.settings-grid--two-equal{display:grid;grid-template-columns:1fr;gap:var(--space-5);margin-bottom:var(--space-6);align-items:stretch}.settings-grid--two-equal>*{grid-column:auto}@media (min-width: 1024px){.settings-grid--two-equal{grid-template-columns:repeat(2,minmax(0,1fr))}}.card-spacer{flex-grow:1;min-height:24px}.section-description{color:var(--text-muted);font-size:.875rem;margin-bottom:var(--space-6);max-width:640px;line-height:1.6}.input-group{display:flex;align-items:center;gap:8px;background:var(--bg);border-radius:6px;padding:0 12px;height:42px;border:1px solid var(--border);transition:all .2s ease;position:relative}.input-group:hover{border-color:var(--border-strong)}.mesh-gradient-infra .input-group:focus-within,.mesh-gradient-ai .input-group:focus-within{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .03);box-shadow:0 0 0 1px var(--color-accent)}.input-group input,.input-group select{background:transparent;border:none;color:var(--text);font-size:.95rem;width:100%;height:100%;outline:none;font-family:JetBrains Mono,monospace;font-weight:500}.input-group input::placeholder{color:var(--text-dim);opacity:.5}.input-group select{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 0 center;padding-right:2rem}.input-group .code-font{color:var(--text-dim);font-size:.7rem;font-weight:500;letter-spacing:1px;font-family:JetBrains Mono,monospace}.health-monitor-alert{display:flex;align-items:center;gap:12px;background:rgb(var(--rgb-amber-alt) / .06);border:1px solid rgb(var(--rgb-amber-alt) / .2);padding:12px 16px;border-radius:6px;color:var(--status-busy-fg);font-size:11px;font-weight:500}.status-banner{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:6px;font-size:11px;animation:slideIn .3s ease;margin-top:16px;font-weight:500}@keyframes slideIn{0%{opacity:0;transform:translate(-20px)}to{opacity:1;transform:translate(0)}}.status-banner.success{background:rgb(var(--rgb-success) / .06);border:1px solid rgb(var(--rgb-success) / .25);color:var(--color-success)}.status-banner.error{background:#ff44440f;border:1px solid rgba(255,68,68,.25);color:var(--status-error-fg)}.cron-presets{margin-top:24px;padding-top:16px;border-top:1px solid var(--border)}.presets-label{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:500;color:var(--text-dim);margin-bottom:10px}.preset-chip{padding:5px 12px;margin:2px;background:var(--bg);border:1px solid var(--border);color:var(--text-muted);font-size:11px;font-weight:500;border-radius:4px;cursor:pointer;transition:all .2s ease;white-space:nowrap}.preset-chip:hover{background:var(--surface-2);color:var(--text);border-color:var(--border-strong)}.preset-chip.active{background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .3)}.settings-footer{position:sticky;bottom:0;background:var(--surface);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border-top:1px solid var(--border-strong);padding:16px 32px;display:flex;justify-content:space-between;align-items:center;margin-top:auto;z-index:1000}.footer-left{display:flex;align-items:center;gap:16px}.footer-right{display:flex;gap:16px}.footer-dirty{display:inline-flex;align-items:center;gap:8px;color:var(--amber);font-family:Inter,sans-serif;font-size:13px;font-weight:500}.footer-dirty__dot{width:8px;height:8px;border-radius:50%;background:var(--amber);box-shadow:none;animation:dirty-pulse 2s ease-in-out infinite}@keyframes dirty-pulse{0%,to{opacity:1}50%{opacity:.55}}.footer-divider{width:1px;height:18px;background:var(--border-strong)}.save-btn{background:var(--color-accent);color:var(--bg);padding:10px 24px;border-radius:6px;font-weight:600;font-size:11px;border:none;transition:all .2s;display:flex;align-items:center;gap:6px}.save-btn:hover:not(:disabled){background:var(--color-accent-strong);transform:translateY(-1px);box-shadow:none}.save-btn:active:not(:disabled){transform:translateY(0)}.reset-btn{background:transparent;border:1px solid var(--border);color:var(--text-muted);padding:9px 20px;border-radius:6px;font-weight:500;font-size:11px;transition:all .2s}.reset-btn:hover:not(:disabled){background:var(--surface-2);color:var(--text);border-color:var(--border-strong)}.reset-to-defaults-btn{background:transparent;border:1px solid rgba(255,68,68,.2);color:#f44;padding:9px 20px;border-radius:6px;font-size:11px;font-weight:500;display:flex;align-items:center;gap:6px;transition:all .2s}.reset-to-defaults-btn:hover:not(:disabled){background:rgb(var(--rgb-red-alt) / .05);border-color:var(--red-alt)}.save-btn:disabled,.reset-btn:disabled,.reset-to-defaults-btn:disabled{opacity:.5;cursor:not-allowed;box-shadow:none;filter:grayscale(.2)}.setting-field{display:flex;flex-direction:column;gap:var(--space-2);width:100%}.setting-input-wrapper{display:flex;align-items:center;gap:var(--space-4);background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:8px 12px;transition:border-color .15s,box-shadow .15s}.setting-input-wrapper:focus-within{border-color:var(--color-accent);box-shadow:0 0 0 2px #3fb95066}.setting-input-wrapper input,.setting-input-wrapper select{background:transparent;border:none;color:var(--text);font-size:.875rem;width:100%;outline:none}.settings-loading{height:400px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-4);color:var(--text-muted)}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 640px){.settings-container{padding:var(--space-6)}.settings-footer{flex-direction:column;gap:var(--space-3);padding:var(--space-6)}.footer-left,.footer-right{width:100%;display:flex;flex-direction:column;gap:var(--space-2)}.reset-btn,.save-btn,.reset-to-defaults-btn{width:100%;justify-content:center;white-space:nowrap}}.save-btn,.reset-btn,.reset-to-defaults-btn{white-space:nowrap}.glow-error{box-shadow:none;border-color:rgb(var(--rgb-red) / .4)!important;animation:pulse-error 2s infinite}@keyframes pulse-error{0%{box-shadow:none}50%{box-shadow:none}to{box-shadow:none}}.critical-alert-card{background:#7f1d1d4d;border:2px solid var(--status-error-fg);border-radius:var(--radius-lg);overflow:hidden;margin-top:var(--space-8);box-shadow:none;animation:shake-entry .4s ease-out}@keyframes shake-entry{0%{transform:translate(0)}25%{transform:translate(-5px)}50%{transform:translate(5px)}75%{transform:translate(-5px)}to{transform:translate(0)}}.critical-header{background:var(--status-error-fg);color:var(--text);padding:16px 24px;display:flex;align-items:center;gap:12px;font-weight:700;font-size:1.1rem;letter-spacing:.02em}.setting-input-wrapper select{background:transparent;color:var(--text);font-family:Inter,sans-serif;font-weight:500;cursor:pointer;padding-right:32px;-moz-appearance:none;appearance:none;-webkit-appearance:none;color-scheme:dark}.setting-input-wrapper{position:relative}.setting-input-wrapper:after{content:"";position:absolute;right:12px;top:50%;transform:translateY(-50%);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid var(--text-dim);pointer-events:none}.setting-input-wrapper:hover:after{border-top-color:var(--color-accent)}.setting-input-wrapper select option{background-color:var(--surface);color:var(--text);padding:12px}.critical-body{padding:24px;color:#fca5a5}.critical-body p{margin:0 0 16px;line-height:1.6;font-size:.95rem}.terminal-block-critical{background:var(--bg);border:1px solid rgba(127,29,29,.6);border-radius:8px;padding:16px;font-family:JetBrains Mono,monospace;font-size:.85rem;color:var(--white);display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:16px}.terminal-block-critical code{color:#a5f3fc;font-weight:600}.copy-btn-critical{background:rgb(var(--rgb-fg) / .1);border:1px solid rgb(var(--rgb-fg) / .2);color:var(--white);width:32px;height:32px;border-radius:6px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.copy-btn-critical:hover{background:rgb(var(--rgb-fg) / .2);transform:scale(1.05)}.setting-input-wrapper:focus-within{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .03);box-shadow:0 0 0 1px var(--color-accent),inset 0 0 0 1px rgb(var(--rgb-accent) / .1);transform:translateY(-1px)}.live-signal{width:6px;height:6px;background-color:var(--color-success);border-radius:50%;margin-right:6px;position:relative}.live-signal:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:var(--color-success);animation:ping-signal 1.5s cubic-bezier(0,0,.2,1) infinite}@keyframes ping-signal{75%,to{transform:scale(2.5);opacity:0}}.input-container{background:rgb(var(--rgb-fg) / .05);border:1px solid rgb(var(--rgb-fg) / .1);height:42px}.status-pill{height:42px;background:rgb(var(--rgb-fg) / .05);border:1px solid rgb(var(--rgb-fg) / .1)}.card-header-dense{border-bottom:1px solid rgb(var(--rgb-fg) / .05);padding-bottom:16px;margin-bottom:24px}.form-field{display:flex;flex-direction:column;gap:10px}.field-label{font-size:.75rem;font-weight:700;color:var(--text-muted);padding-left:2px}.status-badge{display:flex;align-items:center;gap:8px;padding:0 16px;border-radius:6px;font-size:.8rem;font-weight:600;font-family:JetBrains Mono,monospace;height:42px;width:100%;transition:all .2s}.status-badge.success-filled{background:rgb(var(--rgb-success) / .15);color:var(--color-success-soft);border:1px solid rgb(var(--rgb-success) / .2)}.status-badge.error-filled{background:rgb(var(--rgb-red) / .15);color:var(--red-400);border:1px solid rgb(var(--rgb-red) / .2)}.ghost-btn{background:transparent;border:1px solid rgb(var(--rgb-fg) / .1);color:var(--text-muted);padding:0 20px;height:40px;border-radius:6px;font-weight:600;font-size:.85rem;transition:all .2s;display:flex;align-items:center;gap:8px}.ghost-btn:hover{background:rgb(var(--rgb-fg) / .05);color:var(--text);border-color:rgb(var(--rgb-fg) / .2)}.save-btn.primary{height:40px;box-shadow:none}.ai-provider-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--space-4)}.ai-provider-card{display:flex;flex-direction:column;gap:12px;padding:16px 20px;border-radius:8px;border:1px solid rgb(var(--rgb-fg) / .08);background:rgb(var(--rgb-fg) / .03);cursor:pointer;transition:all .2s ease;text-align:left;color:var(--text)}.ai-provider-card:hover:not(.disabled){border-color:rgb(var(--rgb-fg) / .2);background:rgb(var(--rgb-fg) / .06)}.ai-provider-card.active{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);box-shadow:0 0 0 1px var(--color-accent)}.ai-provider-card.disabled{opacity:.4;cursor:not-allowed;filter:grayscale(.5)}.ai-provider-card-header{display:flex;align-items:center;gap:12px}.ai-provider-icon{width:36px;height:36px;border-radius:8px;background:rgb(var(--rgb-fg) / .06);display:flex;align-items:center;justify-content:center;color:var(--text-muted);flex-shrink:0}.ai-provider-card.active .ai-provider-icon{background:rgb(var(--rgb-accent) / .15);color:var(--color-accent)}.ai-provider-info{display:flex;flex-direction:column;gap:2px;min-width:0}.ai-provider-name{font-weight:700;font-size:.95rem;color:var(--text)}.ai-provider-desc{font-size:.75rem;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ai-provider-status{display:flex;align-items:center}.ai-config-display{display:flex;flex-direction:column;gap:1px;background:rgb(var(--rgb-fg) / .04);border-radius:8px;overflow:hidden;border:1px solid rgb(var(--rgb-fg) / .06)}.ai-config-row{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#02061780}.ai-config-row+.ai-config-row{border-top:1px solid rgb(var(--rgb-fg) / .04)}.ai-config-label{font-size:.8rem;font-weight:600;color:var(--text-muted)}.ai-config-value{font-size:.9rem;font-weight:500;color:var(--text);display:flex;align-items:center;gap:8px}.ai-config-value.mono{font-family:JetBrains Mono,monospace;font-size:.85rem;color:var(--text)}.ai-config-default{font-size:11px;background:rgb(var(--rgb-fg) / .06);color:var(--text-dim);padding:2px 6px;border-radius:4px}.toggle-group{display:flex;align-items:center;gap:12px}.switch{position:relative;display:inline-block;width:38px;height:22px;flex-shrink:0}.switch input{opacity:0;width:0;height:0}.slider{position:absolute;top:0;right:0;bottom:0;left:0;background:rgb(var(--rgb-fg) / .08);border:1px solid var(--border);transition:all .2s ease;cursor:pointer;border-radius:999px}.slider:before{content:"";position:absolute;width:16px;height:16px;left:2px;top:50%;transform:translateY(-50%);background:var(--text-muted);border-radius:50%;transition:all .2s ease}.switch input:checked+.slider{background:rgb(var(--rgb-accent) / .15);border-color:var(--color-accent);box-shadow:none}.switch input:checked+.slider:before{left:calc(100% - 18px);background:var(--color-accent)}.switch input:focus-visible+.slider{outline:2px solid var(--color-accent);outline-offset:2px}.toggle-label{font-size:11px;font-weight:700;color:var(--text-muted)}.cron-preview{margin-top:12px;padding:10px 12px;background:rgb(var(--rgb-well) / calc(.25 * var(--well-k)));border:1px solid var(--border);border-radius:6px;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px}.cron-preview .preview-label{font-size:11px;font-weight:700;color:var(--text-dim)}.cron-preview .preview-value{font-size:13px;color:var(--text);font-weight:500}.cron-presets{margin-top:12px}.presets-label{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--text-dim);margin-bottom:8px}.presets-grid{display:flex;flex-wrap:wrap;gap:8px}.preset-chip{padding:6px 12px;border-radius:6px;border:1px solid var(--border);background:rgb(var(--rgb-fg) / .03);color:var(--text-muted);font-size:11px;font-weight:600;cursor:pointer;transition:all .2s ease}.preset-chip:hover{border-color:var(--border);color:var(--text)}.preset-chip.active{background:rgb(var(--rgb-accent) / .18);border-color:var(--color-accent);color:var(--color-accent);box-shadow:inset 0 0 0 1px rgb(var(--rgb-accent) / .35)}.preset-chip__check{color:var(--color-accent)}.active-pill{display:inline-flex;align-items:center;gap:5px;margin-left:auto;padding:4px 10px;border-radius:999px;font-family:Inter,sans-serif;font-size:11px;font-weight:600;color:var(--color-accent);background:rgb(var(--rgb-accent) / .1);border:1px solid rgb(var(--rgb-accent) / .3);letter-spacing:.01em}.card-title-row{display:inline-flex;align-items:center;gap:6px}.modified-dot{width:6px;height:6px;border-radius:50%;background:var(--amber);box-shadow:none;display:inline-block}.input-group.has-error{border-color:rgb(var(--rgb-red) / .55);background:rgb(var(--rgb-red) / .04)}.input-group.has-error:focus-within{border-color:var(--red);box-shadow:0 0 0 1px var(--red);background:rgb(var(--rgb-red) / .06)}.input-status{display:flex;align-items:center;gap:6px;margin-top:4px;font-family:Inter,sans-serif;font-size:12px;font-weight:500;letter-spacing:.01em}.input-status--ok{color:var(--color-success)}.input-status--error{color:var(--status-error-fg)}.presets-grid--stacked{display:flex;flex-direction:column;gap:8px;align-items:stretch}.presets-grid--stacked .preset-chip{justify-content:flex-start;width:100%}.switch--header{margin-left:auto}.healing-state{font-size:11px;font-weight:700;margin-top:-4px}.healing-state.is-on{color:var(--color-accent)}.healing-state.is-off{color:var(--text-dim)}.healing-events{margin-top:auto;padding:12px;border-radius:var(--radius-md);background:rgb(var(--rgb-fg) / .025);border:1px solid var(--border);display:flex;flex-direction:column;gap:10px}.healing-events__link{margin-left:auto;display:inline-flex;align-items:center;gap:3px;text-decoration:none;color:var(--color-accent);font-family:JetBrains Mono,monospace;font-size:9.5px;font-weight:600;letter-spacing:.06em;padding:2px 6px;border-radius:4px;border:1px solid rgb(var(--rgb-accent) / .25);background:rgb(var(--rgb-accent) / .06);transition:all .15s ease;text-transform:none}.healing-events__link:hover{background:rgb(var(--rgb-accent) / .12);border-color:rgb(var(--rgb-accent) / .4)}.healing-events__header{display:flex;align-items:center;gap:6px;font-size:11px;font-weight:700;color:var(--text-dim)}.healing-events__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}.healing-events__empty{font-size:11.5px;color:var(--text-dim);line-height:1.45;padding:6px 2px}.healing-event{display:flex;gap:10px;align-items:flex-start}.healing-event__icon{color:var(--color-accent);flex-shrink:0;margin-top:1px}.healing-event__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.healing-event__row{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.healing-event__kind{font-size:12px;font-weight:700;color:var(--text)}.healing-event__when{font-family:JetBrains Mono,monospace;font-size:10px;color:var(--text-dim);white-space:nowrap}.healing-event__message{font-size:11.5px;color:var(--text-muted);line-height:1.4}.settings-footer{animation:dirty-slide-up .2s cubic-bezier(.2,0,0,1)}@keyframes dirty-slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.page-header-subnote{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-dim);margin-left:8px}.provider-count-pill{display:inline-flex;align-items:center;margin-left:auto;padding:4px 10px;border-radius:6px;font-size:11px;font-weight:700}.provider-count-pill.is-ok{background:rgb(var(--rgb-success) / .1);color:var(--color-success);border:1px solid rgb(var(--rgb-success) / .3)}.provider-count-pill.is-empty{background:#8a938f14;color:var(--text-muted);border:1px solid var(--border-strong)}.provider-list{display:flex;flex-direction:column;gap:10px}.provider-row{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:var(--radius-md);border:1px solid var(--border);background:rgb(var(--rgb-fg) / .02);color:var(--text);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,box-shadow .15s;width:100%}.provider-row:hover:not(:disabled):not(.is-active){border-color:var(--border-strong);background:rgb(var(--rgb-fg) / .04)}.provider-row.is-active{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);box-shadow:inset 0 0 0 1px rgb(var(--rgb-accent) / .4)}.provider-row.is-disabled{cursor:not-allowed;opacity:.55}.provider-row__icon{width:36px;height:36px;border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;background:rgb(var(--rgb-fg) / .05);color:var(--text-muted);flex-shrink:0;font-family:Outfit,sans-serif;font-weight:700;font-size:16px}.provider-row.is-active .provider-row__icon{background:rgb(var(--rgb-accent) / .18);color:var(--color-accent)}.ai-provider-glyph{font-family:Outfit,sans-serif;font-weight:700;font-size:18px;line-height:1}.provider-row__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.provider-row__name{font-weight:700;font-size:14px;color:var(--text)}.provider-row__desc{font-size:12px;color:var(--text-muted);line-height:1.4}.provider-row__status{margin-top:6px}.provider-status{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:4px;font-size:11px;font-weight:700;border:1px solid transparent}.provider-status--active{color:var(--color-accent);background:rgb(var(--rgb-accent) / .12);border-color:rgb(var(--rgb-accent) / .35)}.provider-status--off{color:var(--text-dim);background:rgb(var(--rgb-fg) / .04);border-color:var(--border-strong)}.provider-status--ready{color:var(--text-muted);background:rgb(var(--rgb-fg) / .04);border-color:var(--border)}.test-connection-btn{margin-top:auto;display:flex;align-items:center;justify-content:center;gap:8px;padding:12px 16px;border-radius:var(--radius-md);background:rgb(var(--rgb-fg) / .04);border:1px solid var(--border-strong);color:var(--text);font-family:Inter,sans-serif;font-size:13px;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s;width:100%}.test-connection-btn:hover:not(:disabled){background:rgb(var(--rgb-accent) / .06);border-color:rgb(var(--rgb-accent) / .4);color:var(--color-accent)}.test-connection-btn:disabled{opacity:.5;cursor:not-allowed}.ai-config-row .ai-config-default{margin-left:auto}.maintenance-notice{background:rgb(var(--rgb-blue) / .05)!important;border-color:rgb(var(--rgb-blue) / .25)!important;color:var(--blue)!important;text-transform:none!important;letter-spacing:normal!important}.stat-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--space-4);margin-bottom:var(--space-5)}.stat-strip__cell{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:16px 20px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:4px}.stat-strip__value{font-family:Outfit,sans-serif;font-size:28px;font-weight:700;line-height:1.1;color:var(--text);letter-spacing:-.02em}.stat-strip__value--accent{color:var(--color-accent)}.stat-strip__label{font-size:11px;font-weight:600;color:var(--text-dim)}.data-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);overflow:hidden}.data-card .table-row:hover{background:rgb(var(--rgb-fg) / .03)}.pill-chip{display:inline-flex;align-items:center;padding:3px 9px;border-radius:999px;font-family:JetBrains Mono,monospace;font-size:10.5px;font-weight:600;letter-spacing:.04em;border:1px solid transparent;line-height:1.4}.pill-chip--shared{background:rgb(var(--rgb-fg) / .04);color:var(--text-muted);border-color:var(--border-strong)}.pill-chip--team{background:rgb(var(--rgb-accent) / .1);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .3)}.pill-chip--scope{background:rgb(var(--rgb-blue) / .1);color:var(--blue);border-color:rgb(var(--rgb-blue) / .3)}.pill-chip--admin{background:rgb(var(--rgb-amber) / .12);color:var(--amber);border-color:rgb(var(--rgb-amber) / .35)}.scope-chips{display:inline-flex;flex-wrap:wrap;gap:4px}.row-meta-mono{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);margin-top:2px}.row-mono{font-family:JetBrains Mono,monospace;font-size:12px;color:var(--text-muted)}.row-action{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;border-radius:var(--radius-md);background:transparent;border:1px solid var(--border-strong);color:var(--text-muted);font-size:11px;font-weight:600;cursor:pointer;transition:all .15s ease}.row-action:hover:not(:disabled){background:rgb(var(--rgb-fg) / .04);border-color:rgb(var(--rgb-fg) / .2);color:var(--text)}.row-action--danger{color:var(--status-error-fg);border-color:rgb(var(--rgb-red) / .25)}.row-action--danger:hover:not(:disabled){background:rgb(var(--rgb-red) / .06);border-color:rgb(var(--rgb-red) / .5);color:#fca5a5}.row-action:disabled{opacity:.4;cursor:not-allowed}.empty-state{background:var(--surface);border:1px dashed var(--border-strong);border-radius:var(--radius-lg);padding:56px 32px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}.empty-state__icon{width:56px;height:56px;border-radius:50%;background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);display:flex;align-items:center;justify-content:center;margin-bottom:4px;border:1px solid rgb(var(--rgb-accent) / .18)}.empty-state__title{margin:0;font-family:Outfit,sans-serif;font-size:18px;font-weight:700;color:var(--text);letter-spacing:-.005em}.empty-state__copy{margin:0;font-size:13px;color:var(--text-muted);line-height:1.55;max-width:480px}.empty-state__action{margin-top:12px}.team-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-4)}.team-card{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius-lg);padding:18px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:14px;text-align:left;cursor:pointer;transition:border-color .15s,transform .15s,box-shadow .15s;color:var(--text);width:100%}.team-card:hover{border-color:rgb(var(--rgb-accent) / .4);transform:translateY(-1px);box-shadow:var(--shadow-md)}.team-card__header{display:flex;align-items:flex-start;gap:12px}.team-card__icon{width:36px;height:36px;border-radius:var(--radius-md);background:rgb(var(--rgb-accent) / .1);color:var(--color-accent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.team-card__title{flex:1;min-width:0}.team-card__name{font-family:Outfit,sans-serif;font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.005em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.team-card__id{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);margin-top:2px}.team-card__delete{flex-shrink:0}.team-card__metrics{display:flex;gap:20px;border-top:1px dashed var(--border);padding-top:12px}.team-card__metric{display:flex;align-items:center;gap:6px;color:var(--text-muted);font-size:12px}.team-card__metric svg{color:var(--text-dim)}.team-card__metric-value{font-family:Outfit,sans-serif;font-size:16px;font-weight:700;color:var(--text)}.team-card__metric-label{color:var(--text-dim);font-size:11px;letter-spacing:.02em}.team-card__footer{margin-top:auto;font-family:JetBrains Mono,monospace;font-size:10.5px;color:var(--text-dim);letter-spacing:.04em}:root[data-theme=light] .ai-config-row{background:var(--surface-2)}:root[data-theme=light] .setting-input-wrapper select{color-scheme:light}:root[data-theme=light] .reset-to-defaults-btn{border-color:rgb(var(--rgb-red) / .3);color:var(--red)}:root[data-theme=light] .row-action--danger:hover:not(:disabled){color:var(--red-100)}
@@ -1 +1 @@
1
- import{j as t}from"./index-DI1fGIyj.js";const d={neutral:"text-[var(--text-muted)]",good:"text-[var(--color-success)]",bad:"text-[var(--color-danger)]"},o=({label:e,value:r,valueCls:a="text-[var(--text)]",note:s,noteTone:x="neutral"})=>t.jsxs("div",{className:"min-w-0 rounded-lg border border-[var(--border)] bg-[var(--surface)] px-4 py-3",children:[t.jsx("div",{className:"text-xs text-[var(--text-muted)]",children:e}),t.jsx("div",{className:`mt-1 text-2xl font-semibold tabular-nums leading-tight truncate ${a}`,children:r}),t.jsx("div",{className:`mt-0.5 text-[11px] truncate ${d[x]}`,children:s??" "})]});export{o as S};
1
+ import{j as t}from"./index-BOxe43p1.js";const d={neutral:"text-[var(--text-muted)]",good:"text-[var(--color-success)]",bad:"text-[var(--color-danger)]"},o=({label:e,value:r,valueCls:a="text-[var(--text)]",note:s,noteTone:x="neutral"})=>t.jsxs("div",{className:"min-w-0 rounded-lg border border-[var(--border)] bg-[var(--surface)] px-4 py-3",children:[t.jsx("div",{className:"text-xs text-[var(--text-muted)]",children:e}),t.jsx("div",{className:`mt-1 text-2xl font-semibold tabular-nums leading-tight truncate ${a}`,children:r}),t.jsx("div",{className:`mt-0.5 text-[11px] truncate ${d[x]}`,children:s??" "})]});export{o as S};
@@ -1,4 +1,4 @@
1
- import{c as e}from"./index-DI1fGIyj.js";/**
1
+ import{c as e}from"./index-BOxe43p1.js";/**
2
2
  * @license lucide-react v0.555.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.