@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,442 @@
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 _AdbBackend_instances, _AdbBackend_serial, _AdbBackend_recordingProcess, _AdbBackend_recordingPath, _AdbBackend_recordingRemotePath, _AdbBackend_adb, _AdbBackend_dumpUiHierarchy;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AdbBackend = void 0;
16
+ exports.parseAndroidHierarchy = parseAndroidHierarchy;
17
+ exports.parseNodeAttributes = parseNodeAttributes;
18
+ const node_child_process_1 = require("node:child_process");
19
+ const alert_labels_js_1 = require("../utils/alert-labels.cjs");
20
+ const element_js_1 = require("../utils/element.cjs");
21
+ const exec_js_1 = require("../utils/exec.cjs");
22
+ class AdbBackend {
23
+ constructor(serial) {
24
+ _AdbBackend_instances.add(this);
25
+ this.platform = 'android';
26
+ _AdbBackend_serial.set(this, void 0);
27
+ _AdbBackend_recordingProcess.set(this, null);
28
+ _AdbBackend_recordingPath.set(this, null);
29
+ _AdbBackend_recordingRemotePath.set(this, '/sdcard/device-mcp-recording.mp4');
30
+ __classPrivateFieldSet(this, _AdbBackend_serial, serial, "f");
31
+ }
32
+ async ensureConnected() {
33
+ if (!(await (0, exec_js_1.isCommandAvailable)('adb'))) {
34
+ throw new Error('adb is not installed or not on $PATH.\n' +
35
+ 'Install Android SDK platform-tools.');
36
+ }
37
+ const state = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['get-state']);
38
+ if (state.trim() !== 'device') {
39
+ throw new Error(`Device ${__classPrivateFieldGet(this, _AdbBackend_serial, "f")} is not ready (state: ${state.trim()})`);
40
+ }
41
+ }
42
+ async getDeviceInfo() {
43
+ const [model, version] = await Promise.all([
44
+ __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'getprop', 'ro.product.model']),
45
+ __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'getprop', 'ro.build.version.release']),
46
+ ]);
47
+ return {
48
+ platform: 'android',
49
+ deviceId: __classPrivateFieldGet(this, _AdbBackend_serial, "f"),
50
+ name: model.trim(),
51
+ osVersion: version.trim(),
52
+ state: 'device',
53
+ };
54
+ }
55
+ async snapshot() {
56
+ const raw = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_dumpUiHierarchy).call(this);
57
+ const hierarchy = parseAndroidHierarchy(raw);
58
+ return {
59
+ platform: 'android',
60
+ hierarchy,
61
+ raw,
62
+ timestamp: Date.now(),
63
+ };
64
+ }
65
+ async tapElement(query) {
66
+ const snapshot = await this.snapshot();
67
+ const element = (0, element_js_1.findElement)(snapshot.hierarchy, query);
68
+ if (!element) {
69
+ throw new Error(`Element not found: ${JSON.stringify(query)}\n` +
70
+ 'Use device_snapshot to inspect the current UI hierarchy.');
71
+ }
72
+ const x = Math.round(element.frame.x + element.frame.width / 2);
73
+ const y = Math.round(element.frame.y + element.frame.height / 2);
74
+ await this.tapCoordinates(x, y);
75
+ return {
76
+ success: true,
77
+ x,
78
+ y,
79
+ targetDescription: (0, element_js_1.describeElement)(element),
80
+ };
81
+ }
82
+ async tapCoordinates(x, y) {
83
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'tap', String(x), String(y)]);
84
+ }
85
+ async typeText(text) {
86
+ // Android keyevent 29+shift = Ctrl+A (select all), 67 = DEL
87
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'keyevent', 'KEYCODE_MOVE_HOME']);
88
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, [
89
+ 'shell',
90
+ 'input',
91
+ 'keyevent',
92
+ '--longpress',
93
+ 'KEYCODE_SHIFT_LEFT',
94
+ 'KEYCODE_MOVE_END',
95
+ ]);
96
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'keyevent', '67']);
97
+ // Android input text requires escaping spaces and special chars
98
+ const escaped = text.replace(/ /gu, '%s').replace(/[&|;<>]/gu, '\\$&');
99
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'text', escaped]);
100
+ }
101
+ async swipe(direction, startX, startY, distance) {
102
+ const d = distance ?? 500;
103
+ const sx = startX ?? 540;
104
+ const sy = startY ?? 960;
105
+ const [endX, endY] = (0, element_js_1.computeSwipeEnd)(sx, sy, direction, d);
106
+ const durationMs = 300;
107
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, [
108
+ 'shell',
109
+ 'input',
110
+ 'swipe',
111
+ String(sx),
112
+ String(sy),
113
+ String(endX),
114
+ String(endY),
115
+ String(durationMs),
116
+ ]);
117
+ }
118
+ async waitForElement(query, timeoutMs = 10000, intervalMs = 500) {
119
+ const start = Date.now();
120
+ while (Date.now() - start < timeoutMs) {
121
+ const snapshot = await this.snapshot();
122
+ const element = (0, element_js_1.findElement)(snapshot.hierarchy, query);
123
+ if (element) {
124
+ return element;
125
+ }
126
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
127
+ }
128
+ throw new Error(`Timed out waiting for element: ${JSON.stringify(query)} (${timeoutMs}ms)`);
129
+ }
130
+ async getAppState(bundleId) {
131
+ const raw = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'dumpsys', 'activity', 'processes']);
132
+ const pidMatch = raw.match(new RegExp(`PID #(\\d+):.*${bundleId.replace(/\./gu, '\\.')}`, 'u'));
133
+ if (pidMatch) {
134
+ return {
135
+ bundleId,
136
+ state: 'Running',
137
+ pid: parseInt(pidMatch[1], 10),
138
+ };
139
+ }
140
+ const pmResult = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, [
141
+ 'shell',
142
+ 'pm',
143
+ 'list',
144
+ 'packages',
145
+ bundleId,
146
+ ]);
147
+ if (pmResult.includes(bundleId)) {
148
+ return { bundleId, state: 'Installed (not running)' };
149
+ }
150
+ return { bundleId, state: 'Not Installed' };
151
+ }
152
+ async screenshot(outputPath) {
153
+ const localPath = outputPath ?? `/tmp/device-mcp-screenshot-${Date.now()}.png`;
154
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'screencap', '-p', '/sdcard/screenshot.png']);
155
+ await (0, exec_js_1.execStrict)('adb', [
156
+ '-s',
157
+ __classPrivateFieldGet(this, _AdbBackend_serial, "f"),
158
+ 'pull',
159
+ '/sdcard/screenshot.png',
160
+ localPath,
161
+ ]);
162
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'rm', '-f', '/sdcard/screenshot.png']);
163
+ const data = await (0, exec_js_1.execStrict)('base64', [localPath]);
164
+ return { data: data.trim(), format: 'png', path: localPath };
165
+ }
166
+ async openApp(bundleId) {
167
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, [
168
+ 'shell',
169
+ 'monkey',
170
+ '-p',
171
+ bundleId,
172
+ '-c',
173
+ 'android.intent.category.LAUNCHER',
174
+ '1',
175
+ ]);
176
+ }
177
+ async closeApp(bundleId) {
178
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'am', 'force-stop', bundleId]);
179
+ }
180
+ async pressButton(button) {
181
+ // Android keyevent codes
182
+ const keyMap = {
183
+ home: '3',
184
+ back: '4',
185
+ enter: '66',
186
+ lock: '26',
187
+ };
188
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'keyevent', keyMap[button]]);
189
+ }
190
+ async dismissKeyboard() {
191
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'input', 'keyevent', '111']);
192
+ }
193
+ async dismissAlert(accept) {
194
+ const snap = await this.snapshot();
195
+ const candidates = accept ? alert_labels_js_1.ACCEPT_LABELS : alert_labels_js_1.DENY_LABELS;
196
+ for (const label of candidates) {
197
+ const element = (0, element_js_1.findElement)(snap.hierarchy, { text: label });
198
+ if (element) {
199
+ const cx = Math.round(element.frame.x + element.frame.width / 2);
200
+ const cy = Math.round(element.frame.y + element.frame.height / 2);
201
+ await this.tapCoordinates(cx, cy);
202
+ return;
203
+ }
204
+ }
205
+ throw new Error(`No alert button found. Tried: ${candidates.join(', ')}`);
206
+ }
207
+ async getLogs(durationSeconds = 30, filter) {
208
+ const args = ['shell', 'logcat', '-d', '-t', String(durationSeconds)];
209
+ if (filter) {
210
+ args.push('-e', filter);
211
+ }
212
+ const raw = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, args);
213
+ const entries = raw
214
+ .trim()
215
+ .split('\n')
216
+ .filter(Boolean)
217
+ .map((line) => {
218
+ const match = line.match(/^(\d{2}-\d{2}\s+\S+)\s+(\w)\/.*?:\s*(.*)/u);
219
+ if (match) {
220
+ return {
221
+ timestamp: match[1],
222
+ level: match[2],
223
+ message: match[3],
224
+ };
225
+ }
226
+ return { timestamp: '', level: 'info', message: line };
227
+ });
228
+ return { entries, source: 'logcat' };
229
+ }
230
+ async longPress(query, durationMs = 1000) {
231
+ const snap = await this.snapshot();
232
+ const element = (0, element_js_1.findElement)(snap.hierarchy, query);
233
+ if (!element) {
234
+ throw new Error(`Element not found: ${JSON.stringify(query)}\n` +
235
+ 'Use device_snapshot to inspect the current UI hierarchy.');
236
+ }
237
+ const cx = Math.round(element.frame.x + element.frame.width / 2);
238
+ const cy = Math.round(element.frame.y + element.frame.height / 2);
239
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, [
240
+ 'shell',
241
+ 'input',
242
+ 'swipe',
243
+ String(cx),
244
+ String(cy),
245
+ String(cx),
246
+ String(cy),
247
+ String(durationMs),
248
+ ]);
249
+ return {
250
+ success: true,
251
+ x: cx,
252
+ y: cy,
253
+ targetDescription: (0, element_js_1.describeElement)(element),
254
+ };
255
+ }
256
+ async scrollToElement(query, direction = 'down', maxAttempts = 10) {
257
+ let previousRaw = '';
258
+ for (let i = 0; i < maxAttempts; i++) {
259
+ const snap = await this.snapshot();
260
+ const element = (0, element_js_1.findElement)(snap.hierarchy, query);
261
+ if (element) {
262
+ return element;
263
+ }
264
+ if (snap.raw === previousRaw) {
265
+ break;
266
+ }
267
+ previousRaw = snap.raw;
268
+ await this.swipe(direction);
269
+ }
270
+ throw new Error(`Element not found after scrolling: ${JSON.stringify(query)}\n` +
271
+ 'Use device_snapshot to inspect the current UI hierarchy.');
272
+ }
273
+ async getAlertText() {
274
+ const snap = await this.snapshot();
275
+ const texts = collectAndroidAlertTexts(snap.hierarchy);
276
+ if (texts.length === 0) {
277
+ throw new Error('No alert is currently displayed.\n' +
278
+ 'Use device_snapshot to inspect the current UI hierarchy.');
279
+ }
280
+ return texts.join('\n');
281
+ }
282
+ async getWindowSize() {
283
+ const raw = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'wm', 'size']);
284
+ const match = raw.match(/(\d+)x(\d+)/u);
285
+ if (match) {
286
+ return {
287
+ width: parseInt(match[1], 10),
288
+ height: parseInt(match[2], 10),
289
+ };
290
+ }
291
+ throw new Error(`Unable to parse window size from: ${raw.trim()}`);
292
+ }
293
+ async getContexts() {
294
+ return ['NATIVE_APP'];
295
+ }
296
+ async setContext(context) {
297
+ if (context === 'NATIVE_APP') {
298
+ return;
299
+ }
300
+ throw new Error('Context switching requires Appium backend. ADB only supports NATIVE_APP.');
301
+ }
302
+ async getClipboard() {
303
+ throw new Error('Clipboard access via ADB is not supported on modern Android. ' +
304
+ 'Use the Appium backend for clipboard operations.');
305
+ }
306
+ async setClipboard(_text) {
307
+ throw new Error('Clipboard access via ADB is not supported on modern Android. ' +
308
+ 'Use the Appium backend for clipboard operations.');
309
+ }
310
+ async startScreenRecording(outputPath) {
311
+ if (__classPrivateFieldGet(this, _AdbBackend_recordingProcess, "f")) {
312
+ throw new Error('Screen recording is already in progress');
313
+ }
314
+ __classPrivateFieldSet(this, _AdbBackend_recordingPath, outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`, "f");
315
+ __classPrivateFieldSet(this, _AdbBackend_recordingProcess, (0, node_child_process_1.spawn)('adb', [
316
+ '-s',
317
+ __classPrivateFieldGet(this, _AdbBackend_serial, "f"),
318
+ 'shell',
319
+ 'screenrecord',
320
+ __classPrivateFieldGet(this, _AdbBackend_recordingRemotePath, "f"),
321
+ ]), "f");
322
+ __classPrivateFieldGet(this, _AdbBackend_recordingProcess, "f").on('error', () => {
323
+ __classPrivateFieldSet(this, _AdbBackend_recordingProcess, null, "f");
324
+ __classPrivateFieldSet(this, _AdbBackend_recordingPath, null, "f");
325
+ });
326
+ }
327
+ async stopScreenRecording() {
328
+ if (!__classPrivateFieldGet(this, _AdbBackend_recordingProcess, "f") || !__classPrivateFieldGet(this, _AdbBackend_recordingPath, "f")) {
329
+ throw new Error('No screen recording in progress');
330
+ }
331
+ const localPath = __classPrivateFieldGet(this, _AdbBackend_recordingPath, "f");
332
+ __classPrivateFieldGet(this, _AdbBackend_recordingProcess, "f").kill('SIGINT');
333
+ await new Promise((resolve) => setTimeout(resolve, 2000));
334
+ __classPrivateFieldSet(this, _AdbBackend_recordingProcess, null, "f");
335
+ __classPrivateFieldSet(this, _AdbBackend_recordingPath, null, "f");
336
+ await (0, exec_js_1.execStrict)('adb', [
337
+ '-s',
338
+ __classPrivateFieldGet(this, _AdbBackend_serial, "f"),
339
+ 'pull',
340
+ __classPrivateFieldGet(this, _AdbBackend_recordingRemotePath, "f"),
341
+ localPath,
342
+ ]);
343
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'rm', '-f', __classPrivateFieldGet(this, _AdbBackend_recordingRemotePath, "f")]);
344
+ return localPath;
345
+ }
346
+ }
347
+ exports.AdbBackend = AdbBackend;
348
+ _AdbBackend_serial = new WeakMap(), _AdbBackend_recordingProcess = new WeakMap(), _AdbBackend_recordingPath = new WeakMap(), _AdbBackend_recordingRemotePath = new WeakMap(), _AdbBackend_instances = new WeakSet(), _AdbBackend_adb = async function _AdbBackend_adb(args) {
349
+ return (0, exec_js_1.execStrict)('adb', ['-s', __classPrivateFieldGet(this, _AdbBackend_serial, "f"), ...args]);
350
+ }, _AdbBackend_dumpUiHierarchy = async function _AdbBackend_dumpUiHierarchy() {
351
+ const remotePath = '/sdcard/window_dump.xml';
352
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'uiautomator', 'dump', remotePath]);
353
+ const xml = await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'cat', remotePath]);
354
+ await __classPrivateFieldGet(this, _AdbBackend_instances, "m", _AdbBackend_adb).call(this, ['shell', 'rm', '-f', remotePath]);
355
+ return xml;
356
+ };
357
+ function collectAndroidAlertTexts(elements) {
358
+ const texts = [];
359
+ for (const el of elements) {
360
+ const isDialog = el.type.includes('Dialog') || el.type.includes('AlertDialog');
361
+ if (isDialog) {
362
+ collectTextValues(el.children ?? [], texts);
363
+ return texts;
364
+ }
365
+ if (el.children) {
366
+ const found = collectAndroidAlertTexts(el.children);
367
+ if (found.length > 0) {
368
+ return found;
369
+ }
370
+ }
371
+ }
372
+ return texts;
373
+ }
374
+ function collectTextValues(elements, texts) {
375
+ for (const el of elements) {
376
+ if (el.type.includes('TextView') && el.value) {
377
+ texts.push(el.value);
378
+ }
379
+ if (el.children) {
380
+ collectTextValues(el.children, texts);
381
+ }
382
+ }
383
+ }
384
+ function parseAndroidHierarchy(xml) {
385
+ const stack = [[]];
386
+ // Matches all <node ...>, </node>, and <node .../> tags in document order
387
+ const tagRegex = /<(\/?)node(?:\s+([^>]*?))?\s*(\/?)>/gu;
388
+ let match;
389
+ while ((match = tagRegex.exec(xml)) !== null) {
390
+ const isClosing = match[1] === '/';
391
+ const attrs = match[2];
392
+ const isSelfClosing = match[3] === '/';
393
+ if (isClosing) {
394
+ if (stack.length > 1) {
395
+ stack.pop();
396
+ }
397
+ }
398
+ else if (isSelfClosing && attrs) {
399
+ const element = parseNodeAttributes(attrs);
400
+ if (element) {
401
+ stack[stack.length - 1].push(element);
402
+ }
403
+ }
404
+ else if (attrs) {
405
+ const element = parseNodeAttributes(attrs);
406
+ if (element) {
407
+ element.children = [];
408
+ stack[stack.length - 1].push(element);
409
+ stack.push(element.children);
410
+ }
411
+ }
412
+ }
413
+ return stack[0];
414
+ }
415
+ function parseNodeAttributes(attrs) {
416
+ const get = (name) => {
417
+ const attrMatch = attrs.match(new RegExp(`${name}="([^"]*)"`, 'u'));
418
+ return attrMatch?.[1] || undefined;
419
+ };
420
+ const boundsStr = get('bounds');
421
+ if (!boundsStr) {
422
+ return null;
423
+ }
424
+ // bounds format: [x1,y1][x2,y2]
425
+ const boundsMatch = boundsStr.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/u);
426
+ if (!boundsMatch) {
427
+ return null;
428
+ }
429
+ const x1 = parseInt(boundsMatch[1], 10);
430
+ const y1 = parseInt(boundsMatch[2], 10);
431
+ const x2 = parseInt(boundsMatch[3], 10);
432
+ const y2 = parseInt(boundsMatch[4], 10);
433
+ return {
434
+ type: get('class') ?? 'Unknown',
435
+ label: get('content-desc') || undefined,
436
+ value: get('text') || undefined,
437
+ identifier: get('resource-id') || undefined,
438
+ frame: { x: x1, y: y1, width: x2 - x1, height: y2 - y1 },
439
+ enabled: get('enabled') !== 'false',
440
+ };
441
+ }
442
+ //# sourceMappingURL=adb-backend.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb-backend.cjs","sourceRoot":"","sources":["../../src/backends/adb-backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\n\nimport type {\n DeviceBackend,\n DeviceButton,\n DeviceInfo,\n SnapshotResult,\n ScreenshotResult,\n LogsResult,\n TapResult,\n AppStateResult,\n ElementQuery,\n UIElement,\n WindowSize,\n} from './types.js';\nimport { ACCEPT_LABELS, DENY_LABELS } from '../utils/alert-labels.js';\nimport {\n findElement,\n describeElement,\n computeSwipeEnd,\n} from '../utils/element.js';\nimport { execStrict, isCommandAvailable } from '../utils/exec.js';\n\nexport class AdbBackend implements DeviceBackend {\n readonly platform = 'android' as const;\n\n readonly #serial: string;\n\n #recordingProcess: ChildProcess | null = null;\n\n #recordingPath: string | null = null;\n\n readonly #recordingRemotePath = '/sdcard/device-mcp-recording.mp4';\n\n constructor(serial: string) {\n this.#serial = serial;\n }\n\n async #adb(args: string[]): Promise<string> {\n return execStrict('adb', ['-s', this.#serial, ...args]);\n }\n\n async ensureConnected(): Promise<void> {\n if (!(await isCommandAvailable('adb'))) {\n throw new Error(\n 'adb is not installed or not on $PATH.\\n' +\n 'Install Android SDK platform-tools.',\n );\n }\n const state = await this.#adb(['get-state']);\n if (state.trim() !== 'device') {\n throw new Error(\n `Device ${this.#serial} is not ready (state: ${state.trim()})`,\n );\n }\n }\n\n async getDeviceInfo(): Promise<DeviceInfo> {\n const [model, version] = await Promise.all([\n this.#adb(['shell', 'getprop', 'ro.product.model']),\n this.#adb(['shell', 'getprop', 'ro.build.version.release']),\n ]);\n return {\n platform: 'android',\n deviceId: this.#serial,\n name: model.trim(),\n osVersion: version.trim(),\n state: 'device',\n };\n }\n\n async snapshot(): Promise<SnapshotResult> {\n const raw = await this.#dumpUiHierarchy();\n const hierarchy = parseAndroidHierarchy(raw);\n return {\n platform: 'android',\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 x = Math.round(element.frame.x + element.frame.width / 2);\n const y = Math.round(element.frame.y + element.frame.height / 2);\n await this.tapCoordinates(x, y);\n\n return {\n success: true,\n x,\n y,\n targetDescription: describeElement(element),\n };\n }\n\n async tapCoordinates(x: number, y: number): Promise<void> {\n await this.#adb(['shell', 'input', 'tap', String(x), String(y)]);\n }\n\n async typeText(text: string): Promise<void> {\n // Android keyevent 29+shift = Ctrl+A (select all), 67 = DEL\n await this.#adb(['shell', 'input', 'keyevent', 'KEYCODE_MOVE_HOME']);\n await this.#adb([\n 'shell',\n 'input',\n 'keyevent',\n '--longpress',\n 'KEYCODE_SHIFT_LEFT',\n 'KEYCODE_MOVE_END',\n ]);\n await this.#adb(['shell', 'input', 'keyevent', '67']);\n // Android input text requires escaping spaces and special chars\n const escaped = text.replace(/ /gu, '%s').replace(/[&|;<>]/gu, '\\\\$&');\n await this.#adb(['shell', 'input', 'text', escaped]);\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 d = distance ?? 500;\n const sx = startX ?? 540;\n const sy = startY ?? 960;\n const [endX, endY] = computeSwipeEnd(sx, sy, direction, d);\n const durationMs = 300;\n\n await this.#adb([\n 'shell',\n 'input',\n 'swipe',\n String(sx),\n String(sy),\n String(endX),\n String(endY),\n String(durationMs),\n ]);\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 snapshot = await this.snapshot();\n const element = findElement(snapshot.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 raw = await this.#adb(['shell', 'dumpsys', 'activity', 'processes']);\n\n const pidMatch = raw.match(\n new RegExp(`PID #(\\\\d+):.*${bundleId.replace(/\\./gu, '\\\\.')}`, 'u'),\n );\n\n if (pidMatch) {\n return {\n bundleId,\n state: 'Running',\n pid: parseInt(pidMatch[1], 10),\n };\n }\n\n const pmResult = await this.#adb([\n 'shell',\n 'pm',\n 'list',\n 'packages',\n bundleId,\n ]);\n if (pmResult.includes(bundleId)) {\n return { bundleId, state: 'Installed (not running)' };\n }\n\n return { bundleId, state: 'Not Installed' };\n }\n\n async #dumpUiHierarchy(): Promise<string> {\n const remotePath = '/sdcard/window_dump.xml';\n await this.#adb(['shell', 'uiautomator', 'dump', remotePath]);\n const xml = await this.#adb(['shell', 'cat', remotePath]);\n await this.#adb(['shell', 'rm', '-f', remotePath]);\n return xml;\n }\n\n async screenshot(outputPath?: string): Promise<ScreenshotResult> {\n const localPath =\n outputPath ?? `/tmp/device-mcp-screenshot-${Date.now()}.png`;\n await this.#adb(['shell', 'screencap', '-p', '/sdcard/screenshot.png']);\n await execStrict('adb', [\n '-s',\n this.#serial,\n 'pull',\n '/sdcard/screenshot.png',\n localPath,\n ]);\n await this.#adb(['shell', 'rm', '-f', '/sdcard/screenshot.png']);\n const data = await execStrict('base64', [localPath]);\n return { data: data.trim(), format: 'png', path: localPath };\n }\n\n async openApp(bundleId: string): Promise<void> {\n await this.#adb([\n 'shell',\n 'monkey',\n '-p',\n bundleId,\n '-c',\n 'android.intent.category.LAUNCHER',\n '1',\n ]);\n }\n\n async closeApp(bundleId: string): Promise<void> {\n await this.#adb(['shell', 'am', 'force-stop', bundleId]);\n }\n\n async pressButton(button: DeviceButton): Promise<void> {\n // Android keyevent codes\n const keyMap: Record<DeviceButton, string> = {\n home: '3',\n back: '4',\n enter: '66',\n lock: '26',\n };\n await this.#adb(['shell', 'input', 'keyevent', keyMap[button]]);\n }\n\n async dismissKeyboard(): Promise<void> {\n await this.#adb(['shell', 'input', 'keyevent', '111']);\n }\n\n async dismissAlert(accept: boolean): Promise<void> {\n const snap = await this.snapshot();\n const candidates = accept ? ACCEPT_LABELS : DENY_LABELS;\n\n for (const label of candidates) {\n const element = findElement(snap.hierarchy, { text: label });\n if (element) {\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 this.tapCoordinates(cx, cy);\n return;\n }\n }\n\n throw new Error(`No alert button found. Tried: ${candidates.join(', ')}`);\n }\n\n async getLogs(durationSeconds = 30, filter?: string): Promise<LogsResult> {\n const args = ['shell', 'logcat', '-d', '-t', String(durationSeconds)];\n if (filter) {\n args.push('-e', filter);\n }\n const raw = await this.#adb(args);\n const entries = raw\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const match = line.match(/^(\\d{2}-\\d{2}\\s+\\S+)\\s+(\\w)\\/.*?:\\s*(.*)/u);\n if (match) {\n return {\n timestamp: match[1],\n level: match[2],\n message: match[3],\n };\n }\n return { timestamp: '', level: 'info', message: line };\n });\n return { entries, source: 'logcat' };\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 cx = Math.round(element.frame.x + element.frame.width / 2);\n const cy = Math.round(element.frame.y + element.frame.height / 2);\n await this.#adb([\n 'shell',\n 'input',\n 'swipe',\n String(cx),\n String(cy),\n String(cx),\n String(cy),\n String(durationMs),\n ]);\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 snap = await this.snapshot();\n const texts = collectAndroidAlertTexts(snap.hierarchy);\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 async getWindowSize(): Promise<WindowSize> {\n const raw = await this.#adb(['shell', 'wm', 'size']);\n const match = raw.match(/(\\d+)x(\\d+)/u);\n if (match) {\n return {\n width: parseInt(match[1], 10),\n height: parseInt(match[2], 10),\n };\n }\n throw new Error(`Unable to parse window size from: ${raw.trim()}`);\n }\n\n async getContexts(): Promise<string[]> {\n return ['NATIVE_APP'];\n }\n\n async setContext(context: string): Promise<void> {\n if (context === 'NATIVE_APP') {\n return;\n }\n throw new Error(\n 'Context switching requires Appium backend. ADB only supports NATIVE_APP.',\n );\n }\n\n async getClipboard(): Promise<string> {\n throw new Error(\n 'Clipboard access via ADB is not supported on modern Android. ' +\n 'Use the Appium backend for clipboard operations.',\n );\n }\n\n async setClipboard(_text: string): Promise<void> {\n throw new Error(\n 'Clipboard access via ADB is not supported on modern Android. ' +\n 'Use the Appium backend for clipboard operations.',\n );\n }\n\n async startScreenRecording(outputPath?: string): Promise<void> {\n if (this.#recordingProcess) {\n throw new Error('Screen recording is already in progress');\n }\n this.#recordingPath =\n outputPath ?? `/tmp/device-mcp-recording-${Date.now()}.mp4`;\n this.#recordingProcess = spawn('adb', [\n '-s',\n this.#serial,\n 'shell',\n 'screenrecord',\n this.#recordingRemotePath,\n ]);\n this.#recordingProcess.on('error', () => {\n this.#recordingProcess = null;\n this.#recordingPath = null;\n });\n }\n\n async stopScreenRecording(): Promise<string> {\n if (!this.#recordingProcess || !this.#recordingPath) {\n throw new Error('No screen recording in progress');\n }\n const localPath = this.#recordingPath;\n this.#recordingProcess.kill('SIGINT');\n await new Promise((resolve) => setTimeout(resolve, 2000));\n this.#recordingProcess = null;\n this.#recordingPath = null;\n\n await execStrict('adb', [\n '-s',\n this.#serial,\n 'pull',\n this.#recordingRemotePath,\n localPath,\n ]);\n await this.#adb(['shell', 'rm', '-f', this.#recordingRemotePath]);\n return localPath;\n }\n}\n\nfunction collectAndroidAlertTexts(elements: UIElement[]): string[] {\n const texts: string[] = [];\n for (const el of elements) {\n const isDialog =\n el.type.includes('Dialog') || el.type.includes('AlertDialog');\n if (isDialog) {\n collectTextValues(el.children ?? [], texts);\n return texts;\n }\n if (el.children) {\n const found = collectAndroidAlertTexts(el.children);\n if (found.length > 0) {\n return found;\n }\n }\n }\n return texts;\n}\n\nfunction collectTextValues(elements: UIElement[], texts: string[]): void {\n for (const el of elements) {\n if (el.type.includes('TextView') && el.value) {\n texts.push(el.value);\n }\n if (el.children) {\n collectTextValues(el.children, texts);\n }\n }\n}\n\nexport function parseAndroidHierarchy(xml: string): UIElement[] {\n const stack: UIElement[][] = [[]];\n\n // Matches all <node ...>, </node>, and <node .../> tags in document order\n const tagRegex = /<(\\/?)node(?:\\s+([^>]*?))?\\s*(\\/?)>/gu;\n let match: RegExpExecArray | null;\n\n while ((match = tagRegex.exec(xml)) !== null) {\n const isClosing = match[1] === '/';\n const attrs = match[2];\n const isSelfClosing = match[3] === '/';\n\n if (isClosing) {\n if (stack.length > 1) {\n stack.pop();\n }\n } else if (isSelfClosing && attrs) {\n const element = parseNodeAttributes(attrs);\n if (element) {\n stack[stack.length - 1].push(element);\n }\n } else if (attrs) {\n const element = parseNodeAttributes(attrs);\n if (element) {\n element.children = [];\n stack[stack.length - 1].push(element);\n stack.push(element.children);\n }\n }\n }\n\n return stack[0];\n}\n\nexport function parseNodeAttributes(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"]}
@@ -0,0 +1,35 @@
1
+ import type { DeviceBackend, DeviceButton, DeviceInfo, SnapshotResult, ScreenshotResult, LogsResult, TapResult, AppStateResult, ElementQuery, UIElement, WindowSize } from "./types.cjs";
2
+ export declare class AdbBackend implements DeviceBackend {
3
+ #private;
4
+ readonly platform: "android";
5
+ constructor(serial: string);
6
+ ensureConnected(): Promise<void>;
7
+ getDeviceInfo(): Promise<DeviceInfo>;
8
+ snapshot(): Promise<SnapshotResult>;
9
+ tapElement(query: ElementQuery): Promise<TapResult>;
10
+ tapCoordinates(x: number, y: number): Promise<void>;
11
+ typeText(text: string): Promise<void>;
12
+ swipe(direction: 'up' | 'down' | 'left' | 'right', startX?: number, startY?: number, distance?: number): Promise<void>;
13
+ waitForElement(query: ElementQuery, timeoutMs?: number, intervalMs?: number): Promise<UIElement>;
14
+ getAppState(bundleId: string): Promise<AppStateResult>;
15
+ screenshot(outputPath?: string): Promise<ScreenshotResult>;
16
+ openApp(bundleId: string): Promise<void>;
17
+ closeApp(bundleId: string): Promise<void>;
18
+ pressButton(button: DeviceButton): Promise<void>;
19
+ dismissKeyboard(): Promise<void>;
20
+ dismissAlert(accept: boolean): Promise<void>;
21
+ getLogs(durationSeconds?: number, filter?: string): Promise<LogsResult>;
22
+ longPress(query: ElementQuery, durationMs?: number): Promise<TapResult>;
23
+ scrollToElement(query: ElementQuery, direction?: 'up' | 'down', maxAttempts?: number): Promise<UIElement>;
24
+ getAlertText(): Promise<string>;
25
+ getWindowSize(): Promise<WindowSize>;
26
+ getContexts(): Promise<string[]>;
27
+ setContext(context: string): Promise<void>;
28
+ getClipboard(): Promise<string>;
29
+ setClipboard(_text: string): Promise<void>;
30
+ startScreenRecording(outputPath?: string): Promise<void>;
31
+ stopScreenRecording(): Promise<string>;
32
+ }
33
+ export declare function parseAndroidHierarchy(xml: string): UIElement[];
34
+ export declare function parseNodeAttributes(attrs: string): UIElement | null;
35
+ //# sourceMappingURL=adb-backend.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb-backend.d.cts","sourceRoot":"","sources":["../../src/backends/adb-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,UAAU,EACX,oBAAmB;AASpB,qBAAa,UAAW,YAAW,aAAa;;IAC9C,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;gBAU3B,MAAM,EAAE,MAAM;IAQpB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAehC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAcpC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAWnC,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC;IAsBnD,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrC,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;IAmBV,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;IAqCtD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgB1D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5C,OAAO,CAAC,eAAe,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAwBnE,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IA+BrE,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;IAY/B,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAYpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAO/B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1C,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAoB7C;AAgCD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAgC9D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA8BnE"}
@@ -0,0 +1,35 @@
1
+ import type { DeviceBackend, DeviceButton, DeviceInfo, SnapshotResult, ScreenshotResult, LogsResult, TapResult, AppStateResult, ElementQuery, UIElement, WindowSize } from "./types.mjs";
2
+ export declare class AdbBackend implements DeviceBackend {
3
+ #private;
4
+ readonly platform: "android";
5
+ constructor(serial: string);
6
+ ensureConnected(): Promise<void>;
7
+ getDeviceInfo(): Promise<DeviceInfo>;
8
+ snapshot(): Promise<SnapshotResult>;
9
+ tapElement(query: ElementQuery): Promise<TapResult>;
10
+ tapCoordinates(x: number, y: number): Promise<void>;
11
+ typeText(text: string): Promise<void>;
12
+ swipe(direction: 'up' | 'down' | 'left' | 'right', startX?: number, startY?: number, distance?: number): Promise<void>;
13
+ waitForElement(query: ElementQuery, timeoutMs?: number, intervalMs?: number): Promise<UIElement>;
14
+ getAppState(bundleId: string): Promise<AppStateResult>;
15
+ screenshot(outputPath?: string): Promise<ScreenshotResult>;
16
+ openApp(bundleId: string): Promise<void>;
17
+ closeApp(bundleId: string): Promise<void>;
18
+ pressButton(button: DeviceButton): Promise<void>;
19
+ dismissKeyboard(): Promise<void>;
20
+ dismissAlert(accept: boolean): Promise<void>;
21
+ getLogs(durationSeconds?: number, filter?: string): Promise<LogsResult>;
22
+ longPress(query: ElementQuery, durationMs?: number): Promise<TapResult>;
23
+ scrollToElement(query: ElementQuery, direction?: 'up' | 'down', maxAttempts?: number): Promise<UIElement>;
24
+ getAlertText(): Promise<string>;
25
+ getWindowSize(): Promise<WindowSize>;
26
+ getContexts(): Promise<string[]>;
27
+ setContext(context: string): Promise<void>;
28
+ getClipboard(): Promise<string>;
29
+ setClipboard(_text: string): Promise<void>;
30
+ startScreenRecording(outputPath?: string): Promise<void>;
31
+ stopScreenRecording(): Promise<string>;
32
+ }
33
+ export declare function parseAndroidHierarchy(xml: string): UIElement[];
34
+ export declare function parseNodeAttributes(attrs: string): UIElement | null;
35
+ //# sourceMappingURL=adb-backend.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adb-backend.d.mts","sourceRoot":"","sources":["../../src/backends/adb-backend.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,UAAU,EACX,oBAAmB;AASpB,qBAAa,UAAW,YAAW,aAAa;;IAC9C,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;gBAU3B,MAAM,EAAE,MAAM;IAQpB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAehC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAcpC,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAWnC,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC;IAsBnD,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrC,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;IAmBV,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;IAqCtD,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgB1D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhD,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5C,OAAO,CAAC,eAAe,SAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAwBnE,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,SAAO,GAAG,OAAO,CAAC,SAAS,CAAC;IA+BrE,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;IAY/B,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAYpC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIhC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAO/B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1C,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxD,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;CAoB7C;AAgCD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAgC9D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA8BnE"}