@metamask/device-mcp 0.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 (315) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +266 -0
  3. package/dist/backends/adb-backend.cjs +442 -0
  4. package/dist/backends/adb-backend.cjs.map +1 -0
  5. package/dist/backends/adb-backend.d.cts +35 -0
  6. package/dist/backends/adb-backend.d.cts.map +1 -0
  7. package/dist/backends/adb-backend.d.mts +35 -0
  8. package/dist/backends/adb-backend.d.mts.map +1 -0
  9. package/dist/backends/adb-backend.mjs +436 -0
  10. package/dist/backends/adb-backend.mjs.map +1 -0
  11. package/dist/backends/appium-backend.cjs +518 -0
  12. package/dist/backends/appium-backend.cjs.map +1 -0
  13. package/dist/backends/appium-backend.d.cts +36 -0
  14. package/dist/backends/appium-backend.d.cts.map +1 -0
  15. package/dist/backends/appium-backend.d.mts +36 -0
  16. package/dist/backends/appium-backend.d.mts.map +1 -0
  17. package/dist/backends/appium-backend.mjs +512 -0
  18. package/dist/backends/appium-backend.mjs.map +1 -0
  19. package/dist/backends/idb-backend.cjs +442 -0
  20. package/dist/backends/idb-backend.cjs.map +1 -0
  21. package/dist/backends/idb-backend.d.cts +35 -0
  22. package/dist/backends/idb-backend.d.cts.map +1 -0
  23. package/dist/backends/idb-backend.d.mts +35 -0
  24. package/dist/backends/idb-backend.d.mts.map +1 -0
  25. package/dist/backends/idb-backend.mjs +436 -0
  26. package/dist/backends/idb-backend.mjs.map +1 -0
  27. package/dist/backends/index.cjs +134 -0
  28. package/dist/backends/index.cjs.map +1 -0
  29. package/dist/backends/index.d.cts +16 -0
  30. package/dist/backends/index.d.cts.map +1 -0
  31. package/dist/backends/index.d.mts +16 -0
  32. package/dist/backends/index.d.mts.map +1 -0
  33. package/dist/backends/index.mjs +126 -0
  34. package/dist/backends/index.mjs.map +1 -0
  35. package/dist/backends/session-file.cjs +62 -0
  36. package/dist/backends/session-file.cjs.map +1 -0
  37. package/dist/backends/session-file.d.cts +24 -0
  38. package/dist/backends/session-file.d.cts.map +1 -0
  39. package/dist/backends/session-file.d.mts +24 -0
  40. package/dist/backends/session-file.d.mts.map +1 -0
  41. package/dist/backends/session-file.mjs +59 -0
  42. package/dist/backends/session-file.mjs.map +1 -0
  43. package/dist/backends/types.cjs +3 -0
  44. package/dist/backends/types.cjs.map +1 -0
  45. package/dist/backends/types.d.cts +93 -0
  46. package/dist/backends/types.d.cts.map +1 -0
  47. package/dist/backends/types.d.mts +93 -0
  48. package/dist/backends/types.d.mts.map +1 -0
  49. package/dist/backends/types.mjs +2 -0
  50. package/dist/backends/types.mjs.map +1 -0
  51. package/dist/backends/webdriver-client.cjs +167 -0
  52. package/dist/backends/webdriver-client.cjs.map +1 -0
  53. package/dist/backends/webdriver-client.d.cts +55 -0
  54. package/dist/backends/webdriver-client.d.cts.map +1 -0
  55. package/dist/backends/webdriver-client.d.mts +55 -0
  56. package/dist/backends/webdriver-client.d.mts.map +1 -0
  57. package/dist/backends/webdriver-client.mjs +162 -0
  58. package/dist/backends/webdriver-client.mjs.map +1 -0
  59. package/dist/cli/device-mcp.cjs +20 -0
  60. package/dist/cli/device-mcp.cjs.map +1 -0
  61. package/dist/cli/device-mcp.d.cts +3 -0
  62. package/dist/cli/device-mcp.d.cts.map +1 -0
  63. package/dist/cli/device-mcp.d.mts +3 -0
  64. package/dist/cli/device-mcp.d.mts.map +1 -0
  65. package/dist/cli/device-mcp.mjs +18 -0
  66. package/dist/cli/device-mcp.mjs.map +1 -0
  67. package/dist/index.cjs +9 -0
  68. package/dist/index.cjs.map +1 -0
  69. package/dist/index.d.cts +5 -0
  70. package/dist/index.d.cts.map +1 -0
  71. package/dist/index.d.mts +5 -0
  72. package/dist/index.d.mts.map +1 -0
  73. package/dist/index.mjs +3 -0
  74. package/dist/index.mjs.map +1 -0
  75. package/dist/server.cjs +43 -0
  76. package/dist/server.cjs.map +1 -0
  77. package/dist/server.d.cts +4 -0
  78. package/dist/server.d.cts.map +1 -0
  79. package/dist/server.d.mts +4 -0
  80. package/dist/server.d.mts.map +1 -0
  81. package/dist/server.mjs +40 -0
  82. package/dist/server.mjs.map +1 -0
  83. package/dist/tools/alert-text.cjs +25 -0
  84. package/dist/tools/alert-text.cjs.map +1 -0
  85. package/dist/tools/alert-text.d.cts +4 -0
  86. package/dist/tools/alert-text.d.cts.map +1 -0
  87. package/dist/tools/alert-text.d.mts +4 -0
  88. package/dist/tools/alert-text.d.mts.map +1 -0
  89. package/dist/tools/alert-text.mjs +22 -0
  90. package/dist/tools/alert-text.mjs.map +1 -0
  91. package/dist/tools/app-state.cjs +40 -0
  92. package/dist/tools/app-state.cjs.map +1 -0
  93. package/dist/tools/app-state.d.cts +4 -0
  94. package/dist/tools/app-state.d.cts.map +1 -0
  95. package/dist/tools/app-state.d.mts +4 -0
  96. package/dist/tools/app-state.d.mts.map +1 -0
  97. package/dist/tools/app-state.mjs +37 -0
  98. package/dist/tools/app-state.mjs.map +1 -0
  99. package/dist/tools/clipboard.cjs +42 -0
  100. package/dist/tools/clipboard.cjs.map +1 -0
  101. package/dist/tools/clipboard.d.cts +4 -0
  102. package/dist/tools/clipboard.d.cts.map +1 -0
  103. package/dist/tools/clipboard.d.mts +4 -0
  104. package/dist/tools/clipboard.d.mts.map +1 -0
  105. package/dist/tools/clipboard.mjs +39 -0
  106. package/dist/tools/clipboard.mjs.map +1 -0
  107. package/dist/tools/close-app.cjs +25 -0
  108. package/dist/tools/close-app.cjs.map +1 -0
  109. package/dist/tools/close-app.d.cts +4 -0
  110. package/dist/tools/close-app.d.cts.map +1 -0
  111. package/dist/tools/close-app.d.mts +4 -0
  112. package/dist/tools/close-app.d.mts.map +1 -0
  113. package/dist/tools/close-app.mjs +22 -0
  114. package/dist/tools/close-app.mjs.map +1 -0
  115. package/dist/tools/context.cjs +52 -0
  116. package/dist/tools/context.cjs.map +1 -0
  117. package/dist/tools/context.d.cts +4 -0
  118. package/dist/tools/context.d.cts.map +1 -0
  119. package/dist/tools/context.d.mts +4 -0
  120. package/dist/tools/context.d.mts.map +1 -0
  121. package/dist/tools/context.mjs +49 -0
  122. package/dist/tools/context.mjs.map +1 -0
  123. package/dist/tools/device-info.cjs +34 -0
  124. package/dist/tools/device-info.cjs.map +1 -0
  125. package/dist/tools/device-info.d.cts +4 -0
  126. package/dist/tools/device-info.d.cts.map +1 -0
  127. package/dist/tools/device-info.d.mts +4 -0
  128. package/dist/tools/device-info.d.mts.map +1 -0
  129. package/dist/tools/device-info.mjs +31 -0
  130. package/dist/tools/device-info.mjs.map +1 -0
  131. package/dist/tools/dismiss-alert.cjs +34 -0
  132. package/dist/tools/dismiss-alert.cjs.map +1 -0
  133. package/dist/tools/dismiss-alert.d.cts +4 -0
  134. package/dist/tools/dismiss-alert.d.cts.map +1 -0
  135. package/dist/tools/dismiss-alert.d.mts +4 -0
  136. package/dist/tools/dismiss-alert.d.mts.map +1 -0
  137. package/dist/tools/dismiss-alert.mjs +31 -0
  138. package/dist/tools/dismiss-alert.mjs.map +1 -0
  139. package/dist/tools/dismiss-keyboard.cjs +23 -0
  140. package/dist/tools/dismiss-keyboard.cjs.map +1 -0
  141. package/dist/tools/dismiss-keyboard.d.cts +4 -0
  142. package/dist/tools/dismiss-keyboard.d.cts.map +1 -0
  143. package/dist/tools/dismiss-keyboard.d.mts +4 -0
  144. package/dist/tools/dismiss-keyboard.d.mts.map +1 -0
  145. package/dist/tools/dismiss-keyboard.mjs +20 -0
  146. package/dist/tools/dismiss-keyboard.mjs.map +1 -0
  147. package/dist/tools/generate-locators.cjs +33 -0
  148. package/dist/tools/generate-locators.cjs.map +1 -0
  149. package/dist/tools/generate-locators.d.cts +4 -0
  150. package/dist/tools/generate-locators.d.cts.map +1 -0
  151. package/dist/tools/generate-locators.d.mts +4 -0
  152. package/dist/tools/generate-locators.d.mts.map +1 -0
  153. package/dist/tools/generate-locators.mjs +30 -0
  154. package/dist/tools/generate-locators.mjs.map +1 -0
  155. package/dist/tools/index.cjs +50 -0
  156. package/dist/tools/index.cjs.map +1 -0
  157. package/dist/tools/index.d.cts +24 -0
  158. package/dist/tools/index.d.cts.map +1 -0
  159. package/dist/tools/index.d.mts +24 -0
  160. package/dist/tools/index.d.mts.map +1 -0
  161. package/dist/tools/index.mjs +24 -0
  162. package/dist/tools/index.mjs.map +1 -0
  163. package/dist/tools/logs.cjs +48 -0
  164. package/dist/tools/logs.cjs.map +1 -0
  165. package/dist/tools/logs.d.cts +4 -0
  166. package/dist/tools/logs.d.cts.map +1 -0
  167. package/dist/tools/logs.d.mts +4 -0
  168. package/dist/tools/logs.d.mts.map +1 -0
  169. package/dist/tools/logs.mjs +45 -0
  170. package/dist/tools/logs.mjs.map +1 -0
  171. package/dist/tools/long-press.cjs +38 -0
  172. package/dist/tools/long-press.cjs.map +1 -0
  173. package/dist/tools/long-press.d.cts +4 -0
  174. package/dist/tools/long-press.d.cts.map +1 -0
  175. package/dist/tools/long-press.d.mts +4 -0
  176. package/dist/tools/long-press.d.mts.map +1 -0
  177. package/dist/tools/long-press.mjs +35 -0
  178. package/dist/tools/long-press.mjs.map +1 -0
  179. package/dist/tools/open-app.cjs +26 -0
  180. package/dist/tools/open-app.cjs.map +1 -0
  181. package/dist/tools/open-app.d.cts +4 -0
  182. package/dist/tools/open-app.d.cts.map +1 -0
  183. package/dist/tools/open-app.d.mts +4 -0
  184. package/dist/tools/open-app.d.mts.map +1 -0
  185. package/dist/tools/open-app.mjs +23 -0
  186. package/dist/tools/open-app.mjs.map +1 -0
  187. package/dist/tools/press-button.cjs +30 -0
  188. package/dist/tools/press-button.cjs.map +1 -0
  189. package/dist/tools/press-button.d.cts +4 -0
  190. package/dist/tools/press-button.d.cts.map +1 -0
  191. package/dist/tools/press-button.d.mts +4 -0
  192. package/dist/tools/press-button.d.mts.map +1 -0
  193. package/dist/tools/press-button.mjs +27 -0
  194. package/dist/tools/press-button.mjs.map +1 -0
  195. package/dist/tools/screen-recording.cjs +46 -0
  196. package/dist/tools/screen-recording.cjs.map +1 -0
  197. package/dist/tools/screen-recording.d.cts +4 -0
  198. package/dist/tools/screen-recording.d.cts.map +1 -0
  199. package/dist/tools/screen-recording.d.mts +4 -0
  200. package/dist/tools/screen-recording.d.mts.map +1 -0
  201. package/dist/tools/screen-recording.mjs +43 -0
  202. package/dist/tools/screen-recording.mjs.map +1 -0
  203. package/dist/tools/screenshot.cjs +42 -0
  204. package/dist/tools/screenshot.cjs.map +1 -0
  205. package/dist/tools/screenshot.d.cts +4 -0
  206. package/dist/tools/screenshot.d.cts.map +1 -0
  207. package/dist/tools/screenshot.d.mts +4 -0
  208. package/dist/tools/screenshot.d.mts.map +1 -0
  209. package/dist/tools/screenshot.mjs +39 -0
  210. package/dist/tools/screenshot.mjs.map +1 -0
  211. package/dist/tools/scroll-to-element.cjs +56 -0
  212. package/dist/tools/scroll-to-element.cjs.map +1 -0
  213. package/dist/tools/scroll-to-element.d.cts +4 -0
  214. package/dist/tools/scroll-to-element.d.cts.map +1 -0
  215. package/dist/tools/scroll-to-element.d.mts +4 -0
  216. package/dist/tools/scroll-to-element.d.mts.map +1 -0
  217. package/dist/tools/scroll-to-element.mjs +53 -0
  218. package/dist/tools/scroll-to-element.mjs.map +1 -0
  219. package/dist/tools/shared.cjs +11 -0
  220. package/dist/tools/shared.cjs.map +1 -0
  221. package/dist/tools/shared.d.cts +8 -0
  222. package/dist/tools/shared.d.cts.map +1 -0
  223. package/dist/tools/shared.d.mts +8 -0
  224. package/dist/tools/shared.d.mts.map +1 -0
  225. package/dist/tools/shared.mjs +8 -0
  226. package/dist/tools/shared.mjs.map +1 -0
  227. package/dist/tools/snapshot.cjs +37 -0
  228. package/dist/tools/snapshot.cjs.map +1 -0
  229. package/dist/tools/snapshot.d.cts +4 -0
  230. package/dist/tools/snapshot.d.cts.map +1 -0
  231. package/dist/tools/snapshot.d.mts +4 -0
  232. package/dist/tools/snapshot.d.mts.map +1 -0
  233. package/dist/tools/snapshot.mjs +34 -0
  234. package/dist/tools/snapshot.mjs.map +1 -0
  235. package/dist/tools/swipe.cjs +39 -0
  236. package/dist/tools/swipe.cjs.map +1 -0
  237. package/dist/tools/swipe.d.cts +4 -0
  238. package/dist/tools/swipe.d.cts.map +1 -0
  239. package/dist/tools/swipe.d.mts +4 -0
  240. package/dist/tools/swipe.d.mts.map +1 -0
  241. package/dist/tools/swipe.mjs +36 -0
  242. package/dist/tools/swipe.mjs.map +1 -0
  243. package/dist/tools/tap-coordinates.cjs +27 -0
  244. package/dist/tools/tap-coordinates.cjs.map +1 -0
  245. package/dist/tools/tap-coordinates.d.cts +4 -0
  246. package/dist/tools/tap-coordinates.d.cts.map +1 -0
  247. package/dist/tools/tap-coordinates.d.mts +4 -0
  248. package/dist/tools/tap-coordinates.d.mts.map +1 -0
  249. package/dist/tools/tap-coordinates.mjs +24 -0
  250. package/dist/tools/tap-coordinates.mjs.map +1 -0
  251. package/dist/tools/tap-element.cjs +46 -0
  252. package/dist/tools/tap-element.cjs.map +1 -0
  253. package/dist/tools/tap-element.d.cts +4 -0
  254. package/dist/tools/tap-element.d.cts.map +1 -0
  255. package/dist/tools/tap-element.d.mts +4 -0
  256. package/dist/tools/tap-element.d.mts.map +1 -0
  257. package/dist/tools/tap-element.mjs +43 -0
  258. package/dist/tools/tap-element.mjs.map +1 -0
  259. package/dist/tools/type-text.cjs +32 -0
  260. package/dist/tools/type-text.cjs.map +1 -0
  261. package/dist/tools/type-text.d.cts +4 -0
  262. package/dist/tools/type-text.d.cts.map +1 -0
  263. package/dist/tools/type-text.d.mts +4 -0
  264. package/dist/tools/type-text.d.mts.map +1 -0
  265. package/dist/tools/type-text.mjs +29 -0
  266. package/dist/tools/type-text.mjs.map +1 -0
  267. package/dist/tools/wait-for.cjs +51 -0
  268. package/dist/tools/wait-for.cjs.map +1 -0
  269. package/dist/tools/wait-for.d.cts +4 -0
  270. package/dist/tools/wait-for.d.cts.map +1 -0
  271. package/dist/tools/wait-for.d.mts +4 -0
  272. package/dist/tools/wait-for.d.mts.map +1 -0
  273. package/dist/tools/wait-for.mjs +48 -0
  274. package/dist/tools/wait-for.mjs.map +1 -0
  275. package/dist/tools/window-size.cjs +29 -0
  276. package/dist/tools/window-size.cjs.map +1 -0
  277. package/dist/tools/window-size.d.cts +4 -0
  278. package/dist/tools/window-size.d.cts.map +1 -0
  279. package/dist/tools/window-size.d.mts +4 -0
  280. package/dist/tools/window-size.d.mts.map +1 -0
  281. package/dist/tools/window-size.mjs +26 -0
  282. package/dist/tools/window-size.mjs.map +1 -0
  283. package/dist/utils/alert-labels.cjs +26 -0
  284. package/dist/utils/alert-labels.cjs.map +1 -0
  285. package/dist/utils/alert-labels.d.cts +3 -0
  286. package/dist/utils/alert-labels.d.cts.map +1 -0
  287. package/dist/utils/alert-labels.d.mts +3 -0
  288. package/dist/utils/alert-labels.d.mts.map +1 -0
  289. package/dist/utils/alert-labels.mjs +23 -0
  290. package/dist/utils/alert-labels.mjs.map +1 -0
  291. package/dist/utils/element.cjs +212 -0
  292. package/dist/utils/element.cjs.map +1 -0
  293. package/dist/utils/element.d.cts +24 -0
  294. package/dist/utils/element.d.cts.map +1 -0
  295. package/dist/utils/element.d.mts +24 -0
  296. package/dist/utils/element.d.mts.map +1 -0
  297. package/dist/utils/element.mjs +203 -0
  298. package/dist/utils/element.mjs.map +1 -0
  299. package/dist/utils/exec.cjs +57 -0
  300. package/dist/utils/exec.cjs.map +1 -0
  301. package/dist/utils/exec.d.cts +23 -0
  302. package/dist/utils/exec.d.cts.map +1 -0
  303. package/dist/utils/exec.d.mts +23 -0
  304. package/dist/utils/exec.d.mts.map +1 -0
  305. package/dist/utils/exec.mjs +52 -0
  306. package/dist/utils/exec.mjs.map +1 -0
  307. package/dist/utils/platform.cjs +93 -0
  308. package/dist/utils/platform.cjs.map +1 -0
  309. package/dist/utils/platform.d.cts +8 -0
  310. package/dist/utils/platform.d.cts.map +1 -0
  311. package/dist/utils/platform.d.mts +8 -0
  312. package/dist/utils/platform.d.mts.map +1 -0
  313. package/dist/utils/platform.mjs +90 -0
  314. package/dist/utils/platform.mjs.map +1 -0
  315. package/package.json +106 -0
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _AppiumBackend_instances, _AppiumBackend_client, _AppiumBackend_config, _AppiumBackend_recording, _AppiumBackend_recordingOutputPath, _AppiumBackend_getHierarchy, _AppiumBackend_getIosHierarchy, _AppiumBackend_requireClient;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AppiumBackend = void 0;
16
+ exports.parseAppiumAndroidHierarchy = parseAppiumAndroidHierarchy;
17
+ exports.parseAppiumIosHierarchy = parseAppiumIosHierarchy;
18
+ const node_fs_1 = require("node:fs");
19
+ const node_path_1 = require("node:path");
20
+ const webdriver_client_js_1 = require("./webdriver-client.cjs");
21
+ const element_js_1 = require("../utils/element.cjs");
22
+ class AppiumBackend {
23
+ constructor(config) {
24
+ _AppiumBackend_instances.add(this);
25
+ _AppiumBackend_client.set(this, null);
26
+ _AppiumBackend_config.set(this, void 0);
27
+ _AppiumBackend_recording.set(this, false);
28
+ _AppiumBackend_recordingOutputPath.set(this, null);
29
+ __classPrivateFieldSet(this, _AppiumBackend_config, config, "f");
30
+ this.platform = config.platform;
31
+ }
32
+ async ensureConnected() {
33
+ if (__classPrivateFieldGet(this, _AppiumBackend_client, "f")) {
34
+ return;
35
+ }
36
+ if (__classPrivateFieldGet(this, _AppiumBackend_config, "f").mode === 'attach') {
37
+ __classPrivateFieldSet(this, _AppiumBackend_client, new webdriver_client_js_1.WebDriverClient(__classPrivateFieldGet(this, _AppiumBackend_config, "f").appiumUrl, __classPrivateFieldGet(this, _AppiumBackend_config, "f").sessionId, __classPrivateFieldGet(this, _AppiumBackend_config, "f").auth), "f");
38
+ await __classPrivateFieldGet(this, _AppiumBackend_client, "f").getStatus();
39
+ }
40
+ else {
41
+ const { client } = await (0, webdriver_client_js_1.createSession)(__classPrivateFieldGet(this, _AppiumBackend_config, "f").appiumUrl, __classPrivateFieldGet(this, _AppiumBackend_config, "f").capabilities, __classPrivateFieldGet(this, _AppiumBackend_config, "f").auth);
42
+ __classPrivateFieldSet(this, _AppiumBackend_client, client, "f");
43
+ }
44
+ }
45
+ async getDeviceInfo() {
46
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
47
+ const details = await client.getSessionDetails();
48
+ const caps = (details.capabilities ?? details);
49
+ return {
50
+ platform: this.platform,
51
+ deviceId: caps.udid ?? client.sessionId,
52
+ name: caps.deviceName ?? 'Appium Device',
53
+ osVersion: caps.platformVersion ?? 'Unknown',
54
+ state: 'connected',
55
+ };
56
+ }
57
+ async snapshot() {
58
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
59
+ const raw = await __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_getHierarchy).call(this, client);
60
+ const hierarchy = this.platform === 'ios'
61
+ ? parseAppiumIosHierarchy(raw)
62
+ : parseAppiumAndroidHierarchy(raw);
63
+ return {
64
+ platform: this.platform,
65
+ hierarchy,
66
+ raw,
67
+ timestamp: Date.now(),
68
+ };
69
+ }
70
+ async tapElement(query) {
71
+ const snapshot = await this.snapshot();
72
+ const element = (0, element_js_1.findElement)(snapshot.hierarchy, query);
73
+ if (!element) {
74
+ throw new Error(`Element not found: ${JSON.stringify(query)}\n` +
75
+ 'Use device_snapshot to inspect the current UI hierarchy.');
76
+ }
77
+ const targetX = Math.round(element.frame.x + element.frame.width / 2);
78
+ const targetY = Math.round(element.frame.y + element.frame.height / 2);
79
+ await this.tapCoordinates(targetX, targetY);
80
+ return {
81
+ success: true,
82
+ x: targetX,
83
+ y: targetY,
84
+ targetDescription: (0, element_js_1.describeElement)(element),
85
+ };
86
+ }
87
+ async tapCoordinates(targetX, targetY) {
88
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
89
+ await client.performActions([
90
+ {
91
+ type: 'pointer',
92
+ id: 'finger1',
93
+ parameters: { pointerType: 'touch' },
94
+ actions: [
95
+ { type: 'pointerMove', duration: 0, x: targetX, y: targetY },
96
+ { type: 'pointerDown', button: 0 },
97
+ { type: 'pause', duration: 50 },
98
+ { type: 'pointerUp', button: 0 },
99
+ ],
100
+ },
101
+ ]);
102
+ await client.releaseActions();
103
+ }
104
+ async typeText(text) {
105
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
106
+ const activeElement = await client.findElement('xpath', '//*[@focused="true"]');
107
+ const elementId = extractElementId(activeElement);
108
+ await client.elementClear(elementId);
109
+ await client.elementSendKeys(elementId, text);
110
+ }
111
+ async swipe(direction, startX, startY, distance) {
112
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
113
+ const dist = distance ?? 500;
114
+ const sx = startX ?? 200;
115
+ const sy = startY ?? 400;
116
+ const [endX, endY] = (0, element_js_1.computeSwipeEnd)(sx, sy, direction, dist);
117
+ await client.performActions([
118
+ {
119
+ type: 'pointer',
120
+ id: 'finger1',
121
+ parameters: { pointerType: 'touch' },
122
+ actions: [
123
+ { type: 'pointerMove', duration: 0, x: sx, y: sy },
124
+ { type: 'pointerDown', button: 0 },
125
+ { type: 'pointerMove', duration: 300, x: endX, y: endY },
126
+ { type: 'pointerUp', button: 0 },
127
+ ],
128
+ },
129
+ ]);
130
+ await client.releaseActions();
131
+ }
132
+ async waitForElement(query, timeoutMs = 10000, intervalMs = 500) {
133
+ const start = Date.now();
134
+ while (Date.now() - start < timeoutMs) {
135
+ const snap = await this.snapshot();
136
+ const element = (0, element_js_1.findElement)(snap.hierarchy, query);
137
+ if (element) {
138
+ return element;
139
+ }
140
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
141
+ }
142
+ throw new Error(`Timed out waiting for element: ${JSON.stringify(query)} (${timeoutMs}ms)`);
143
+ }
144
+ async getAppState(bundleId) {
145
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
146
+ if (this.platform === 'ios') {
147
+ // iOS app state: 0=not installed, 1=not running, 2=background, 3=suspended, 4=foreground
148
+ const state = await client.queryAppState(bundleId);
149
+ const stateMap = {
150
+ 0: 'Not Installed',
151
+ 1: 'Not Running',
152
+ 2: 'Running (background)',
153
+ 3: 'Suspended',
154
+ 4: 'Running (foreground)',
155
+ };
156
+ return { bundleId, state: stateMap[state] ?? `Unknown (${state})` };
157
+ }
158
+ try {
159
+ const activity = await client.getCurrentActivity();
160
+ return { bundleId, state: `Running (${activity})` };
161
+ }
162
+ catch {
163
+ return { bundleId, state: 'Not Running' };
164
+ }
165
+ }
166
+ async screenshot() {
167
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
168
+ const data = await client.execute('mobile: getScreenshot', []);
169
+ return { data, format: 'png' };
170
+ }
171
+ async openApp(bundleId) {
172
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
173
+ await client.execute('mobile: activateApp', [{ bundleId }]);
174
+ }
175
+ async closeApp(bundleId) {
176
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
177
+ await client.execute('mobile: terminateApp', [{ bundleId }]);
178
+ }
179
+ async pressButton(button) {
180
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
181
+ if (this.platform === 'ios') {
182
+ const iosMap = {
183
+ home: 'home',
184
+ lock: 'lock',
185
+ back: 'home',
186
+ enter: '\n',
187
+ };
188
+ await client.execute('mobile: pressButton', [{ name: iosMap[button] }]);
189
+ }
190
+ else {
191
+ // Android keyevent codes
192
+ const androidMap = {
193
+ home: 3,
194
+ back: 4,
195
+ enter: 66,
196
+ lock: 26,
197
+ };
198
+ await client.execute('mobile: pressKey', [
199
+ { keycode: androidMap[button] },
200
+ ]);
201
+ }
202
+ }
203
+ async dismissKeyboard() {
204
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
205
+ if (this.platform === 'ios') {
206
+ await client.execute('mobile: hideKeyboard', []);
207
+ }
208
+ else {
209
+ await client.execute('mobile: hideKeyboard', []);
210
+ }
211
+ }
212
+ async dismissAlert(accept) {
213
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
214
+ const action = accept ? 'accept' : 'dismiss';
215
+ await client.execute(`mobile: ${action}Alert`, []);
216
+ }
217
+ async getLogs(durationSeconds = 30, filter) {
218
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
219
+ const logType = this.platform === 'ios' ? 'syslog' : 'logcat';
220
+ const raw = await client.execute('mobile: getLog', [{ type: logType }]);
221
+ let entries = raw.map((entry) => ({
222
+ timestamp: typeof entry.timestamp === 'string' ? entry.timestamp : '',
223
+ level: typeof entry.level === 'string' ? entry.level : 'info',
224
+ message: typeof entry.message === 'string' ? entry.message : '',
225
+ }));
226
+ if (filter) {
227
+ const pattern = new RegExp(filter, 'iu');
228
+ entries = entries.filter((entry) => pattern.test(entry.message));
229
+ }
230
+ const cutoff = Date.now() - durationSeconds * 1000;
231
+ entries = entries.filter((entry) => {
232
+ const ts = Number(entry.timestamp);
233
+ return isNaN(ts) || ts >= cutoff;
234
+ });
235
+ return { entries, source: `appium ${logType}` };
236
+ }
237
+ async longPress(query, durationMs = 1000) {
238
+ const snap = await this.snapshot();
239
+ const element = (0, element_js_1.findElement)(snap.hierarchy, query);
240
+ if (!element) {
241
+ throw new Error(`Element not found: ${JSON.stringify(query)}\n` +
242
+ 'Use device_snapshot to inspect the current UI hierarchy.');
243
+ }
244
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
245
+ const cx = Math.round(element.frame.x + element.frame.width / 2);
246
+ const cy = Math.round(element.frame.y + element.frame.height / 2);
247
+ await client.performActions([
248
+ {
249
+ type: 'pointer',
250
+ id: 'finger1',
251
+ parameters: { pointerType: 'touch' },
252
+ actions: [
253
+ { type: 'pointerMove', duration: 0, x: cx, y: cy },
254
+ { type: 'pointerDown', button: 0 },
255
+ { type: 'pause', duration: durationMs },
256
+ { type: 'pointerUp', button: 0 },
257
+ ],
258
+ },
259
+ ]);
260
+ await client.releaseActions();
261
+ return {
262
+ success: true,
263
+ x: cx,
264
+ y: cy,
265
+ targetDescription: (0, element_js_1.describeElement)(element),
266
+ };
267
+ }
268
+ async scrollToElement(query, direction = 'down', maxAttempts = 10) {
269
+ let previousRaw = '';
270
+ for (let i = 0; i < maxAttempts; i++) {
271
+ const snap = await this.snapshot();
272
+ const element = (0, element_js_1.findElement)(snap.hierarchy, query);
273
+ if (element) {
274
+ return element;
275
+ }
276
+ if (snap.raw === previousRaw) {
277
+ break;
278
+ }
279
+ previousRaw = snap.raw;
280
+ await this.swipe(direction);
281
+ }
282
+ throw new Error(`Element not found after scrolling: ${JSON.stringify(query)}\n` +
283
+ 'Use device_snapshot to inspect the current UI hierarchy.');
284
+ }
285
+ async getAlertText() {
286
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
287
+ try {
288
+ return await client.execute('mobile: getAlertText', []);
289
+ }
290
+ catch {
291
+ const snap = await this.snapshot();
292
+ const texts = collectAppiumAlertTexts(snap.hierarchy, this.platform);
293
+ if (texts.length === 0) {
294
+ throw new Error('No alert is currently displayed.\n' +
295
+ 'Use device_snapshot to inspect the current UI hierarchy.');
296
+ }
297
+ return texts.join('\n');
298
+ }
299
+ }
300
+ async getWindowSize() {
301
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
302
+ try {
303
+ const rect = await client.getWindowRect();
304
+ return { width: rect.width, height: rect.height };
305
+ }
306
+ catch {
307
+ const snap = await this.snapshot();
308
+ if (snap.hierarchy.length > 0) {
309
+ const root = snap.hierarchy[0];
310
+ if (root.frame.width > 0 && root.frame.height > 0) {
311
+ return { width: root.frame.width, height: root.frame.height };
312
+ }
313
+ }
314
+ throw new Error('Unable to determine window size');
315
+ }
316
+ }
317
+ async getContexts() {
318
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
319
+ return client.getContexts();
320
+ }
321
+ async setContext(context) {
322
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
323
+ await client.setCurrentContext(context);
324
+ }
325
+ async getClipboard() {
326
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
327
+ const b64 = await client.execute('mobile: getClipboard', [
328
+ { contentType: 'plaintext' },
329
+ ]);
330
+ return Buffer.from(b64, 'base64').toString('utf-8');
331
+ }
332
+ async setClipboard(text) {
333
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
334
+ await client.execute('mobile: setClipboard', [
335
+ {
336
+ content: Buffer.from(text).toString('base64'),
337
+ contentType: 'plaintext',
338
+ },
339
+ ]);
340
+ }
341
+ async startScreenRecording(outputPath) {
342
+ if (__classPrivateFieldGet(this, _AppiumBackend_recording, "f")) {
343
+ throw new Error('Screen recording is already in progress');
344
+ }
345
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
346
+ await client.execute('mobile: startRecordingScreen', [{}]);
347
+ __classPrivateFieldSet(this, _AppiumBackend_recording, true, "f");
348
+ __classPrivateFieldSet(this, _AppiumBackend_recordingOutputPath, (0, node_path_1.resolve)(outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`), "f");
349
+ }
350
+ async stopScreenRecording() {
351
+ if (!__classPrivateFieldGet(this, _AppiumBackend_recording, "f") || !__classPrivateFieldGet(this, _AppiumBackend_recordingOutputPath, "f")) {
352
+ throw new Error('No screen recording in progress');
353
+ }
354
+ const client = __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_requireClient).call(this);
355
+ const b64 = await client.execute('mobile: stopRecordingScreen', []);
356
+ const data = Buffer.from(b64, 'base64');
357
+ if (data.length === 0) {
358
+ throw new Error('Screen recording returned empty data');
359
+ }
360
+ const outputPath = (0, node_path_1.resolve)(__classPrivateFieldGet(this, _AppiumBackend_recordingOutputPath, "f"));
361
+ (0, node_fs_1.writeFileSync)(outputPath, data);
362
+ __classPrivateFieldSet(this, _AppiumBackend_recording, false, "f");
363
+ __classPrivateFieldSet(this, _AppiumBackend_recordingOutputPath, null, "f");
364
+ return outputPath;
365
+ }
366
+ }
367
+ exports.AppiumBackend = AppiumBackend;
368
+ _AppiumBackend_client = new WeakMap(), _AppiumBackend_config = new WeakMap(), _AppiumBackend_recording = new WeakMap(), _AppiumBackend_recordingOutputPath = new WeakMap(), _AppiumBackend_instances = new WeakSet(), _AppiumBackend_getHierarchy = async function _AppiumBackend_getHierarchy(client) {
369
+ if (this.platform === 'ios') {
370
+ return __classPrivateFieldGet(this, _AppiumBackend_instances, "m", _AppiumBackend_getIosHierarchy).call(this, client);
371
+ }
372
+ return client.getPageSource();
373
+ }, _AppiumBackend_getIosHierarchy = async function _AppiumBackend_getIosHierarchy(client) {
374
+ // Limit hierarchy depth to avoid "JS stack is too deep" on complex iOS apps
375
+ try {
376
+ await client.updateSettings({ snapshotMaxDepth: 30 });
377
+ }
378
+ catch {
379
+ // snapshotMaxDepth not supported on older XCUITest drivers
380
+ }
381
+ try {
382
+ return await client.execute('mobile: source', [
383
+ { format: 'xml' },
384
+ ]);
385
+ }
386
+ catch {
387
+ return client.getPageSource();
388
+ }
389
+ }, _AppiumBackend_requireClient = function _AppiumBackend_requireClient() {
390
+ if (!__classPrivateFieldGet(this, _AppiumBackend_client, "f")) {
391
+ throw new Error('AppiumBackend not connected. Call ensureConnected() first.');
392
+ }
393
+ return __classPrivateFieldGet(this, _AppiumBackend_client, "f");
394
+ };
395
+ function collectAppiumAlertTexts(elements, platform) {
396
+ const texts = [];
397
+ for (const el of elements) {
398
+ const isAlert = platform === 'ios'
399
+ ? el.type === 'Alert' || el.type === 'Sheet'
400
+ : el.type.includes('Dialog');
401
+ if (isAlert) {
402
+ collectAppiumTextValues(el.children ?? [], texts);
403
+ return texts;
404
+ }
405
+ if (el.children) {
406
+ const found = collectAppiumAlertTexts(el.children, platform);
407
+ if (found.length > 0) {
408
+ return found;
409
+ }
410
+ }
411
+ }
412
+ return texts;
413
+ }
414
+ function collectAppiumTextValues(elements, texts) {
415
+ for (const el of elements) {
416
+ const text = el.value ?? el.label;
417
+ if (text &&
418
+ (el.type === 'StaticText' ||
419
+ el.type.includes('TextView') ||
420
+ el.type === 'Text')) {
421
+ texts.push(text);
422
+ }
423
+ if (el.children) {
424
+ collectAppiumTextValues(el.children, texts);
425
+ }
426
+ }
427
+ }
428
+ function extractElementId(element) {
429
+ // W3C uses 'element-6066-11e4-a52e-4f735466cecf', JSONWP uses 'ELEMENT'
430
+ const id = element['element-6066-11e4-a52e-4f735466cecf'] ||
431
+ element.ELEMENT ||
432
+ Object.values(element)[0];
433
+ if (!id) {
434
+ throw new Error(`Failed to extract element ID from Appium response: ${JSON.stringify(element)}`);
435
+ }
436
+ return id;
437
+ }
438
+ function parseAppiumAndroidHierarchy(xml) {
439
+ const elements = [];
440
+ const nodeRegex = /<node\s+([^>]+)\/?>/gu;
441
+ let match;
442
+ while ((match = nodeRegex.exec(xml)) !== null) {
443
+ const element = parseAndroidNodeAttrs(match[1]);
444
+ if (element) {
445
+ elements.push(element);
446
+ }
447
+ }
448
+ return elements;
449
+ }
450
+ function parseAndroidNodeAttrs(attrs) {
451
+ const get = (name) => {
452
+ const attrMatch = attrs.match(new RegExp(`${name}="([^"]*)"`, 'u'));
453
+ return attrMatch?.[1] || undefined;
454
+ };
455
+ const boundsStr = get('bounds');
456
+ if (!boundsStr) {
457
+ return null;
458
+ }
459
+ // bounds format: [x1,y1][x2,y2]
460
+ const boundsMatch = boundsStr.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/u);
461
+ if (!boundsMatch) {
462
+ return null;
463
+ }
464
+ const x1 = parseInt(boundsMatch[1], 10);
465
+ const y1 = parseInt(boundsMatch[2], 10);
466
+ const x2 = parseInt(boundsMatch[3], 10);
467
+ const y2 = parseInt(boundsMatch[4], 10);
468
+ return {
469
+ type: get('class') ?? 'Unknown',
470
+ label: get('content-desc') || undefined,
471
+ value: get('text') || undefined,
472
+ identifier: get('resource-id') || undefined,
473
+ frame: { x: x1, y: y1, width: x2 - x1, height: y2 - y1 },
474
+ enabled: get('enabled') !== 'false',
475
+ };
476
+ }
477
+ function parseAppiumIosHierarchy(xml) {
478
+ const elements = [];
479
+ // XCUITest XML uses <XCUIElementType* ...> elements
480
+ const nodeRegex = /<(XCUIElementType\w+)\s+([^>]+)\/?>/gu;
481
+ let match;
482
+ while ((match = nodeRegex.exec(xml)) !== null) {
483
+ const typeName = match[1];
484
+ const element = parseIosNodeAttrs(typeName, match[2]);
485
+ if (element) {
486
+ elements.push(element);
487
+ }
488
+ }
489
+ return elements;
490
+ }
491
+ function parseIosNodeAttrs(typeName, attrs) {
492
+ const get = (name) => {
493
+ const attrMatch = attrs.match(new RegExp(`${name}="([^"]*)"`, 'u'));
494
+ return attrMatch?.[1] || undefined;
495
+ };
496
+ const xStr = get('x');
497
+ const yStr = get('y');
498
+ const widthStr = get('width');
499
+ const heightStr = get('height');
500
+ if (!xStr || !yStr || !widthStr || !heightStr) {
501
+ return null;
502
+ }
503
+ const shortType = typeName.replace(/^XCUIElementType/u, '');
504
+ return {
505
+ type: shortType,
506
+ label: get('label') || undefined,
507
+ value: get('value') || undefined,
508
+ identifier: get('name') || undefined,
509
+ frame: {
510
+ x: parseInt(xStr, 10),
511
+ y: parseInt(yStr, 10),
512
+ width: parseInt(widthStr, 10),
513
+ height: parseInt(heightStr, 10),
514
+ },
515
+ enabled: get('enabled') !== 'false',
516
+ };
517
+ }
518
+ //# sourceMappingURL=appium-backend.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-backend.cjs","sourceRoot":"","sources":["../../src/backends/appium-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFileSync } from 'node:fs';\nimport { resolve as resolvePath } from 'node:path';\n\nimport type { SessionConfig } from './session-file.js';\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n SnapshotResult,\n ScreenshotResult,\n LogsResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n Platform,\n WindowSize,\n} from './types.js';\nimport { WebDriverClient, createSession } from './webdriver-client.js';\nimport {\n findElement,\n describeElement,\n computeSwipeEnd,\n} from '../utils/element.js';\n\nexport class AppiumBackend implements DeviceBackend {\n readonly platform: Platform;\n\n #client: WebDriverClient | null = null;\n\n readonly #config: SessionConfig;\n\n #recording = false;\n\n #recordingOutputPath: string | null = null;\n\n constructor(config: SessionConfig) {\n this.#config = config;\n this.platform = config.platform;\n }\n\n async ensureConnected(): Promise<void> {\n if (this.#client) {\n return;\n }\n\n if (this.#config.mode === 'attach') {\n this.#client = new WebDriverClient(\n this.#config.appiumUrl,\n this.#config.sessionId,\n this.#config.auth,\n );\n await this.#client.getStatus();\n } else {\n const { client } = await createSession(\n this.#config.appiumUrl,\n this.#config.capabilities,\n this.#config.auth,\n );\n this.#client = client;\n }\n }\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n const client = this.#requireClient();\n const details = await client.getSessionDetails();\n const caps = (details.capabilities ?? details) as Record<string, unknown>;\n\n return {\n platform: this.platform,\n deviceId: (caps.udid as string) ?? client.sessionId,\n name: (caps.deviceName as string) ?? 'Appium Device',\n osVersion: (caps.platformVersion as string) ?? 'Unknown',\n state: 'connected',\n };\n }\n\n async snapshot(): Promise<SnapshotResult> {\n const client = this.#requireClient();\n const raw = await this.#getHierarchy(client);\n const hierarchy =\n this.platform === 'ios'\n ? parseAppiumIosHierarchy(raw)\n : parseAppiumAndroidHierarchy(raw);\n\n return {\n platform: this.platform,\n hierarchy,\n raw,\n timestamp: Date.now(),\n };\n }\n\n async tapElement(query: ElementQuery): Promise<TapResult> {\n const snapshot = await this.snapshot();\n const element = findElement(snapshot.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const targetX = Math.round(element.frame.x + element.frame.width / 2);\n const targetY = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(targetX, targetY);\n\n return {\n success: true,\n x: targetX,\n y: targetY,\n targetDescription: describeElement(element),\n };\n }\n\n async tapCoordinates(targetX: number, targetY: number): Promise<void> {\n const client = this.#requireClient();\n await client.performActions([\n {\n type: 'pointer',\n id: 'finger1',\n parameters: { pointerType: 'touch' },\n actions: [\n { type: 'pointerMove', duration: 0, x: targetX, y: targetY },\n { type: 'pointerDown', button: 0 },\n { type: 'pause', duration: 50 },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n await client.releaseActions();\n }\n\n async typeText(text: string): Promise<void> {\n const client = this.#requireClient();\n const activeElement = await client.findElement(\n 'xpath',\n '//*[@focused=\"true\"]',\n );\n const elementId = extractElementId(activeElement);\n await client.elementClear(elementId);\n await client.elementSendKeys(elementId, text);\n }\n\n async swipe(\n direction: 'up' | 'down' | 'left' | 'right',\n startX?: number,\n startY?: number,\n distance?: number,\n ): Promise<void> {\n const client = this.#requireClient();\n const dist = distance ?? 500;\n const sx = startX ?? 200;\n const sy = startY ?? 400;\n const [endX, endY] = computeSwipeEnd(sx, sy, direction, dist);\n\n await client.performActions([\n {\n type: 'pointer',\n id: 'finger1',\n parameters: { pointerType: 'touch' },\n actions: [\n { type: 'pointerMove', duration: 0, x: sx, y: sy },\n { type: 'pointerDown', button: 0 },\n { type: 'pointerMove', duration: 300, x: endX, y: endY },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n await client.releaseActions();\n }\n\n async waitForElement(\n query: ElementQuery,\n timeoutMs = 10_000,\n intervalMs = 500,\n ): Promise<UIElement> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (element) {\n return element;\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n throw new Error(\n `Timed out waiting for element: ${JSON.stringify(query)} (${timeoutMs}ms)`,\n );\n }\n\n async getAppState(bundleId: string): Promise<AppStateResult> {\n const client = this.#requireClient();\n\n if (this.platform === 'ios') {\n // iOS app state: 0=not installed, 1=not running, 2=background, 3=suspended, 4=foreground\n const state = await client.queryAppState(bundleId);\n const stateMap: Record<number, string> = {\n 0: 'Not Installed',\n 1: 'Not Running',\n 2: 'Running (background)',\n 3: 'Suspended',\n 4: 'Running (foreground)',\n };\n return { bundleId, state: stateMap[state] ?? `Unknown (${state})` };\n }\n\n try {\n const activity = await client.getCurrentActivity();\n return { bundleId, state: `Running (${activity})` };\n } catch {\n return { bundleId, state: 'Not Running' };\n }\n }\n\n async #getHierarchy(client: WebDriverClient): Promise<string> {\n if (this.platform === 'ios') {\n return this.#getIosHierarchy(client);\n }\n return client.getPageSource();\n }\n\n async #getIosHierarchy(client: WebDriverClient): Promise<string> {\n // Limit hierarchy depth to avoid \"JS stack is too deep\" on complex iOS apps\n try {\n await client.updateSettings({ snapshotMaxDepth: 30 });\n } catch {\n // snapshotMaxDepth not supported on older XCUITest drivers\n }\n\n try {\n return await client.execute<string>('mobile: source', [\n { format: 'xml' },\n ]);\n } catch {\n return client.getPageSource();\n }\n }\n\n async screenshot(): Promise<ScreenshotResult> {\n const client = this.#requireClient();\n const data = await client.execute<string>('mobile: getScreenshot', []);\n return { data, format: 'png' };\n }\n\n async openApp(bundleId: string): Promise<void> {\n const client = this.#requireClient();\n await client.execute('mobile: activateApp', [{ bundleId }]);\n }\n\n async closeApp(bundleId: string): Promise<void> {\n const client = this.#requireClient();\n await client.execute('mobile: terminateApp', [{ bundleId }]);\n }\n\n async pressButton(button: DeviceButton): Promise<void> {\n const client = this.#requireClient();\n if (this.platform === 'ios') {\n const iosMap: Record<DeviceButton, string> = {\n home: 'home',\n lock: 'lock',\n back: 'home',\n enter: '\\n',\n };\n await client.execute('mobile: pressButton', [{ name: iosMap[button] }]);\n } else {\n // Android keyevent codes\n const androidMap: Record<DeviceButton, number> = {\n home: 3,\n back: 4,\n enter: 66,\n lock: 26,\n };\n await client.execute('mobile: pressKey', [\n { keycode: androidMap[button] },\n ]);\n }\n }\n\n async dismissKeyboard(): Promise<void> {\n const client = this.#requireClient();\n if (this.platform === 'ios') {\n await client.execute('mobile: hideKeyboard', []);\n } else {\n await client.execute('mobile: hideKeyboard', []);\n }\n }\n\n async dismissAlert(accept: boolean): Promise<void> {\n const client = this.#requireClient();\n const action = accept ? 'accept' : 'dismiss';\n await client.execute(`mobile: ${action}Alert`, []);\n }\n\n async getLogs(durationSeconds = 30, filter?: string): Promise<LogsResult> {\n const client = this.#requireClient();\n const logType = this.platform === 'ios' ? 'syslog' : 'logcat';\n const raw = await client.execute<Record<string, unknown>[]>(\n 'mobile: getLog',\n [{ type: logType }],\n );\n\n let entries = raw.map((entry) => ({\n timestamp: typeof entry.timestamp === 'string' ? entry.timestamp : '',\n level: typeof entry.level === 'string' ? entry.level : 'info',\n message: typeof entry.message === 'string' ? entry.message : '',\n }));\n\n if (filter) {\n const pattern = new RegExp(filter, 'iu');\n entries = entries.filter((entry) => pattern.test(entry.message));\n }\n\n const cutoff = Date.now() - durationSeconds * 1000;\n entries = entries.filter((entry) => {\n const ts = Number(entry.timestamp);\n return isNaN(ts) || ts >= cutoff;\n });\n\n return { entries, source: `appium ${logType}` };\n }\n\n async longPress(query: ElementQuery, durationMs = 1000): Promise<TapResult> {\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (!element) {\n throw new Error(\n `Element not found: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n const client = this.#requireClient();\n const cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await client.performActions([\n {\n type: 'pointer',\n id: 'finger1',\n parameters: { pointerType: 'touch' },\n actions: [\n { type: 'pointerMove', duration: 0, x: cx, y: cy },\n { type: 'pointerDown', button: 0 },\n { type: 'pause', duration: durationMs },\n { type: 'pointerUp', button: 0 },\n ],\n },\n ]);\n await client.releaseActions();\n\n return {\n success: true,\n x: cx,\n y: cy,\n targetDescription: describeElement(element),\n };\n }\n\n async scrollToElement(\n query: ElementQuery,\n direction: 'up' | 'down' = 'down',\n maxAttempts = 10,\n ): Promise<UIElement> {\n let previousRaw = '';\n\n for (let i = 0; i < maxAttempts; i++) {\n const snap = await this.snapshot();\n const element = findElement(snap.hierarchy, query);\n if (element) {\n return element;\n }\n if (snap.raw === previousRaw) {\n break;\n }\n previousRaw = snap.raw;\n await this.swipe(direction);\n }\n throw new Error(\n `Element not found after scrolling: ${JSON.stringify(query)}\\n` +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n\n async getAlertText(): Promise<string> {\n const client = this.#requireClient();\n try {\n return await client.execute<string>('mobile: getAlertText', []);\n } catch {\n const snap = await this.snapshot();\n const texts = collectAppiumAlertTexts(snap.hierarchy, this.platform);\n if (texts.length === 0) {\n throw new Error(\n 'No alert is currently displayed.\\n' +\n 'Use device_snapshot to inspect the current UI hierarchy.',\n );\n }\n return texts.join('\\n');\n }\n }\n\n async getWindowSize(): Promise<WindowSize> {\n const client = this.#requireClient();\n try {\n const rect = await client.getWindowRect();\n return { width: rect.width, height: rect.height };\n } catch {\n const snap = await this.snapshot();\n if (snap.hierarchy.length > 0) {\n const root = snap.hierarchy[0];\n if (root.frame.width > 0 && root.frame.height > 0) {\n return { width: root.frame.width, height: root.frame.height };\n }\n }\n throw new Error('Unable to determine window size');\n }\n }\n\n async getContexts(): Promise<string[]> {\n const client = this.#requireClient();\n return client.getContexts();\n }\n\n async setContext(context: string): Promise<void> {\n const client = this.#requireClient();\n await client.setCurrentContext(context);\n }\n\n async getClipboard(): Promise<string> {\n const client = this.#requireClient();\n const b64 = await client.execute<string>('mobile: getClipboard', [\n { contentType: 'plaintext' },\n ]);\n return Buffer.from(b64, 'base64').toString('utf-8');\n }\n\n async setClipboard(text: string): Promise<void> {\n const client = this.#requireClient();\n await client.execute('mobile: setClipboard', [\n {\n content: Buffer.from(text).toString('base64'),\n contentType: 'plaintext',\n },\n ]);\n }\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n if (this.#recording) {\n throw new Error('Screen recording is already in progress');\n }\n const client = this.#requireClient();\n await client.execute('mobile: startRecordingScreen', [{}]);\n this.#recording = true;\n this.#recordingOutputPath = resolvePath(\n outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`,\n );\n }\n\n async stopScreenRecording(): Promise<string> {\n if (!this.#recording || !this.#recordingOutputPath) {\n throw new Error('No screen recording in progress');\n }\n const client = this.#requireClient();\n const b64 = await client.execute<string>('mobile: stopRecordingScreen', []);\n const data = Buffer.from(b64, 'base64');\n if (data.length === 0) {\n throw new Error('Screen recording returned empty data');\n }\n const outputPath = resolvePath(this.#recordingOutputPath);\n writeFileSync(outputPath, data);\n this.#recording = false;\n this.#recordingOutputPath = null;\n return outputPath;\n }\n\n #requireClient(): WebDriverClient {\n if (!this.#client) {\n throw new Error(\n 'AppiumBackend not connected. Call ensureConnected() first.',\n );\n }\n return this.#client;\n }\n}\n\nfunction collectAppiumAlertTexts(\n elements: UIElement[],\n platform: Platform,\n): string[] {\n const texts: string[] = [];\n for (const el of elements) {\n const isAlert =\n platform === 'ios'\n ? el.type === 'Alert' || el.type === 'Sheet'\n : el.type.includes('Dialog');\n if (isAlert) {\n collectAppiumTextValues(el.children ?? [], texts);\n return texts;\n }\n if (el.children) {\n const found = collectAppiumAlertTexts(el.children, platform);\n if (found.length > 0) {\n return found;\n }\n }\n }\n return texts;\n}\n\nfunction collectAppiumTextValues(elements: UIElement[], texts: string[]): void {\n for (const el of elements) {\n const text = el.value ?? el.label;\n if (\n text &&\n (el.type === 'StaticText' ||\n el.type.includes('TextView') ||\n el.type === 'Text')\n ) {\n texts.push(text);\n }\n if (el.children) {\n collectAppiumTextValues(el.children, texts);\n }\n }\n}\n\nfunction extractElementId(element: Record<string, string>): string {\n // W3C uses 'element-6066-11e4-a52e-4f735466cecf', JSONWP uses 'ELEMENT'\n const id =\n element['element-6066-11e4-a52e-4f735466cecf'] ||\n element.ELEMENT ||\n Object.values(element)[0];\n\n if (!id) {\n throw new Error(\n `Failed to extract element ID from Appium response: ${JSON.stringify(element)}`,\n );\n }\n return id;\n}\n\nexport function parseAppiumAndroidHierarchy(xml: string): UIElement[] {\n const elements: UIElement[] = [];\n const nodeRegex = /<node\\s+([^>]+)\\/?>/gu;\n let match;\n\n while ((match = nodeRegex.exec(xml)) !== null) {\n const element = parseAndroidNodeAttrs(match[1]);\n if (element) {\n elements.push(element);\n }\n }\n\n return elements;\n}\n\nfunction parseAndroidNodeAttrs(attrs: string): UIElement | null {\n const get = (name: string): string | undefined => {\n const attrMatch = attrs.match(new RegExp(`${name}=\"([^\"]*)\"`, 'u'));\n return attrMatch?.[1] || undefined;\n };\n\n const boundsStr = get('bounds');\n if (!boundsStr) {\n return null;\n }\n\n // bounds format: [x1,y1][x2,y2]\n const boundsMatch = boundsStr.match(/\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]/u);\n if (!boundsMatch) {\n return null;\n }\n\n const x1 = parseInt(boundsMatch[1], 10);\n const y1 = parseInt(boundsMatch[2], 10);\n const x2 = parseInt(boundsMatch[3], 10);\n const y2 = parseInt(boundsMatch[4], 10);\n\n return {\n type: get('class') ?? 'Unknown',\n label: get('content-desc') || undefined,\n value: get('text') || undefined,\n identifier: get('resource-id') || undefined,\n frame: { x: x1, y: y1, width: x2 - x1, height: y2 - y1 },\n enabled: get('enabled') !== 'false',\n };\n}\n\nexport function parseAppiumIosHierarchy(xml: string): UIElement[] {\n const elements: UIElement[] = [];\n // XCUITest XML uses <XCUIElementType* ...> elements\n const nodeRegex = /<(XCUIElementType\\w+)\\s+([^>]+)\\/?>/gu;\n let match;\n\n while ((match = nodeRegex.exec(xml)) !== null) {\n const typeName = match[1];\n const element = parseIosNodeAttrs(typeName, match[2]);\n if (element) {\n elements.push(element);\n }\n }\n\n return elements;\n}\n\nfunction parseIosNodeAttrs(typeName: string, attrs: string): UIElement | null {\n const get = (name: string): string | undefined => {\n const attrMatch = attrs.match(new RegExp(`${name}=\"([^\"]*)\"`, 'u'));\n return attrMatch?.[1] || undefined;\n };\n\n const xStr = get('x');\n const yStr = get('y');\n const widthStr = get('width');\n const heightStr = get('height');\n\n if (!xStr || !yStr || !widthStr || !heightStr) {\n return null;\n }\n\n const shortType = typeName.replace(/^XCUIElementType/u, '');\n\n return {\n type: shortType,\n label: get('label') || undefined,\n value: get('value') || undefined,\n identifier: get('name') || undefined,\n frame: {\n x: parseInt(xStr, 10),\n y: parseInt(yStr, 10),\n width: parseInt(widthStr, 10),\n height: parseInt(heightStr, 10),\n },\n enabled: get('enabled') !== 'false',\n };\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import type { SessionConfig } from "./session-file.cjs";
2
+ import type { DeviceBackend, DeviceButton, DeviceInfo, SnapshotResult, ScreenshotResult, LogsResult, TapResult, AppStateResult, ElementQuery, UIElement, Platform, WindowSize } from "./types.cjs";
3
+ export declare class AppiumBackend implements DeviceBackend {
4
+ #private;
5
+ readonly platform: Platform;
6
+ constructor(config: SessionConfig);
7
+ ensureConnected(): Promise<void>;
8
+ getDeviceInfo(): Promise<DeviceInfo>;
9
+ snapshot(): Promise<SnapshotResult>;
10
+ tapElement(query: ElementQuery): Promise<TapResult>;
11
+ tapCoordinates(targetX: number, targetY: number): Promise<void>;
12
+ typeText(text: string): Promise<void>;
13
+ swipe(direction: 'up' | 'down' | 'left' | 'right', startX?: number, startY?: number, distance?: number): Promise<void>;
14
+ waitForElement(query: ElementQuery, timeoutMs?: number, intervalMs?: number): Promise<UIElement>;
15
+ getAppState(bundleId: string): Promise<AppStateResult>;
16
+ screenshot(): Promise<ScreenshotResult>;
17
+ openApp(bundleId: string): Promise<void>;
18
+ closeApp(bundleId: string): Promise<void>;
19
+ pressButton(button: DeviceButton): Promise<void>;
20
+ dismissKeyboard(): Promise<void>;
21
+ dismissAlert(accept: boolean): Promise<void>;
22
+ getLogs(durationSeconds?: number, filter?: string): Promise<LogsResult>;
23
+ longPress(query: ElementQuery, durationMs?: number): Promise<TapResult>;
24
+ scrollToElement(query: ElementQuery, direction?: 'up' | 'down', maxAttempts?: number): Promise<UIElement>;
25
+ getAlertText(): Promise<string>;
26
+ getWindowSize(): Promise<WindowSize>;
27
+ getContexts(): Promise<string[]>;
28
+ setContext(context: string): Promise<void>;
29
+ getClipboard(): Promise<string>;
30
+ setClipboard(text: string): Promise<void>;
31
+ startScreenRecording(outputPath?: string): Promise<void>;
32
+ stopScreenRecording(): Promise<string>;
33
+ }
34
+ export declare function parseAppiumAndroidHierarchy(xml: string): UIElement[];
35
+ export declare function parseAppiumIosHierarchy(xml: string): UIElement[];
36
+ //# sourceMappingURL=appium-backend.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appium-backend.d.cts","sourceRoot":"","sources":["../../src/backends/appium-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,2BAA0B;AACvD,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,EACX,oBAAmB;AAQpB,qBAAa,aAAc,YAAW,aAAa;;IACjD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAUhB,MAAM,EAAE,aAAa;IAK3B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBhC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAcpC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAgBnC,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC;IAsBnD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB/D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrC,KAAK,CACT,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAC3C,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAuBV,cAAc,CAClB,KAAK,EAAE,YAAY,EACnB,SAAS,SAAS,EAClB,UAAU,SAAM,GACf,OAAO,CAAC,SAAS,CAAC;IAef,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgDtD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAMvC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBhD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5C,OAAO,CAAC,eAAe,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA4BnE,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IAoCrE,eAAe,CACnB,KAAK,EAAE,YAAY,EACnB,SAAS,GAAE,IAAI,GAAG,MAAe,EACjC,WAAW,SAAK,GACf,OAAO,CAAC,SAAS,CAAC;IAqBf,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAiB/B,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAiBpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAKhC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ/B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAyB7C;AA0DD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAapE;AAkCD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAehE"}