@xenon-device-management/xenon 1.1.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 (228) hide show
  1. package/README.md +446 -0
  2. package/lib/package.json +207 -0
  3. package/lib/public/assets/Layouts-7IT8aFLI.js +11 -0
  4. package/lib/public/assets/Layouts-DPMls9vh.css +1 -0
  5. package/lib/public/assets/ai-settings-BbnfgdEx.js +11 -0
  6. package/lib/public/assets/apps-CRMrI4_p.js +16 -0
  7. package/lib/public/assets/apps-CcM77dgg.css +1 -0
  8. package/lib/public/assets/badge-B1nKs8zj.css +1 -0
  9. package/lib/public/assets/badge-CSvl5xIU.js +11 -0
  10. package/lib/public/assets/button-CJlKn4PZ.css +1 -0
  11. package/lib/public/assets/button-CvLaGFYj.js +26 -0
  12. package/lib/public/assets/calendar-6w-D6Oaw.js +6 -0
  13. package/lib/public/assets/clock-DcdeWBPr.js +6 -0
  14. package/lib/public/assets/cpu-DiSoXT9n.js +6 -0
  15. package/lib/public/assets/device-explorer-CajM63OJ.js +193 -0
  16. package/lib/public/assets/device-explorer-CxdUAoTL.css +1 -0
  17. package/lib/public/assets/index-ByQwMN5T.js +174 -0
  18. package/lib/public/assets/index-C1DBaoSh.js +1 -0
  19. package/lib/public/assets/index-qzCez_kk.css +1 -0
  20. package/lib/public/assets/lock-B23ibZmo.js +6 -0
  21. package/lib/public/assets/maintenance-settings-CirzA6yG.js +6 -0
  22. package/lib/public/assets/mouse-pointer-2-Cz76SHFb.js +6 -0
  23. package/lib/public/assets/plus-BBwlIevt.js +6 -0
  24. package/lib/public/assets/session-dashboard-C2k7FFv_.css +1 -0
  25. package/lib/public/assets/session-dashboard-HPDtwPOZ.js +62 -0
  26. package/lib/public/assets/settings-DrZsZwdc.js +1 -0
  27. package/lib/public/assets/trash-2-DQpvzJec.js +6 -0
  28. package/lib/public/assets/useSocket-Dxsqae2a.js +16 -0
  29. package/lib/public/assets/webhook-settings-CDPgsgkb.css +1 -0
  30. package/lib/public/assets/webhook-settings-Cp-B4Nrw.js +1 -0
  31. package/lib/public/assets/zap-DovP6iow.js +6 -0
  32. package/lib/public/favicon.ico +0 -0
  33. package/lib/public/favicon.png +0 -0
  34. package/lib/public/favicon.svg +9 -0
  35. package/lib/public/index.html +46 -0
  36. package/lib/public/logo.svg +17 -0
  37. package/lib/public/logo192.png +0 -0
  38. package/lib/public/logo512.png +0 -0
  39. package/lib/public/manifest.json +25 -0
  40. package/lib/public/robots.txt +3 -0
  41. package/lib/schema.json +348 -0
  42. package/lib/src/InternalHttpClient.js +212 -0
  43. package/lib/src/PluginContext.js +29 -0
  44. package/lib/src/XenonCapabilityManager.js +199 -0
  45. package/lib/src/app/index.js +167 -0
  46. package/lib/src/app/routers/apps.js +79 -0
  47. package/lib/src/app/routers/config.js +131 -0
  48. package/lib/src/app/routers/control.js +835 -0
  49. package/lib/src/app/routers/dashboard.js +301 -0
  50. package/lib/src/app/routers/grid.js +352 -0
  51. package/lib/src/app/routers/reservation.js +190 -0
  52. package/lib/src/app/routers/webhook.js +83 -0
  53. package/lib/src/app/swagger-docs.js +203 -0
  54. package/lib/src/app/swagger.js +366 -0
  55. package/lib/src/chromeUtils.js +148 -0
  56. package/lib/src/commands/handle.js +19 -0
  57. package/lib/src/commands/index.js +8 -0
  58. package/lib/src/config.js +73 -0
  59. package/lib/src/dashboard/asset-manager.js +84 -0
  60. package/lib/src/dashboard/commands.js +284 -0
  61. package/lib/src/dashboard/event-manager.js +699 -0
  62. package/lib/src/dashboard/services/app-service.js +134 -0
  63. package/lib/src/dashboard/services/failure-analysis-service.js +173 -0
  64. package/lib/src/dashboard/services/session-service.js +113 -0
  65. package/lib/src/data-service/CircuitBreaker.js +83 -0
  66. package/lib/src/data-service/config-service.js +155 -0
  67. package/lib/src/data-service/db.js +122 -0
  68. package/lib/src/data-service/device-service.js +320 -0
  69. package/lib/src/data-service/device-store.interface.js +2 -0
  70. package/lib/src/data-service/device-store.js +345 -0
  71. package/lib/src/data-service/pending-sessions-service.js +25 -0
  72. package/lib/src/data-service/pluginArgs.js +25 -0
  73. package/lib/src/data-service/prisma-service.js +31 -0
  74. package/lib/src/data-service/prisma-store.js +385 -0
  75. package/lib/src/data-service/queue-service.js +150 -0
  76. package/lib/src/data-service/web-config-service.js +130 -0
  77. package/lib/src/device-managers/AndroidDeviceManager.js +1155 -0
  78. package/lib/src/device-managers/ChromeDriverManager.js +68 -0
  79. package/lib/src/device-managers/HealthMonitorService.js +325 -0
  80. package/lib/src/device-managers/IOSDeviceManager.js +351 -0
  81. package/lib/src/device-managers/NodeDevices.js +82 -0
  82. package/lib/src/device-managers/android/AndroidStreamService.js +370 -0
  83. package/lib/src/device-managers/android/DeviceLockManager.js +45 -0
  84. package/lib/src/device-managers/cloud/CapabilityManager.js +26 -0
  85. package/lib/src/device-managers/cloud/Devices.js +86 -0
  86. package/lib/src/device-managers/iOSTracker.js +44 -0
  87. package/lib/src/device-managers/index.js +89 -0
  88. package/lib/src/device-managers/ios/IOSDiscoveryService.js +268 -0
  89. package/lib/src/device-managers/ios/IOSStreamService.js +893 -0
  90. package/lib/src/device-managers/ios/WDAClient.js +866 -0
  91. package/lib/src/device-utils.js +663 -0
  92. package/lib/src/enums/Capabilities.js +8 -0
  93. package/lib/src/enums/Cloud.js +11 -0
  94. package/lib/src/enums/Platform.js +9 -0
  95. package/lib/src/enums/SessionType.js +9 -0
  96. package/lib/src/enums/SocketEvents.js +15 -0
  97. package/lib/src/helpers/UniversalMjpegProxy.js +273 -0
  98. package/lib/src/helpers/index.js +229 -0
  99. package/lib/src/index.js +95 -0
  100. package/lib/src/interceptors/CommandInterceptor.js +524 -0
  101. package/lib/src/interfaces/ICloudManager.js +2 -0
  102. package/lib/src/interfaces/IDevice.js +2 -0
  103. package/lib/src/interfaces/IDeviceFilterOptions.js +2 -0
  104. package/lib/src/interfaces/IDeviceManager.js +2 -0
  105. package/lib/src/interfaces/IOptions.js +2 -0
  106. package/lib/src/interfaces/IPluginArgs.js +55 -0
  107. package/lib/src/interfaces/ISessionCapability.js +2 -0
  108. package/lib/src/logger.js +225 -0
  109. package/lib/src/plugin.js +244 -0
  110. package/lib/src/prisma.js +12 -0
  111. package/lib/src/profiling/AndroidAppProfiler.js +213 -0
  112. package/lib/src/proxy/wd-command-proxy.js +221 -0
  113. package/lib/src/scripts/generate-database-migration.js +59 -0
  114. package/lib/src/scripts/initialize-database.js +55 -0
  115. package/lib/src/scripts/install-go-ios.js +66 -0
  116. package/lib/src/scripts/prepare-prisma.js +89 -0
  117. package/lib/src/services/AICommandService.js +143 -0
  118. package/lib/src/services/AIService.js +466 -0
  119. package/lib/src/services/CleanupService.js +141 -0
  120. package/lib/src/services/EventBus.js +74 -0
  121. package/lib/src/services/InspectorService.js +395 -0
  122. package/lib/src/services/MetricsService.js +134 -0
  123. package/lib/src/services/NetworkConditioningService.js +173 -0
  124. package/lib/src/services/NotificationService.js +163 -0
  125. package/lib/src/services/RequestLogService.js +252 -0
  126. package/lib/src/services/ResourceIsolationService.js +122 -0
  127. package/lib/src/services/SecurityService.js +120 -0
  128. package/lib/src/services/ServerManager.js +284 -0
  129. package/lib/src/services/SessionHeartbeatService.js +158 -0
  130. package/lib/src/services/SessionLifecycleService.js +572 -0
  131. package/lib/src/services/SocketClient.js +71 -0
  132. package/lib/src/services/SocketServer.js +87 -0
  133. package/lib/src/services/TracingService.js +132 -0
  134. package/lib/src/services/VideoPipelineService.js +220 -0
  135. package/lib/src/services/healing/FuzzyXmlHealingProvider.js +333 -0
  136. package/lib/src/services/healing/HealEtalonService.js +98 -0
  137. package/lib/src/services/healing/HealedLocatorGenerator.js +132 -0
  138. package/lib/src/services/healing/HealingOrchestrator.js +165 -0
  139. package/lib/src/services/healing/LlmHealingProvider.js +77 -0
  140. package/lib/src/services/healing/OcrHealingProvider.js +119 -0
  141. package/lib/src/services/healing/ResilioTreeHealingProvider.js +100 -0
  142. package/lib/src/services/healing/VisualAiHealingProvider.js +90 -0
  143. package/lib/src/services/healing/types.js +12 -0
  144. package/lib/src/services/omni-vision/OmniVisionService.js +718 -0
  145. package/lib/src/services/omni-vision/VisionAssertionService.js +68 -0
  146. package/lib/src/sessions/CloudSession.js +42 -0
  147. package/lib/src/sessions/LocalSession.js +313 -0
  148. package/lib/src/sessions/RemoteSession.js +287 -0
  149. package/lib/src/sessions/SessionManager.js +238 -0
  150. package/lib/src/sessions/XenonSession.js +44 -0
  151. package/lib/src/types/CLIArgs.js +2 -0
  152. package/lib/src/types/CloudArgs.js +2 -0
  153. package/lib/src/types/CloudSchema.js +131 -0
  154. package/lib/src/types/DeviceType.js +2 -0
  155. package/lib/src/types/DeviceUpdate.js +2 -0
  156. package/lib/src/types/IOSDevice.js +2 -0
  157. package/lib/src/types/Platform.js +2 -0
  158. package/lib/src/types/SessionStatus.js +11 -0
  159. package/lib/src/validators/CapabilityValidator.js +93 -0
  160. package/lib/test/e2e/android/conf.spec.js +43 -0
  161. package/lib/test/e2e/android/conf2.spec.js +44 -0
  162. package/lib/test/e2e/android/conf3.spec.js +44 -0
  163. package/lib/test/e2e/e2ehelper.js +113 -0
  164. package/lib/test/e2e/hubnode/forward-request.spec.js +224 -0
  165. package/lib/test/e2e/hubnode/hubnode.spec.js +214 -0
  166. package/lib/test/e2e/ios/conf1.spec.js +39 -0
  167. package/lib/test/e2e/ios/conf2.spec.js +39 -0
  168. package/lib/test/e2e/plugin-harness.js +236 -0
  169. package/lib/test/e2e/plugin.spec.js +97 -0
  170. package/lib/test/e2e/telemetry_verification.spec.js +83 -0
  171. package/lib/test/e2e/video-recording-test.spec.js +63 -0
  172. package/lib/test/helpers/test-container.js +112 -0
  173. package/lib/test/integration/androidDevices.spec.js +137 -0
  174. package/lib/test/integration/cliArgs.js +73 -0
  175. package/lib/test/integration/ios/01iOSSimulator.spec.js +291 -0
  176. package/lib/test/integration/ios/02iOSDevices.spec.js +75 -0
  177. package/lib/test/integration/testHelpers.js +74 -0
  178. package/lib/test/unit/AndroidDeviceManager.spec.js +178 -0
  179. package/lib/test/unit/ChromeDriverManager.spec.js +26 -0
  180. package/lib/test/unit/CleanupService.spec.js +21 -0
  181. package/lib/test/unit/DeviceModel.spec.js +157 -0
  182. package/lib/test/unit/FuzzyXmlHealingProvider.test.js +294 -0
  183. package/lib/test/unit/GetAdbOriginal.js +42 -0
  184. package/lib/test/unit/HealingCascade.test.js +128 -0
  185. package/lib/test/unit/IOSDeviceManager.spec.js +261 -0
  186. package/lib/test/unit/RemoteIOs.spec.js +78 -0
  187. package/lib/test/unit/ResilioTreeHealingProvider.test.js +96 -0
  188. package/lib/test/unit/commands.spec.js +27 -0
  189. package/lib/test/unit/config.spec.js +27 -0
  190. package/lib/test/unit/device-service.spec.js +307 -0
  191. package/lib/test/unit/device-utils.spec.js +313 -0
  192. package/lib/test/unit/fixtures/device.config.js +4 -0
  193. package/lib/test/unit/fixtures/devices.js +89 -0
  194. package/lib/test/unit/helpers.spec.js +62 -0
  195. package/lib/test/unit/omni-vision.spec.js +100 -0
  196. package/lib/test/unit/plugin.spec.js +133 -0
  197. package/lib/tsconfig.tsbuildinfo +1 -0
  198. package/package.json +207 -0
  199. package/prisma/data.db +0 -0
  200. package/prisma/dev.db +0 -0
  201. package/prisma/dev.db-journal +0 -0
  202. package/prisma/migrations/20231011074725_initial_tables/migration.sql +47 -0
  203. package/prisma/migrations/20231226115334_update_session_log/migration.sql +2 -0
  204. package/prisma/migrations/20251204113710_add_video_recording_enabled/migration.sql +29 -0
  205. package/prisma/migrations/20251204132449_add_log_table/migration.sql +11 -0
  206. package/prisma/migrations/20251205050111_add_profiling_support/migration.sql +47 -0
  207. package/prisma/migrations/20251205050947_add_is_error_field/migration.sql +24 -0
  208. package/prisma/migrations/20260126201337_add_app_model/migration.sql +18 -0
  209. package/prisma/migrations/20260130115722_add_performance_trace_and_xenon_sync/migration.sql +2 -0
  210. package/prisma/migrations/20260130135114_add_device_models/migration.sql +57 -0
  211. package/prisma/migrations/20260130140655_make_systemport_optional/migration.sql +45 -0
  212. package/prisma/migrations/20260130140932_make_device_fields_optional/migration.sql +45 -0
  213. package/prisma/migrations/20260130141040_final_schema_fix/migration.sql +45 -0
  214. package/prisma/migrations/20260130143234_add_device_health_fields/migration.sql +4 -0
  215. package/prisma/migrations/20260130144921_add_failure_category/migration.sql +2 -0
  216. package/prisma/migrations/20260131151456_add_webhook_config/migration.sql +10 -0
  217. package/prisma/migrations/20260201094507_add_device_tags/migration.sql +11 -0
  218. package/prisma/migrations/20260201103410_add_managed_process/migration.sql +15 -0
  219. package/prisma/migrations/20260201140637_add_web_config/migration.sql +22 -0
  220. package/prisma/migrations/20260201162232_add_session_progress/migration.sql +2 -0
  221. package/prisma/migrations/20260201174231_add_total_healed_count/migration.sql +2 -0
  222. package/prisma/migrations/migration_lock.toml +3 -0
  223. package/prisma/schema.prisma +210 -0
  224. package/schema.json +348 -0
  225. package/scripts/build-xenon.sh +32 -0
  226. package/scripts/dev/debug-gemini.ts +44 -0
  227. package/scripts/generate-types-from-schema.js +86 -0
  228. package/scripts/install-compatible-driver.js +39 -0
