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.
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/adb/accessibility.d.ts +10 -0
- package/dist/adb/accessibility.d.ts.map +1 -0
- package/dist/adb/accessibility.js +52 -0
- package/dist/adb/accessibility.js.map +1 -0
- package/dist/adb/index.d.ts +4 -0
- package/dist/adb/index.d.ts.map +1 -0
- package/dist/adb/index.js +4 -0
- package/dist/adb/index.js.map +1 -0
- package/dist/adb/liveTest.d.ts +39 -0
- package/dist/adb/liveTest.d.ts.map +1 -0
- package/dist/adb/liveTest.js +148 -0
- package/dist/adb/liveTest.js.map +1 -0
- package/dist/adb/logcatAnalysis.d.ts +17 -0
- package/dist/adb/logcatAnalysis.d.ts.map +1 -0
- package/dist/adb/logcatAnalysis.js +85 -0
- package/dist/adb/logcatAnalysis.js.map +1 -0
- package/dist/adb/ocr.d.ts +6 -0
- package/dist/adb/ocr.d.ts.map +1 -0
- package/dist/adb/ocr.js +16 -0
- package/dist/adb/ocr.js.map +1 -0
- package/dist/adb/operations.d.ts +48 -0
- package/dist/adb/operations.d.ts.map +1 -0
- package/dist/adb/operations.js +119 -0
- package/dist/adb/operations.js.map +1 -0
- package/dist/adb/runner.d.ts +57 -0
- package/dist/adb/runner.d.ts.map +1 -0
- package/dist/adb/runner.js +135 -0
- package/dist/adb/runner.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +567 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/security/allowlist.d.ts +4 -0
- package/dist/security/allowlist.d.ts.map +1 -0
- package/dist/security/allowlist.js +59 -0
- package/dist/security/allowlist.js.map +1 -0
- package/dist/security/index.d.ts +3 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +3 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/timeout.d.ts +3 -0
- package/dist/security/timeout.d.ts.map +1 -0
- package/dist/security/timeout.js +25 -0
- package/dist/security/timeout.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server-http.d.ts +3 -0
- package/dist/server-http.d.ts.map +1 -0
- package/dist/server-http.js +51 -0
- package/dist/server-http.js.map +1 -0
- package/dist/tools/definitions.d.ts +3 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +110 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers.d.ts +139 -0
- package/dist/tools/handlers.d.ts.map +1 -0
- package/dist/tools/handlers.js +155 -0
- package/dist/tools/handlers.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/schemas.d.ts +462 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +164 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- 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
|
+
[](https://www.npmjs.com/package/android-dev-mcp)
|
|
4
|
+
[](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 @@
|
|
|
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"}
|
package/dist/adb/ocr.js
ADDED
|
@@ -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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"}
|