android-dev-mcp 1.0.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/dist/adb/accessibility.d.ts +10 -0
  4. package/dist/adb/accessibility.d.ts.map +1 -0
  5. package/dist/adb/accessibility.js +52 -0
  6. package/dist/adb/accessibility.js.map +1 -0
  7. package/dist/adb/index.d.ts +4 -0
  8. package/dist/adb/index.d.ts.map +1 -0
  9. package/dist/adb/index.js +4 -0
  10. package/dist/adb/index.js.map +1 -0
  11. package/dist/adb/liveTest.d.ts +39 -0
  12. package/dist/adb/liveTest.d.ts.map +1 -0
  13. package/dist/adb/liveTest.js +148 -0
  14. package/dist/adb/liveTest.js.map +1 -0
  15. package/dist/adb/logcatAnalysis.d.ts +17 -0
  16. package/dist/adb/logcatAnalysis.d.ts.map +1 -0
  17. package/dist/adb/logcatAnalysis.js +85 -0
  18. package/dist/adb/logcatAnalysis.js.map +1 -0
  19. package/dist/adb/ocr.d.ts +6 -0
  20. package/dist/adb/ocr.d.ts.map +1 -0
  21. package/dist/adb/ocr.js +16 -0
  22. package/dist/adb/ocr.js.map +1 -0
  23. package/dist/adb/operations.d.ts +48 -0
  24. package/dist/adb/operations.d.ts.map +1 -0
  25. package/dist/adb/operations.js +119 -0
  26. package/dist/adb/operations.js.map +1 -0
  27. package/dist/adb/runner.d.ts +57 -0
  28. package/dist/adb/runner.d.ts.map +1 -0
  29. package/dist/adb/runner.js +135 -0
  30. package/dist/adb/runner.js.map +1 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +7 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/mcp/index.d.ts +2 -0
  36. package/dist/mcp/index.d.ts.map +1 -0
  37. package/dist/mcp/index.js +2 -0
  38. package/dist/mcp/index.js.map +1 -0
  39. package/dist/mcp/server.d.ts +4 -0
  40. package/dist/mcp/server.d.ts.map +1 -0
  41. package/dist/mcp/server.js +567 -0
  42. package/dist/mcp/server.js.map +1 -0
  43. package/dist/security/allowlist.d.ts +4 -0
  44. package/dist/security/allowlist.d.ts.map +1 -0
  45. package/dist/security/allowlist.js +59 -0
  46. package/dist/security/allowlist.js.map +1 -0
  47. package/dist/security/index.d.ts +3 -0
  48. package/dist/security/index.d.ts.map +1 -0
  49. package/dist/security/index.js +3 -0
  50. package/dist/security/index.js.map +1 -0
  51. package/dist/security/timeout.d.ts +3 -0
  52. package/dist/security/timeout.d.ts.map +1 -0
  53. package/dist/security/timeout.js +25 -0
  54. package/dist/security/timeout.js.map +1 -0
  55. package/dist/server/index.d.ts +2 -0
  56. package/dist/server/index.d.ts.map +1 -0
  57. package/dist/server/index.js +2 -0
  58. package/dist/server/index.js.map +1 -0
  59. package/dist/server-http.d.ts +3 -0
  60. package/dist/server-http.d.ts.map +1 -0
  61. package/dist/server-http.js +51 -0
  62. package/dist/server-http.js.map +1 -0
  63. package/dist/tools/definitions.d.ts +3 -0
  64. package/dist/tools/definitions.d.ts.map +1 -0
  65. package/dist/tools/definitions.js +110 -0
  66. package/dist/tools/definitions.js.map +1 -0
  67. package/dist/tools/handlers.d.ts +139 -0
  68. package/dist/tools/handlers.d.ts.map +1 -0
  69. package/dist/tools/handlers.js +155 -0
  70. package/dist/tools/handlers.js.map +1 -0
  71. package/dist/tools/index.d.ts +4 -0
  72. package/dist/tools/index.d.ts.map +1 -0
  73. package/dist/tools/index.js +4 -0
  74. package/dist/tools/index.js.map +1 -0
  75. package/dist/tools/schemas.d.ts +462 -0
  76. package/dist/tools/schemas.d.ts.map +1 -0
  77. package/dist/tools/schemas.js +164 -0
  78. package/dist/tools/schemas.js.map +1 -0
  79. package/dist/types.d.ts +16 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 android-dev-mcp Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # android-dev-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/android-dev-mcp.svg)](https://www.npmjs.com/package/android-dev-mcp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ MCP server that exposes **Android Debug Bridge (ADB)** as tools. Runs locally. Use with Cursor, Claude Desktop, or any MCP client.