package/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # Xenon
2
+
3
+ <h1 align="center">
4
+ <br>
5
+ <img src="assets/xenon-logo.png" alt="Xenon" width="200">
6
+ <br>
7
+ <br>
8
+ Intelligent Mobile Infrastructure
9
+ <br>
10
+ </h1>
11
+
12
+ <p align="center">
13
+ <strong>Self-healing device orchestration platform for Appium</strong>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="#features">Features</a> •
18
+ <a href="#quick-start">Quick Start</a> •
19
+ <a href="#capabilities">Capabilities</a> •
20
+ <a href="#api-documentation">API Docs</a> •
21
+ <a href="#documentation">Documentation</a> •
22
+ <a href="#contributing">Contributing</a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ ## ✨ What is Xenon?
28
+
29
+ **Xenon** is an intelligent Appium plugin that transforms your mobile device lab into a **self-healing, autonomous infrastructure**. Named after the noble gas known for its stability and reliability, Xenon brings enterprise-grade device orchestration to your testing pipeline.
30
+
31
+ ### Why Xenon?
32
+
33
+ | Problem | Xenon Solution |
34
+ |---------|----------------|
35
+ | Tests fail due to device state | **Auto-recovery** - Devices heal themselves |
36
+ | Manual device management | **Smart allocation** - Queue, reserve, prioritize |
37
+ | Debugging is painful | **Interactive control** - Live stream, touch, shell |
38
+ | No visibility into failures | **Rich artifacts** - Video, screenshots, profiling |
39
+ | Infrastructure silos | **Unified dashboard** - One view for all devices |
40
+
41
+ ---
42
+
43
+ ## 🚀 Features
44
+
45
+ ### Device Orchestration
46
+ - ✅ **Automatic device discovery** - Android (USB + emulators), iOS (devices + simulators)
47
+ - ✅ **Smart session allocation** - Queue management with ETA
48
+ - ✅ **WebSocket-First Sync** - Real-time Hub-Node-Dashboard bidirectional sync
49
+ - ✅ **Device reservation** - Manual mode for debugging
50
+ - ✅ **Team-based quotas** - Fair resource sharing
51
+
52
+ ### Interactive Control
53
+ - ✅ **Live streaming** - Real-time device screen in browser
54
+ - ✅ **Touch interaction** - Tap, swipe, scroll remotely
55
+ - ✅ **App management** - Install, uninstall, clear data
56
+ - ✅ **Interactive Shell** - Execute ADB/iOS commands directly
57
+ - ✅ **Device information** - Battery, storage, network status
58
+
59
+ ### 🧠 AI Self-Healing (Flagship)
60
+ - ✅ **5-Tier Healing Orchestration** - From DOM to LLM recovery
61
+ - ✅ **Signature-Based Learning** - Persistent "Etalon" signatures for high-confidence recovery
62
+ - ✅ **Multi-Modal Fallback** - Syntactic -> OCR -> Visual AI -> LLM reasoning
63
+ - ✅ **Infrastructure-Free** - Works with existing LokiJS (local) or PostgreSQL (remote)
64
+
65
+ ### Recording & Artifacts
66
+ - ✅ **Video recording** - Full session capture
67
+ - ✅ **Screenshot capture** - On-demand and per-command
68
+ - ✅ **Distributed Tracing** - OpenTelemetry spans for exact command latency
69
+ - ✅ **Performance profiling** - CPU, memory, FPS metrics
70
+ - ✅ **Log aggregation** - Appium, device, app logs
71
+ - ✅ **OpenTelemetry Integration** - Standardized distributed tracing for all sessions
72
+
73
+ ### Intelligence (Roadmap)
74
+ - 🔲 **Flaky test detection** - Auto-identify unstable tests
75
+ - 🔲 **Error categorization** - Crash vs timeout vs element not found
76
+ - 🔲 **Predictive health** - USB/battery failure prediction
77
+
78
+ ---
79
+
80
+ ## ⚡ Quick Start
81
+
82
+ ### Installation
83
+
84
+ ```bash
85
+ # Install Xenon plugin
86
+ appium plugin install xenon
87
+
88
+ # Or install from source
89
+ git clone https://github.com/xenon-platform/xenon.git
90
+ cd xenon
91
+ npm install
92
+ npm run build:all
93
+ appium plugin install --source=local .
94
+ ```
95
+
96
+ ### Running
97
+
98
+ ```bash
99
+ # Start Appium with Xenon
100
+ appium server --use-plugins=xenon \
101
+ --plugin-xenon-platform=both \
102
+ --plugin-xenon-enable-dashboard
103
+ ```
104
+
105
+ ## 🔧 Configuration
106
+
107
+ Xenon supports configuration via CLI arguments or a configuration file (YAML/JSON). We recommend using a configuration file for production deployments.
108
+
109
+ ### Using Configuration File (Recommended)
110
+
111
+ Create a `xenon-config.yaml` file:
112
+ ```yaml
113
+ server:
114
+ usePlugins: ["xenon"]
115
+ plugin:
116
+ xenon:
117
+ platform: both
118
+ maxSessions: 8
119
+ enableDashboard: true
120
+ enableSelfHealing: true
121
+ ```
122
+
123
+ Run Appium with the config:
124
+ ```bash
125
+ appium server --config xenon-config.yaml
126
+ ```
127
+
128
+ ### Runtime Configuration ⚡️
129
+
130
+ You can update configuration options at runtime without restarting the server using the API:
131
+
132
+ ```bash
133
+ # Get current config
134
+ GET /xenon/api/config
135
+
136
+ # Update config (e.g. change max sessions)
137
+ PUT /xenon/api/config
138
+ { "maxSessions": 10 }
139
+ ```
140
+
141
+ > **Note:** Some changes (like `platform` or `hub` URL) require a server restart to take full effect. The API response will indicate if a restart is required.
142
+
143
+ ### Build & Session Retention 🧹
144
+
145
+ Xenon includes an enterprise-ready cleanup job that automatically purges older builds, sessions, and associated assets (videos/screenshots) to manage disk space.
146
+
147
+ | Option | Description | Default |
148
+ |--------|-------------|---------|
149
+ | `buildCleanupDays` | Retention period in days | `30` |
150
+ | `buildCleanupMaxCount` | Maximum number of builds to keep | `100` |
151
+ | `buildCleanupSchedule` | Cron schedule for the cleanup job | `"0 0 * * *"` |
152
+ | `deleteBuildAssets` | Delete video recordings and screenshots from disk | `true` |
153
+
154
+ **Example (YAML):**
155
+ ```yaml
156
+ plugin:
157
+ xenon:
158
+ buildCleanupDays: 14
159
+ buildCleanupMaxCount: 50
160
+ buildCleanupSchedule: "0 0 * * *"
161
+ deleteBuildAssets: true
162
+ ```
163
+
164
+ Detailed explanation of how the retention logic works can be found in the **[Data Retention & Maintenance Guide](docs/retention.md)**.
165
+
166
+ See [docs/server-args.md](docs/server-args.md) for all available options.
167
+
168
+ ---
169
+
170
+ ## 📋 Capabilities
171
+
172
+ Xenon uses the `xe:` prefix for its custom capabilities. You can also use `xenon:` as an alternative.
173
+
174
+ ### Session & Build Tracking
175
+
176
+ | Capability | Description | Example |
177
+ |------------|-------------|---------|
178
+ | `xe:build` | Build name for grouping sessions | `"xe:build": "Release-v2.0"` |
179
+ | `xe:name` | Session name for identification | `"xe:name": "Login Test Suite"` |
180
+
181
+ ### Recording & Screenshots
182
+
183
+ | Capability | Description | Default |
184
+ |------------|-------------|---------|
185
+ | `xe:record_video` | Enable video recording | `true` |
186
+ | `xe:screenshot_on_failure` | Capture screenshot on test failure | `true` |
187
+ | `xe:screenshot_on_every_command` | Capture screenshot after each command | `false` |
188
+ | `xe:save_device_logs` | Save device logs (logcat/syslog) | `false` |
189
+
190
+ ### Device Filtering
191
+
192
+ | Capability | Description | Example |
193
+ |------------|-------------|---------|
194
+ | `appium:udids` | Comma-separated list of allowed UDIDs | `"device1,device2"` |
195
+ | `appium:minSDK` | Minimum OS version | `"15"` |
196
+ | `appium:maxSDK` | Maximum OS version | `"17"` |
197
+ | `appium:iPhoneOnly` | Use only iPhone simulators | `true` |
198
+ | `appium:iPadOnly` | Use only iPad simulators | `true` |
199
+ | `appium:filterByHost` | Filter by node IP address | `"192.168.0.100"` |
200
+
201
+ ### Timeouts
202
+
203
+ | Capability | Description | Default |
204
+ |------------|-------------|---------|
205
+ | `appium:deviceAvailabilityTimeout` | Wait time for device availability (ms) | `180000` |
206
+ | `appium:deviceRetryInterval` | Polling interval for device check (ms) | `10000` |
207
+
208
+ ### Example Configuration
209
+
210
+ ```javascript
211
+ const capabilities = {
212
+ platformName: 'iOS',
213
+ 'appium:automationName': 'XCUITest',
214
+ 'appium:app': '/path/to/app.ipa',
215
+
216
+ // Xenon capabilities
217
+ 'xe:build': 'Sprint-42',
218
+ 'xe:name': 'Login Flow Test',
219
+ 'xe:record_video': true,
220
+ 'xe:screenshot_on_failure': true,
221
+ 'xe:save_device_logs': true,
222
+
223
+ // Device filtering
224
+ 'appium:minSDK': '16',
225
+ 'appium:iPhoneOnly': true
226
+ };
227
+ ```
228
+
229
+ ### Custom Execute Script Commands
230
+
231
+ Xenon supports extended control and reporting via the `xenon:` execute script namespace. These commands allow you to interact with the Xenon dashboard and session management directly from your test code.
232
+
233
+ | Command | Description | Example |
234
+ |---------|-------------|---------|
235
+ | `xenon: setSessionStatus` | Mark session as passed/failed in dashboard | `{"status": "passed", "reason": "All steps OK"}` |
236
+ | `xenon: setSessionName` | Update session name at runtime | `{"name": "Step 2: Payment Verification"}` |
237
+ | `xenon: captureEvidence` | Trigger manual screenshot with custom label | `{"reason": "Checkpoint reached", "label": "success"}` |
238
+ | `xenon: addTag` | Add searchable tags to the session | `{"tag": "regression"}` |
239
+ | `xenon: debug` | Send custom debug logs to Xenon dashboard | `{"message": "API Response: 200 OK"}` |
240
+
241
+ See [docs/capabilities.md](docs/capabilities.md) for full usage details.
242
+
243
+ ---
244
+
245
+ ## 🧠 AI Self-Healing
246
+
247
+ Xenon features a best-in-class, 5-tier self-healing system that ensures your tests never fail due to minor UI changes. It automatically intercepts `NoSuchElementError` and attempts to recover the locator using increasingly advanced methods.
248
+
249
+ ### 🛡️ The 5-Tier Strategy
250
+
251
+ | Tier | Provider | Mechanism | Stability |
252
+ |:---|:---|:---|:---|
253
+ | **1** | **Native** | Standard Appium `findElement` | Baseline |
254
+ | **2** | **Fuzzy XML**| **Weighted Signature Matching** (Dice Coefficient) | **85%+** |
255
+ | **3** | **OCR** | Local Text Recognition (Tesseract.js) | High |
256
+ | **4** | **Visual AI**| AI-powered coordinate discovery | High |
257
+ | **5** | **LLM** | Deep Reasoning (Gemini/OpenAI) | Absolute |
258
+
259
+ ### ⚡ Signature-Based Learning (Etalon)
260
+
261
+ Xenon "learns" during every successful run. When an element is found, it captures a persistent **Element Signature (Etalon)**.
262
+ - **Zero Configuration**: Learning is fully automatic and backgrounded.
263
+ - **Persistent Memory**: Signatures are stored in your database (LokiJS or PostgreSQL).
264
+ - **Extreme Precision**: Even if `id`, `text`, or `class` changes, Xenon uses anchor attributes (`content-desc`, `resource-id`) from its memory to find the match with industrial-grade confidence.
265
+
266
+ ### 🎛️ Control & Transparency
267
+
268
+ Xenon provides full visibility and control over its self-healing system:
269
+
270
+ - **Global Toggle**: Enable or disable healing via CLI:
271
+ ```bash
272
+ appium server --use-plugins=xenon --plugin-xenon-enable-self-healing=true
273
+ ```
274
+ - **Live Configuration**: Toggle self-healing directly from the **Xenon Dashboard Settings** at runtime without restarting the server.
275
+ - **Audit Logs**: Every healing event is recorded in the session command history. You can see:
276
+ - **Original Selector**: The locator that failed.
277
+ - **Recovered Selector**: The replacement locator found by Xenon.
278
+ - **Confidence Score**: The mathematical match probability (0-1.0).
279
+ - **Healing Tier**: Which tier (Fuzzy XML, OCR, etc.) performed the recovery.
280
+
281
+ ---
282
+
283
+ ## 📖 API Documentation
284
+
285
+ Xenon provides a comprehensive REST API for device management, session control, and more.
286
+
287
+ ### Swagger UI
288
+
289
+ Access interactive API documentation at:
290
+ ```
291
+ http://localhost:4723/xenon/api-docs
292
+ ```
293
+
294
+ ### OpenAPI Spec
295
+
296
+ Get the raw OpenAPI specification:
297
+ ```
298
+ http://localhost:4723/xenon/api-docs.json
299
+ ```
300
+
301
+ ### API Categories
302
+
303
+ | Category | Base Path | Description |
304
+ |----------|-----------|-------------|
305
+ | **Devices** | `/xenon/api/devices` | Device discovery and management |
306
+ | **Sessions** | `/xenon/api/session` | Session management and logs |
307
+ | **Builds** | `/xenon/api/build` | Build and test execution tracking |
308
+ | **Control** | `/xenon/api/control` | Interactive device control |
309
+ | **Reservations** | `/xenon/api/reservation` | Device reservation for exclusive use |
310
+ | **Applications** | `/xenon/api/apps` | App repository and installation |
311
+ | **Webhooks** | `/xenon/api/webhook` | Notification webhook configuration |
312
+
313
+ ### Key Endpoints
314
+
315
+ #### Devices
316
+ ```bash
317
+ # Get all devices
318
+ GET /xenon/api/devices
319
+
320
+ # Get device by platform
321
+ GET /xenon/api/device/{platform}
322
+
323
+ # Block/Unblock device
324
+ POST /xenon/api/device/{udid}/block
325
+ POST /xenon/api/device/{udid}/unblock
326
+ ```
327
+
328
+ #### Control API
329
+ ```bash
330
+ # Take screenshot
331
+ GET /xenon/api/control/{udid}/screenshot
332
+
333
+ # Tap at coordinates
334
+ POST /xenon/api/control/{udid}/tap
335
+ { "x": 100, "y": 200 }
336
+
337
+ # Swipe gesture
338
+ POST /xenon/api/control/{udid}/swipe
339
+ { "x": 100, "y": 500, "endX": 100, "endY": 100, "duration": 1000 }
340
+
341
+ # Type text
342
+ POST /xenon/api/control/{udid}/text
343
+ { "text": "Hello World" }
344
+
345
+ # Execute shell command (Android)
346
+ POST /xenon/api/control/{udid}/shell
347
+ { "command": "pm list packages" }
348
+
349
+ # Live stream
350
+ GET /xenon/api/control/{udid}/stream
351
+ ```
352
+
353
+ #### Reservations
354
+ ```bash
355
+ # Reserve a device
356
+ POST /xenon/api/reservation
357
+ { "udid": "...", "host": "...", "reservedBy": "John", "duration": "2h" }
358
+
359
+ # Release reservation
360
+ DELETE /xenon/api/reservation/{udid}/{host}
361
+
362
+ # Extend reservation
363
+ POST /xenon/api/reservation/{udid}/{host}/extend
364
+ { "duration": "1h" }
365
+ ```
366
+
367
+ ---
368
+
369
+ ## 🎨 Dashboard
370
+
371
+ Access the dashboard at `http://localhost:4723/xenon/`
372
+
373
+ <p align="center">
374
+ <img src="assets/dashboard.png" alt="Xenon Dashboard" width="100%">
375
+ </p>
376
+
377
+ ### Views
378
+
379
+ | View | Description |
380
+ |------|-------------|
381
+ | **Devices** | Real-time device grid with status indicators |
382
+ | **Sessions** | Active and historical session management |
383
+ | **Builds** | Test runs grouped by build identifier |
384
+ | **Control** | Interactive device control interface |
385
+
386
+ ---
387
+
388
+ ## 📚 Documentation
389
+
390
+ The full documentation is available at:
391
+ **[https://xenon-docs.vercel.app/](https://xenon-docs.vercel.app/)**
392
+
393
+ ### Quick Links
394
+ - [Installation Guide](docs/installation.md)
395
+ - [Configuration Options](docs/configuration.md)
396
+ - [API Reference](docs/api.md)
397
+ - [Troubleshooting](docs/troubleshooting.md)
398
+
399
+ ---
400
+
401
+ ## 🏗️ Development
402
+
403
+ ```bash
404
+ # Clone and install
405
+ git clone https://github.com/xenon-platform/xenon.git
406
+ cd xenon
407
+ npm install
408
+
409
+ # Build everything (Plugin + Dashboard)
410
+ npm run build:all
411
+
412
+ # High-velocity development loop
413
+ # (Auto-rebuilds and restarts Appium server)
414
+ npm run dev
415
+
416
+ # Run tests
417
+ npm run test:all # Unit tests
418
+ npm run test:android # Android integration
419
+ npm run test:ios # iOS integration
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 🤝 Contributing
425
+
426
+ We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
427
+
428
+ ### Contributors
429
+
430
+ <a href="https://github.com/xenon-platform/xenon/graphs/contributors">
431
+ <img src="https://contrib.rocks/image?repo=xenon-platform/xenon" />
432
+ </a>
433
+
434
+ ---
435
+
436
+ ## 📜 License
437
+
438
+ ISC License - See [LICENSE](LICENSE) for details.
439
+
440
+ ---
441
+
442
+ <p align="center">
443
+ <strong>Xenon</strong> - Stable. Reliable. Intelligent.
444
+ <br>
445
+ <em>Named after Element 54 - the noble gas known for stability</em>
446
+ </p>
@@ -0,0 +1,207 @@
1
+ {
2
+ "name": "@xenon-device-management/xenon",
3
+ "version": "1.1.0",
4
+ "description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
5
+ "main": "./lib/src/index.js",
6
+ "exports": {
7
+ ".": "./lib/src/index.js",
8
+ "./schema.json": "./schema.json",
9
+ "./package.json": "./package.json"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc -b && npm run build:copy",
13
+ "build:all": "npm run build:xenon && npm run build",
14
+ "build:copy": "rm -rf lib/public && mkdir -p lib && cp -R src/public lib/ && cp schema.json lib/",
15
+ "build:schema": "node scripts/generate-types-from-schema.js",
16
+ "build:xenon": "sh scripts/build-xenon.sh",
17
+ "dev": "npm run db:migrate && npm run build && npm run plugin:reinstall && npm run server",
18
+ "server": "export APPIUM_HOME=/tmp/xenon-home && npx appium server -ka 800 --use-plugins=xenon -pa /wd/hub --plugin-xenon-platform=both --plugin-xenon-enable-dashboard",
19
+ "plugin:install": "appium plugin install --source=local $(pwd)",
20
+ "plugin:reinstall": "export APPIUM_HOME=/tmp/xenon-home && (appium plugin uninstall xenon || exit 0) && npm run plugin:install",
21
+ "test": "mocha",
22
+ "test:all": "NODE_ENV=test mocha \"test/unit/**/*.{spec,test}.{ts,js}\" --plugin-xenon-platform=both",
23
+ "test:e2e": "mocha \"test/e2e/plugin.spec.*\" --timeout 300000",
24
+ "test:e2e:hub": "mocha \"test/e2e/hubnode/*.spec.ts\" --plugin-xenon-platform=both --timeout 300000",
25
+ "test:android": "mocha \"test/integration/androidDevices.spec.ts\"",
26
+ "test:ios": "mocha \"test/integration/ios/*.spec.ts\"",
27
+ "test:coverage": "nyc npm run test",
28
+ "lint": "eslint . --ext .ts,.tsx --fix",
29
+ "format": "prettier --write \"{src,web,test}/**/*.{ts,tsx,json,md}\" --single-quote",
30
+ "db:migrate": "path-exists lib/src/scripts/initialize-database.js && node lib/src/scripts/initialize-database.js || ts-node src/scripts/initialize-database.ts",
31
+ "db:generate": "ts-node src/scripts/generate-database-migration.ts",
32
+ "prepublishOnly": "npm run build:all"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/xenon-platform/xenon"
37
+ },
38
+ "contributors": [
39
+ {
40
+ "name": "Rabindra Biswal",
41
+ "email": "rabindrabiswal1@gmail.com"
42
+ }
43
+ ],
44
+ "license": "ISC",
45
+ "bugs": {
46
+ "url": "https://github.com/xenon-platform/xenon/issues"
47
+ },
48
+ "homepage": "https://github.com/xenon-platform/xenon#readme",
49
+ "dependencies": {
50
+ "@anthropic-ai/sdk": "^0.72.1",
51
+ "@appium/base-plugin": "^2.2.22",
52
+ "@appium/types": "^0.14.1",
53
+ "@devicefarmer/adbkit": "^3.2.5",
54
+ "@ffmpeg-installer/ffmpeg": "^1.1.0",
55
+ "@fortawesome/fontawesome-svg-core": "^7.1.0",
56
+ "@fortawesome/free-brands-svg-icons": "^7.1.0",
57
+ "@fortawesome/react-fontawesome": "^3.1.1",
58
+ "@google/generative-ai": "^0.24.1",
59
+ "@opentelemetry/api": "^1.9.0",
60
+ "@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
61
+ "@opentelemetry/resources": "^2.5.0",
62
+ "@opentelemetry/sdk-node": "^0.211.0",
63
+ "@opentelemetry/semantic-conventions": "^1.39.0",
64
+ "@prisma/client": "^5.4.1",
65
+ "@types/appium-adb": "^9.10.4",
66
+ "@types/express-fileupload": "^1.5.1",
67
+ "@types/node-persist": "^3.1.5",
68
+ "appium-adb": "^11.0.3",
69
+ "appium-chromedriver": "^5.6.19",
70
+ "appium-ios-device": "^2.7.6",
71
+ "async-lock": "^1.2.8",
72
+ "async-wait-until": "^2.0.12",
73
+ "axios": "^0.27.2",
74
+ "cors": "^2.8.5",
75
+ "download": "^8.0.0",
76
+ "express": "^4.17.3",
77
+ "express-fileupload": "^1.5.2",
78
+ "fast-xml-parser": "^5.3.4",
79
+ "fs-extra": "^11.1.1",
80
+ "get-port": "^5.1.1",
81
+ "http-proxy-agent": "7.0.0",
82
+ "http-proxy-middleware": "^3.0.0-beta.1",
83
+ "https-proxy-agent": "7.0.2",
84
+ "ip": "^1.1.8",
85
+ "jsonschema": "1.4.1",
86
+ "lodash": "^4.17.21",
87
+ "lokijs": "^1.5.12",
88
+ "mjpeg-proxy": "^0.3.0",
89
+ "node-abort-controller": "^3.1.1",
90
+ "node-cache": "^5.1.2",
91
+ "node-persist": "^3.1.3",
92
+ "node-schedule": "^2.1.1",
93
+ "node-simctl": "^7.3.13",
94
+ "normalize-url": "6.1.0",
95
+ "nyc": "^15.1.0",
96
+ "openai": "^6.17.0",
97
+ "ora": "5.4.1",
98
+ "path-exists-cli": "^2.0.0",
99
+ "prisma": "^5.4.1",
100
+ "ramda": "^0.28.0",
101
+ "reflect-metadata": "^0.1.13",
102
+ "resiliotree": "^1.1.3",
103
+ "semver": "^7.5.4",
104
+ "sharp": "^0.34.5",
105
+ "socket.io": "^4.8.3",
106
+ "socket.io-client": "^4.8.3",
107
+ "swagger-jsdoc": "^6.2.8",
108
+ "swagger-ui-express": "^5.0.1",
109
+ "tcp-port-used": "^1.0.2",
110
+ "tesseract.js": "^7.0.0",
111
+ "typedi": "^0.10.0",
112
+ "unzipper": "^0.10.14",
113
+ "usbmux": "^0.1.0",
114
+ "uuid": "^8.3.2",
115
+ "xmldom": "^0.6.0",
116
+ "xpath": "^0.0.34",
117
+ "yargs": "^17.7.2",
118
+ "zod": "^4.3.6"
119
+ },
120
+ "peerDependencies": {
121
+ "appium": "^3.1.1"
122
+ },
123
+ "devDependencies": {
124
+ "@appium/docutils": "^0.4.11",
125
+ "@appium/fake-driver": "^6.0.1",
126
+ "@appium/plugin-test-support": "^1.0.3",
127
+ "@babel/core": "7.23.9",
128
+ "@babel/plugin-proposal-class-properties": "7.18.6",
129
+ "@types/async-lock": "1.4.2",
130
+ "@types/bluebird": "^3.5.42",
131
+ "@types/chai": "4.3.10",
132
+ "@types/chai-as-promised": "^7.1.8",
133
+ "@types/express": "4.17.21",
134
+ "@types/fs-extra": "^11.0.0",
135
+ "@types/ip": "^1.1.2",
136
+ "@types/js-yaml": "^4.0.9",
137
+ "@types/lodash": "4.14.202",
138
+ "@types/lokijs": "1.5.14",
139
+ "@types/mocha": "9.1.1",
140
+ "@types/node-schedule": "1.3.2",
141
+ "@types/sinon": "^17.0.2",
142
+ "@types/sinon-chai": "^3.2.12",
143
+ "@types/swagger-jsdoc": "^6.0.4",
144
+ "@types/swagger-ui-express": "^4.1.8",
145
+ "@types/tcp-port-used": "1.0.4",
146
+ "@types/uuid": "8.3.4",
147
+ "@types/yargs": "17.0.32",
148
+ "@typescript-eslint/eslint-plugin": "5.62.0",
149
+ "@typescript-eslint/parser": "5.62.0",
150
+ "@wdio/types": "^8.24.2",
151
+ "appium": "3.1.1",
152
+ "appium-uiautomator2-driver": "^5.0.3",
153
+ "appium-xcuitest-driver": "^10.1.2",
154
+ "babel-eslint": "10.1.0",
155
+ "chai": "4.3.10",
156
+ "chai-as-promised": "^7.1.1",
157
+ "chai-exclude": "^2.1.0",
158
+ "dotenv": "^16.3.1",
159
+ "eslint": "8.52.0",
160
+ "eslint-config-prettier": "9.0.0",
161
+ "eslint-plugin-import": "2.29.1",
162
+ "eslint-plugin-prettier": "^5.0.0",
163
+ "husky": "7.0.4",
164
+ "js-yaml": "^4.1.0",
165
+ "json-schema-to-typescript": "^15.0.4",
166
+ "lint-staged": "15.0.2",
167
+ "mocha": "9.2.2",
168
+ "prettier": "^3.0.3",
169
+ "ramda": "0.29.1",
170
+ "sinon": "17.0.0",
171
+ "sinon-chai": "^3.7.0",
172
+ "ts-node": "10.9.1",
173
+ "typescript": "^5.5.4",
174
+ "vite": "^4.5.0",
175
+ "webdriverio": "^8.20.4"
176
+ },
177
+ "appium": {
178
+ "pluginName": "xenon",
179
+ "mainClass": "XenonPlugin",
180
+ "schema": "schema.json"
181
+ },
182
+ "engines": {
183
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0",
184
+ "npm": ">=8"
185
+ },
186
+ "lint-staged": {
187
+ "src/*.{js,jsx,ts,tsx,json,css,scss,md}": [
188
+ "npm run prettier",
189
+ "git add"
190
+ ]
191
+ },
192
+ "husky": {
193
+ "hooks": {
194
+ "pre-commit": "lint-staged",
195
+ "pre-push": "npm run test"
196
+ }
197
+ },
198
+ "files": [
199
+ "lib",
200
+ "scripts",
201
+ "prisma",
202
+ "schema.json"
203
+ ],
204
+ "typedoc": {
205
+ "entryPoint": "lib/src/index.js"
206
+ }
207
+ }
@@ -0,0 +1,11 @@
1
+ import{c,j as e,g as l}from"./index-ByQwMN5T.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 i=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]],h=c("rotate-ccw",i);/**
7
+ * @license lucide-react v0.555.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const x=[["path",{d:"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z",key:"1c8476"}],["path",{d:"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7",key:"1ydtos"}],["path",{d:"M7 3v4a1 1 0 0 0 1 1h7",key:"t51u73"}]],j=c("save",x),b=({onSave:o,onDiscard:d,onRestoreDefaults:t,isSaving:s,isValidating:a=!1,saveLabel:n="Save Configuration",restoreLabel:r="Restore Defaults"})=>e.jsxs("div",{className:"settings-footer",children:[e.jsx("div",{className:"footer-left",children:t&&e.jsxs("button",{className:"reset-to-defaults-btn",onClick:t,disabled:s||a,children:[e.jsx(h,{size:16}),r]})}),e.jsxs("div",{className:"footer-right",children:[e.jsx("button",{className:"reset-btn",onClick:d,disabled:s||a,children:"Discard"}),e.jsxs("button",{className:"save-btn",onClick:o,disabled:s||a,children:[s?e.jsx(l,{className:"animate-spin",size:18}):e.jsx(j,{size:18}),s?"Saving...":n]})]})]});export{b as A};