7
+
8
+ **Requirements:** Node.js ≥18, [ADB](https://developer.android.com/tools/adb) on `PATH`.
9
+
10
+ ---
11
+
12
+ ## Run
13
+
14
+ ### Option 1 — curl (new folder, download, run)
15
+
16
+ Create a new folder, open a terminal in it, then:
17
+
18
+ ```bash
19
+ curl -sSL -o start.sh https://raw.githubusercontent.com/ferhatozcelik/adb-mcp/main/start.sh
20
+ chmod +x start.sh
21
+ ./start.sh
22
+ ```
23
+
24
+ The server starts with detailed logs in the terminal. Connect your MCP client to **http://localhost:3000/mcp**.
25
+
26
+ ---
27
+
28
+ ### Option 2 — git clone
29
+
30
+ ```bash
31
+ git clone https://github.com/ferhatozcelik/adb-mcp.git
32
+ cd adb-mcp
33
+ ./start.sh
34
+ ```
35
+
36
+ (stdio: `./start.sh --stdio`)
37
+
38
+ ---
39
+
40
+ ## Connect your MCP client
41
+
42
+ **Cursor** — `.cursor/mcp.json` or MCP settings:
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "android-dev-mcp": {
48
+ "url": "http://localhost:3000/mcp"
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ **Claude Desktop** — `claude_desktop_config.json`:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "android-dev-mcp": {
60
+ "url": "http://localhost:3000/mcp"
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ Port: `PORT=4000 ./start.sh`.
67
+
68
+ **Extra commands:**
69
+ - `./start.sh help` — show usage and options
70
+ - `./start.sh check` — check Node, npm/npx, ADB, and connected devices
71
+
72
+ ---
73
+
74
+ ## stdio mode (optional)
75
+
76
+ From repo: `./start.sh --stdio`. Or with npx: `npx android-dev-mcp`.
77
+
78
+ MCP config: `"command": "npx", "args": ["android-dev-mcp"]`.
79
+
80
+ ---
81
+
82
+ ## Features
83
+
84
+ - List devices, run allowlisted ADB commands, launch app, tap, swipe, input text, screencap, current activity. Security: allowlist + timeout.
85
+
86
+ ---
87
+
88
+ ## Links
89
+
90
+ [npm](https://www.npmjs.com/package/android-dev-mcp) · [LICENSE](LICENSE) · [CONTRIBUTING](CONTRIBUTING.md) · [CHANGELOG](CHANGELOG.md)
@@ -0,0 +1,10 @@
1
+ /** Parse uiautomator dump XML: find node by text/content-desc, return bounds center. */
2
+ export declare function findNodeCenterByText(xml: string, searchText: string): {
3
+ x: number;
4
+ y: number;
5
+ } | null;
6
+ /** Get progress value from UI dump: progress="N" or text like "100" / "100%". Returns max found or null. */
7
+ export declare function getProgressFromXml(xml: string): number | null;
8
+ /** Check if UI dump contains a node with given text (case-insensitive). */
9
+ export declare function isTextVisibleInXml(xml: string, searchText: string): boolean;
10
+ //# sourceMappingURL=accessibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibility.d.ts","sourceRoot":"","sources":["../../src/adb/accessibility.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqBrG;AAED,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB7D;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3E"}
@@ -0,0 +1,52 @@
1
+ /** Parse uiautomator dump XML: find node by text/content-desc, return bounds center. */
2
+ export function findNodeCenterByText(xml, searchText) {
3
+ const normalized = searchText.trim().toLowerCase();
4
+ if (!normalized)
5
+ return null;
6
+ const nodeRe = /<node[^>]+>/g;
7
+ let m;
8
+ while ((m = nodeRe.exec(xml)) !== null) {
9
+ const node = m[0];
10
+ const text = (/text="([^"]*)"/.exec(node)?.[1] ?? /content-desc="([^"]*)"/.exec(node)?.[1] ?? '').toLowerCase();
11
+ if (!text.includes(normalized))
12
+ continue;
13
+ const bounds = /bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/.exec(node);
14
+ if (!bounds)
15
+ continue;
16
+ const left = Number(bounds[1]);
17
+ const top = Number(bounds[2]);
18
+ const right = Number(bounds[3]);
19
+ const bottom = Number(bounds[4]);
20
+ return {
21
+ x: Math.round((left + right) / 2),
22
+ y: Math.round((top + bottom) / 2),
23
+ };
24
+ }
25
+ return null;
26
+ }
27
+ /** Get progress value from UI dump: progress="N" or text like "100" / "100%". Returns max found or null. */
28
+ export function getProgressFromXml(xml) {
29
+ let maxProgress = null;
30
+ const progressAttr = /progress="(\d+)"/g;
31
+ let m;
32
+ while ((m = progressAttr.exec(xml)) !== null) {
33
+ const n = parseInt(m[1], 10);
34
+ if (maxProgress == null || n > maxProgress)
35
+ maxProgress = n;
36
+ }
37
+ const textProgress = /(?:text|content-desc)="([^"]*(\d+)(?:%)?[^"]*)"/g;
38
+ while ((m = textProgress.exec(xml)) !== null) {
39
+ const numMatch = m[2];
40
+ if (numMatch) {
41
+ const n = parseInt(numMatch, 10);
42
+ if (n >= 0 && n <= 100 && (maxProgress == null || n > maxProgress))
43
+ maxProgress = n;
44
+ }
45
+ }
46
+ return maxProgress;
47
+ }
48
+ /** Check if UI dump contains a node with given text (case-insensitive). */
49
+ export function isTextVisibleInXml(xml, searchText) {
50
+ return findNodeCenterByText(xml, searchText) !== null;
51
+ }
52
+ //# sourceMappingURL=accessibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibility.js","sourceRoot":"","sources":["../../src/adb/accessibility.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { listDevices, runAdb, shell, shellBuffer, adbConnect, adbDisconnect, adbKillServer, adbStartServer, adbPush, adbPull, adbInstall, adbUninstall, adbLogcat, adbBackup, adbRestore, adbReboot, adbGetState, adbGetSerialNo, } from './runner.js';
2
+ export { listDevices as adbListDevices, execShell, launchApp, tap, swipe, inputText, screencap, screencapAnalyze, currentActivity, keyevent, screenrecord, homeButton, logcatErrors, logcatCrashes, logcatAnalyze, uiDump, findAndTap, } from './operations.js';
3
+ export { parseScenarioMarkdown, runScenario, type StepKind, type RunScenarioResult, type RunStepResult } from './liveTest.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,MAAM,EACN,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,OAAO,EACP,OAAO,EACP,UAAU,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,IAAI,cAAc,EAC7B,SAAS,EACT,SAAS,EACT,GAAG,EACH,KAAK,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,MAAM,EACN,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,KAAK,QAAQ,EAAE,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { listDevices, runAdb, shell, shellBuffer, adbConnect, adbDisconnect, adbKillServer, adbStartServer, adbPush, adbPull, adbInstall, adbUninstall, adbLogcat, adbBackup, adbRestore, adbReboot, adbGetState, adbGetSerialNo, } from './runner.js';
2
+ export { listDevices as adbListDevices, execShell, launchApp, tap, swipe, inputText, screencap, screencapAnalyze, currentActivity, keyevent, screenrecord, homeButton, logcatErrors, logcatCrashes, logcatAnalyze, uiDump, findAndTap, } from './operations.js';
3
+ export { parseScenarioMarkdown, runScenario } from './liveTest.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adb/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,MAAM,EACN,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,OAAO,EACP,OAAO,EACP,UAAU,EACV,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,IAAI,cAAc,EAC7B,SAAS,EACT,SAAS,EACT,GAAG,EACH,KAAK,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,MAAM,EACN,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAA6D,MAAM,eAAe,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { AdbOptions } from '../types.js';
2
+ export type StepKind = {
3
+ type: 'wait_seconds';
4
+ seconds: number;
5
+ } | {
6
+ type: 'tap';
7
+ text: string;
8
+ } | {
9
+ type: 'wait_progress';
10
+ value: number;
11
+ timeoutMs?: number;
12
+ } | {
13
+ type: 'wait_visible';
14
+ text: string;
15
+ timeoutMs?: number;
16
+ };
17
+ /** Parse a single step line (after stripping list marker). Returns null if not recognized. */
18
+ export declare function parseStepLine(line: string): StepKind | null;
19
+ /** Extract step lines from markdown: lines that start with - or * (skip # headers). */
20
+ export declare function parseScenarioMarkdown(md: string): StepKind[];
21
+ export interface RunStepResult {
22
+ stepIndex: number;
23
+ step: StepKind;
24
+ ok: boolean;
25
+ message: string;
26
+ durationMs?: number;
27
+ }
28
+ export interface RunScenarioResult {
29
+ ok: boolean;
30
+ steps: RunStepResult[];
31
+ totalDurationMs: number;
32
+ log: string;
33
+ }
34
+ export declare function runScenario(markdown: string, options?: AdbOptions & {
35
+ pollMs?: number;
36
+ waitProgressTimeoutMs?: number;
37
+ waitVisibleTimeoutMs?: number;
38
+ }): Promise<RunScenarioResult>;
39
+ //# sourceMappingURL=liveTest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveTest.d.ts","sourceRoot":"","sources":["../../src/adb/liveTest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAsC3D;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,EAAE,CAY5D;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,UAAU,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC1B,GACL,OAAO,CAAC,iBAAiB,CAAC,CAoF5B"}
@@ -0,0 +1,148 @@
1
+ import { uiDump, findAndTap } from './operations.js';
2
+ import { getProgressFromXml, isTextVisibleInXml } from './accessibility.js';
3
+ const DEFAULT_POLL_MS = 800;
4
+ const DEFAULT_WAIT_PROGRESS_TIMEOUT_MS = 60_000;
5
+ const DEFAULT_WAIT_VISIBLE_TIMEOUT_MS = 30_000;
6
+ /** Parse a single step line (after stripping list marker). Returns null if not recognized. */
7
+ export function parseStepLine(line) {
8
+ const trimmed = line.trim();
9
+ if (!trimmed)
10
+ return null;
11
+ const waitSecRe = /(?:(\d+)\s*(?:saniye|sn|sec|seconds?)\s*bekle|wait\s+(\d+)\s*seconds?)/i;
12
+ const secMatch = trimmed.match(waitSecRe);
13
+ if (secMatch) {
14
+ const n = parseInt(secMatch[1] ?? secMatch[2], 10);
15
+ if (n >= 0 && n <= 300)
16
+ return { type: 'wait_seconds', seconds: n };
17
+ }
18
+ const progressRe = /(?:progress\s*(?:bar)?\s*(\d+)\s*olana\s+kadar\s+bekle|wait\s+until\s+progress\s+(\d+))/i;
19
+ const progressMatch = trimmed.match(progressRe);
20
+ if (progressMatch) {
21
+ const n = parseInt(progressMatch[1] ?? progressMatch[2], 10);
22
+ if (n >= 0 && n <= 100)
23
+ return { type: 'wait_progress', value: n };
24
+ }
25
+ const visibleRe = /(?:["']([^"']+)["']\s*görünene\s+kadar\s+bekle|(.+?)\s+görünene\s+kadar\s+bekle|wait\s+until\s+visible\s+["']?([^"'\s]+)["']?)/i;
26
+ const visibleMatch = trimmed.match(visibleRe);
27
+ if (visibleMatch) {
28
+ const text = (visibleMatch[1] ?? visibleMatch[2] ?? visibleMatch[3] ?? '').trim();
29
+ if (text)
30
+ return { type: 'wait_visible', text };
31
+ }
32
+ const tapRe = /(?:["']([^"']+)["']\s*tıkla|tıkla\s+["']?([^"'\s]+)|tap\s+["']?([^"'\s]+)["']?|([A-Za-z0-9\s]+)\s+buton(?:una)?\s+tıkla|(.+?)\s+tıkla\s*$)/i;
33
+ const tapMatch = trimmed.match(tapRe);
34
+ if (tapMatch) {
35
+ const text = (tapMatch[1] ?? tapMatch[2] ?? tapMatch[3] ?? tapMatch[4] ?? tapMatch[5] ?? '').trim();
36
+ if (text)
37
+ return { type: 'tap', text };
38
+ }
39
+ if (trimmed.toLowerCase().startsWith('tap ')) {
40
+ const rest = trimmed.slice(4).replace(/^["']|["']$/g, '').trim();
41
+ if (rest)
42
+ return { type: 'tap', text: rest };
43
+ }
44
+ return null;
45
+ }
46
+ /** Extract step lines from markdown: lines that start with - or * (skip # headers). */
47
+ export function parseScenarioMarkdown(md) {
48
+ const steps = [];
49
+ const lines = md.split(/\r?\n/);
50
+ for (const line of lines) {
51
+ const trimmed = line.trim();
52
+ if (!trimmed || trimmed.startsWith('#'))
53
+ continue;
54
+ const content = trimmed.replace(/^\s*[-*]\s*/, '').trim();
55
+ if (!content)
56
+ continue;
57
+ const step = parseStepLine(content);
58
+ if (step)
59
+ steps.push(step);
60
+ }
61
+ return steps;
62
+ }
63
+ function sleep(ms) {
64
+ return new Promise((resolve) => setTimeout(resolve, ms));
65
+ }
66
+ export async function runScenario(markdown, options = {}) {
67
+ const steps = parseScenarioMarkdown(markdown);
68
+ const { pollMs = DEFAULT_POLL_MS, waitProgressTimeoutMs = DEFAULT_WAIT_PROGRESS_TIMEOUT_MS, waitVisibleTimeoutMs = DEFAULT_WAIT_VISIBLE_TIMEOUT_MS, ...adbOpts } = options;
69
+ const results = [];
70
+ const logLines = [];
71
+ const startTime = Date.now();
72
+ for (let i = 0; i < steps.length; i++) {
73
+ const step = steps[i];
74
+ const stepStart = Date.now();
75
+ let ok = false;
76
+ let message = '';
77
+ try {
78
+ if (step.type === 'wait_seconds') {
79
+ await sleep(step.seconds * 1000);
80
+ ok = true;
81
+ message = `Waited ${step.seconds}s`;
82
+ }
83
+ else if (step.type === 'tap') {
84
+ const result = await findAndTap(step.text, adbOpts);
85
+ ok = result.tapped;
86
+ message = result.tapped
87
+ ? `Tapped "${step.text}" at (${result.x}, ${result.y})`
88
+ : (result.error ?? `Tap failed: ${step.text}`);
89
+ }
90
+ else if (step.type === 'wait_progress') {
91
+ const deadline = Date.now() + (step.timeoutMs ?? waitProgressTimeoutMs);
92
+ while (Date.now() < deadline) {
93
+ const xml = await uiDump(adbOpts);
94
+ const progress = getProgressFromXml(xml);
95
+ if (progress != null && progress >= step.value) {
96
+ ok = true;
97
+ message = `Progress reached ${progress} (>= ${step.value})`;
98
+ break;
99
+ }
100
+ await sleep(pollMs);
101
+ }
102
+ if (!ok)
103
+ message = `Timeout: progress did not reach ${step.value}`;
104
+ }
105
+ else if (step.type === 'wait_visible') {
106
+ const deadline = Date.now() + (step.timeoutMs ?? waitVisibleTimeoutMs);
107
+ while (Date.now() < deadline) {
108
+ const xml = await uiDump(adbOpts);
109
+ if (isTextVisibleInXml(xml, step.text)) {
110
+ ok = true;
111
+ message = `"${step.text}" is visible`;
112
+ break;
113
+ }
114
+ await sleep(pollMs);
115
+ }
116
+ if (!ok)
117
+ message = `Timeout: "${step.text}" did not appear`;
118
+ }
119
+ const durationMs = Date.now() - stepStart;
120
+ results.push({ stepIndex: i, step, ok, message, durationMs });
121
+ logLines.push(`[${i + 1}] ${step.type}: ${message} (${durationMs}ms)`);
122
+ if (!ok)
123
+ break;
124
+ }
125
+ catch (e) {
126
+ const err = e instanceof Error ? e.message : String(e);
127
+ message = `Error: ${err}`;
128
+ results.push({
129
+ stepIndex: i,
130
+ step,
131
+ ok: false,
132
+ message,
133
+ durationMs: Date.now() - stepStart,
134
+ });
135
+ logLines.push(`[${i + 1}] ${step.type}: ${message}`);
136
+ break;
137
+ }
138
+ }
139
+ const totalDurationMs = Date.now() - startTime;
140
+ const ok = results.length > 0 && results.every((r) => r.ok);
141
+ return {
142
+ ok,
143
+ steps: results,
144
+ totalDurationMs,
145
+ log: logLines.join('\n'),
146
+ };
147
+ }
148
+ //# sourceMappingURL=liveTest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveTest.js","sourceRoot":"","sources":["../../src/adb/liveTest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export type LogLevel = 'E' | 'F' | 'EF';
2
+ export declare function isCrashLine(line: string): boolean;
3
+ export declare function extractCrashSnippet(logcat: string, maxLines?: number): string;
4
+ export declare function countErrorLevels(logcat: string): {
5
+ error: number;
6
+ fatal: number;
7
+ };
8
+ export declare function getErrorLines(logcat: string, maxLines?: number): string[];
9
+ export declare function analyzeLogcat(logcat: string): {
10
+ hasCrash: boolean;
11
+ fatalCount: number;
12
+ errorCount: number;
13
+ crashSnippet: string;
14
+ summary: string;
15
+ errorLines: string[];
16
+ };
17
+ //# sourceMappingURL=logcatAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logcatAnalysis.d.ts","sourceRoot":"","sources":["../../src/adb/logcatAnalysis.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;AAgBxC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,CAuBzE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAUjF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,EAAE,CAMtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAwBA"}
@@ -0,0 +1,85 @@
1
+ const CRASH_PATTERNS = [
2
+ /FATAL EXCEPTION/i,
3
+ /AndroidRuntime:\s*FATAL/i,
4
+ /Process:\s*\d+,\s*PID:\s*\d+/,
5
+ /java\.lang\.RuntimeException/i,
6
+ /java\.lang\.NullPointerException/i,
7
+ /Caused by:/i,
8
+ /^\s*at\s+[\w.$]+\s*\(/m,
9
+ /^\*\*\*\s*\*\*\*\s*\*\*\*/m,
10
+ /Fatal signal \d+/i,
11
+ /backtrace:/i,
12
+ /Build fingerprint:/i,
13
+ ];
14
+ export function isCrashLine(line) {
15
+ return CRASH_PATTERNS.some((p) => p.test(line));
16
+ }
17
+ export function extractCrashSnippet(logcat, maxLines = 80) {
18
+ const lines = logcat.split('\n');
19
+ let start = -1;
20
+ let end = lines.length;
21
+ for (let i = 0; i < lines.length; i++) {
22
+ if (/FATAL EXCEPTION|AndroidRuntime:\s*FATAL|Fatal signal/i.test(lines[i])) {
23
+ start = i;
24
+ break;
25
+ }
26
+ }
27
+ if (start < 0) {
28
+ for (let i = 0; i < lines.length; i++) {
29
+ if (isCrashLine(lines[i])) {
30
+ start = Math.max(0, i - 2);
31
+ break;
32
+ }
33
+ }
34
+ }
35
+ if (start < 0)
36
+ return '';
37
+ end = Math.min(start + maxLines, lines.length);
38
+ return lines.slice(start, end).join('\n').trim();
39
+ }
40
+ export function countErrorLevels(logcat) {
41
+ const lines = logcat.split('\n');
42
+ let error = 0;
43
+ let fatal = 0;
44
+ for (const line of lines) {
45
+ const t = line.trim();
46
+ if (/^F\s|^F\/|FATAL\s|F\/\w+/.test(t))
47
+ fatal++;
48
+ else if (/^E\s|^E\/|ERROR\s|E\/\w+/.test(t))
49
+ error++;
50
+ }
51
+ return { error, fatal };
52
+ }
53
+ export function getErrorLines(logcat, maxLines = 200) {
54
+ const lines = logcat.split('\n').filter((l) => {
55
+ const t = l.trim();
56
+ return /^[EF]\s|^[EF]\//.test(t) || /FATAL|AndroidRuntime.*FATAL/i.test(t);
57
+ });
58
+ return lines.slice(-maxLines);
59
+ }
60
+ export function analyzeLogcat(logcat) {
61
+ const { error, fatal } = countErrorLevels(logcat);
62
+ const crashSnippet = extractCrashSnippet(logcat);
63
+ const hasCrash = crashSnippet.length > 0;
64
+ const errorLines = getErrorLines(logcat, 200);
65
+ let summary = '';
66
+ if (hasCrash) {
67
+ const firstLine = crashSnippet.split('\n')[0] ?? '';
68
+ summary = `Crash detected: ${firstLine.slice(0, 120)}`;
69
+ }
70
+ else if (fatal > 0 || error > 0) {
71
+ summary = `Errors: ${error} E, ${fatal} F. No FATAL EXCEPTION block found.`;
72
+ }
73
+ else {
74
+ summary = 'No errors or crashes in recent log.';
75
+ }
76
+ return {
77
+ hasCrash,
78
+ fatalCount: fatal,
79
+ errorCount: error,
80
+ crashSnippet,
81
+ summary,
82
+ errorLines,
83
+ };
84
+ }
85
+ //# sourceMappingURL=logcatAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logcatAnalysis.js","sourceRoot":"","sources":["../../src/adb/logcatAnalysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface OcrResult {
2
+ text: string;
3
+ confidence?: number;
4
+ }
5
+ export declare function extractTextFromImage(buffer: Buffer): Promise<OcrResult>;
6
+ //# sourceMappingURL=ocr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../src/adb/ocr.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAa7E"}
@@ -0,0 +1,16 @@
1
+ export async function extractTextFromImage(buffer) {
2
+ try {
3
+ const Tesseract = await import('tesseract.js');
4
+ const { data } = await Tesseract.default.recognize(buffer, 'eng', {
5
+ logger: () => { },
6
+ });
7
+ return {
8
+ text: (data?.text ?? '').trim(),
9
+ confidence: data?.confidence,
10
+ };
11
+ }
12
+ catch {
13
+ return { text: '' };
14
+ }
15
+ }
16
+ //# sourceMappingURL=ocr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocr.js","sourceRoot":"","sources":["../../src/adb/ocr.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,MAAc;IACvD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QAC/C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE;YAChE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;SACjB,CAAC,CAAC;QACH,OAAO;YACL,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAC/B,UAAU,EAAE,IAAI,EAAE,UAAU;SAC7B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { listDevices } from './runner.js';
2
+ import { type LogLevel } from './logcatAnalysis.js';
3
+ import type { AdbOptions } from '../types.js';
4
+ export { listDevices };
5
+ export declare function execShell(command: string, options?: AdbOptions): Promise<string>;
6
+ export declare function launchApp(packageName: string, activity?: string, options?: AdbOptions): Promise<string>;
7
+ export declare function tap(x: number, y: number, options?: AdbOptions): Promise<string>;
8
+ export declare function swipe(x1: number, y1: number, x2: number, y2: number, durationMs?: number, options?: AdbOptions): Promise<string>;
9
+ export declare function inputText(text: string, options?: AdbOptions): Promise<string>;
10
+ export declare function screencap(options?: AdbOptions): Promise<string>;
11
+ /** Screenshot + optional OCR. */
12
+ export declare function screencapAnalyze(options?: AdbOptions & {
13
+ extractText?: boolean;
14
+ }): Promise<{
15
+ imageBase64: string;
16
+ extractedText: string;
17
+ confidence?: number;
18
+ }>;
19
+ export declare function currentActivity(options?: AdbOptions): Promise<string>;
20
+ export declare function keyevent(keycode: number, options?: AdbOptions): Promise<string>;
21
+ export declare function screenrecord(path: string, durationSec?: number, options?: AdbOptions): Promise<string>;
22
+ export declare function homeButton(options?: AdbOptions): Promise<string>;
23
+ export declare function logcatErrors(level?: LogLevel, maxLines?: number, options?: AdbOptions): Promise<{
24
+ output: string;
25
+ lines: string[];
26
+ }>;
27
+ export declare function logcatCrashes(options?: AdbOptions): Promise<{
28
+ output: string;
29
+ hasCrash: boolean;
30
+ crashSnippet: string;
31
+ summary: string;
32
+ }>;
33
+ export declare function logcatAnalyze(options?: AdbOptions): Promise<{
34
+ errorCount: number;
35
+ fatalCount: number;
36
+ hasCrash: boolean;
37
+ crashSnippet: string;
38
+ summary: string;
39
+ errorLines: string[];
40
+ }>;
41
+ export declare function uiDump(options?: AdbOptions): Promise<string>;
42
+ export declare function findAndTap(text: string, options?: AdbOptions): Promise<{
43
+ tapped: boolean;
44
+ x?: number;
45
+ y?: number;
46
+ error?: string;
47
+ }>;
48
+ //# sourceMappingURL=operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/adb/operations.ts"],"names":[],"mappings":"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"}